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 Foundation
|
||||||
|
import Spatial
|
||||||
|
|
||||||
public struct ChunkGeneration {
|
public struct ChunkGeneration {
|
||||||
private let queue: OperationQueue
|
private let queue: OperationQueue
|
||||||
private let localReadyChunks = ConcurrentDictionary<SIMD3<Int>, Chunk>()
|
private let localReadyChunks = ConcurrentDictionary<SIMD3<Int>, Chunk>()
|
||||||
|
private var chunkGenerationOperations = ConcurrentDictionary<SIMD3<Int>, WeakChunkGenerationOperationHolder>()
|
||||||
private var generatingChunkSet = Set<SIMD3<Int>>()
|
private var generatingChunkSet = Set<SIMD3<Int>>()
|
||||||
|
|
||||||
weak var world: World?
|
weak var world: World?
|
||||||
@ -28,12 +30,51 @@ public struct ChunkGeneration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func queueGenerateJob(chunkID: SIMD3<Int>) {
|
func queueGenerateJob(chunkID: SIMD3<Int>) {
|
||||||
self.queue.addOperation {
|
let operation = ChunkGenerationOperation(chunkID: chunkID)
|
||||||
guard let world = self.world else {
|
operation.world = self.world
|
||||||
return
|
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)
|
||||||
}
|
}
|
||||||
let chunk = world.generateSingleChunkUncommitted(chunkID: chunkID)
|
|
||||||
self.localReadyChunks[chunkID] = chunk
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -76,6 +76,18 @@ public class ConcurrentDictionary<V: Hashable, T>: Collection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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 {
|
fileprivate func locked<X>(_ perform: () -> X) -> X {
|
||||||
self.lock.lock()
|
self.lock.lock()
|
||||||
defer {
|
defer {
|
||||||
|
@ -83,7 +83,7 @@ class Game: GameDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.world.generateAdjacentChunksIfNeeded(position: self.player.position)
|
self.world.generateAdjacentChunksIfNeeded(position: self.player.position)
|
||||||
self.world.update()
|
self.world.update(priorityPosition: self.player.position)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static let material = Material(
|
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()
|
self._chunkGeneration.acceptReadyChunks()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user