mirror of
https://github.com/GayPizzaSpecifications/voxelotl-engine.git
synced 2025-08-02 13:00:53 +00:00
Spatial Chunk Generation
This commit is contained in:
parent
76b61c49ae
commit
f2b3b07832
@ -1,8 +1,10 @@
|
||||
import Foundation
|
||||
import Spatial
|
||||
|
||||
public struct ChunkGeneration {
|
||||
private let queue: OperationQueue
|
||||
private let localReadyChunks = ConcurrentDictionary<SIMD3<Int>, Chunk>()
|
||||
private var chunkGenerationOperations = ConcurrentDictionary<SIMD3<Int>, WeakChunkGenerationOperationHolder>()
|
||||
private var generatingChunkSet = Set<SIMD3<Int>>()
|
||||
|
||||
weak var world: World?
|
||||
@ -28,15 +30,54 @@ public struct ChunkGeneration {
|
||||
}
|
||||
|
||||
func queueGenerateJob(chunkID: SIMD3<Int>) {
|
||||
self.queue.addOperation {
|
||||
guard let world = self.world else {
|
||||
return
|
||||
}
|
||||
let chunk = world.generateSingleChunkUncommitted(chunkID: chunkID)
|
||||
self.localReadyChunks[chunkID] = chunk
|
||||
}
|
||||
let operation = ChunkGenerationOperation(chunkID: chunkID)
|
||||
operation.world = self.world
|
||||
operation.localReadyChunks = self.localReadyChunks
|
||||
operation.chunkGenerationOperations = self.chunkGenerationOperations
|
||||
self.queue.addOperation(operation)
|
||||
let holder = WeakChunkGenerationOperationHolder()
|
||||
holder.operation = operation
|
||||
self.chunkGenerationOperations[chunkID] = holder
|
||||
}
|
||||
|
||||
public mutating func updatePriorityPosition(position: SIMD3<Float>) {
|
||||
let centerChunkID = World.makeID(position: position)
|
||||
let centerChunkPoint = Point3D(x: Double(centerChunkID.x), y: Double(centerChunkID.y), z: Double(centerChunkID.z))
|
||||
|
||||
self.chunkGenerationOperations.with { operations in
|
||||
var remove: [SIMD3<Int>] = []
|
||||
for (chunkID, operation) in operations {
|
||||
if operation.operation == nil {
|
||||
remove.append(chunkID)
|
||||
continue
|
||||
}
|
||||
let chunkPoint = Point3D(x: Double(chunkID.x), y: Double(chunkID.y), z: Double(chunkID.z))
|
||||
let distance = abs(chunkPoint.distance(to: centerChunkPoint))
|
||||
let priority: Operation.QueuePriority
|
||||
if distance < 3 {
|
||||
priority = .veryHigh
|
||||
} else if distance < 6 {
|
||||
priority = .normal
|
||||
} else if distance < 10 {
|
||||
priority = .low
|
||||
} else {
|
||||
priority = .veryLow
|
||||
}
|
||||
|
||||
if priority == .veryLow {
|
||||
operation.operation?.cancel()
|
||||
self.generatingChunkSet.remove(chunkID)
|
||||
} else {
|
||||
operation.operation?.queuePriority = priority
|
||||
}
|
||||
}
|
||||
|
||||
for item in remove {
|
||||
operations.removeValue(forKey: item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public mutating func generateAdjacentIfNeeded(position: SIMD3<Float>) {
|
||||
guard let world = self.world else {
|
||||
return
|
||||
@ -74,3 +115,41 @@ public struct ChunkGeneration {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WeakChunkGenerationOperationHolder {
|
||||
weak var operation: ChunkGenerationOperation?
|
||||
}
|
||||
|
||||
class ChunkGenerationOperation: Operation, @unchecked Sendable {
|
||||
let chunkID: SIMD3<Int>
|
||||
|
||||
weak var world: World?
|
||||
weak var localReadyChunks: ConcurrentDictionary<SIMD3<Int>, Chunk>?
|
||||
weak var chunkGenerationOperations: ConcurrentDictionary<SIMD3<Int>, WeakChunkGenerationOperationHolder>?
|
||||
|
||||
init(chunkID: SIMD3<Int>) {
|
||||
self.chunkID = chunkID
|
||||
}
|
||||
|
||||
override func main() {
|
||||
if isCancelled {
|
||||
return
|
||||
}
|
||||
|
||||
guard let world = self.world else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let localReadyChunks = self.localReadyChunks else {
|
||||
return
|
||||
}
|
||||
|
||||
let chunk = world.generateSingleChunkUncommitted(chunkID: self.chunkID)
|
||||
localReadyChunks[chunkID] = chunk
|
||||
|
||||
guard let chunkGenerationOperations = self.chunkGenerationOperations else {
|
||||
return
|
||||
}
|
||||
chunkGenerationOperations.remove(key: chunkID)
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +75,18 @@ public class ConcurrentDictionary<V: Hashable, T>: Collection {
|
||||
self.inner.removeAll(keepingCapacity: keep)
|
||||
}
|
||||
}
|
||||
|
||||
@discardableResult public func remove(key: V) -> T? {
|
||||
self.locked {
|
||||
self.inner.removeValue(forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
public func with(_ perform: (inout [V : T]) -> Void) {
|
||||
self.locked {
|
||||
perform(&self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func locked<X>(_ perform: () -> X) -> X {
|
||||
self.lock.lock()
|
||||
|
@ -83,7 +83,7 @@ class Game: GameDelegate {
|
||||
}
|
||||
|
||||
self.world.generateAdjacentChunksIfNeeded(position: self.player.position)
|
||||
self.world.update()
|
||||
self.world.update(priorityPosition: self.player.position)
|
||||
}
|
||||
|
||||
public static let material = Material(
|
||||
|
@ -107,7 +107,8 @@ public class World {
|
||||
}
|
||||
}
|
||||
|
||||
public func update() {
|
||||
public func update(priorityPosition: SIMD3<Float>) {
|
||||
self._chunkGeneration.updatePriorityPosition(position: priorityPosition)
|
||||
self._chunkGeneration.acceptReadyChunks()
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user