Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6b4a104

Browse files
committedJan 9, 2023
Group multi-block updates when updating meshes to avoid duplicate updates
1 parent d1c751d commit 6b4a104

File tree

7 files changed

+62
-30
lines changed

7 files changed

+62
-30
lines changed
 

‎.swiftlint.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ line_length: 160
1919
type_body_length: 300
2020
function_parameter_count: 8
2121
file_length: 500
22-
function_body_length: 50
22+
function_body_length: 50
2323
cyclomatic_complexity:
2424
error: 40 # TODO: reset once more occurrences are fixed
2525

‎Sources/Core/Renderer/World/WorldRenderer.swift

+11-1
Original file line numberDiff line numberDiff line change
@@ -285,13 +285,23 @@ public final class WorldRenderer: Renderer {
285285
worldMesh.updateSection(at: position)
286286
}
287287

288-
case let event as World.Event.SetBlock:
288+
case let event as World.Event.SingleBlockUpdate:
289289
let affectedSections = worldMesh.sectionsAffectedBySectionUpdate(at: event.position.chunkSection)
290290

291291
for position in affectedSections {
292292
worldMesh.updateSection(at: position)
293293
}
294294

295+
case let event as World.Event.MultiBlockUpdate:
296+
var affectedSections: Set<ChunkSectionPosition> = []
297+
for update in event.updates {
298+
affectedSections.formUnion(worldMesh.sectionsAffectedBySectionUpdate(at: update.position.chunkSection))
299+
}
300+
301+
for position in affectedSections {
302+
worldMesh.updateSection(at: position)
303+
}
304+
295305
case let event as World.Event.UpdateChunk:
296306
var affectedSections: Set<ChunkSectionPosition> = []
297307

‎Sources/Core/Sources/Network/Protocol/PacketRegistry.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public struct PacketRegistry {
5151
BossBarPacket.self,
5252
ServerDifficultyPacket.self,
5353
ChatMessageClientboundPacket.self,
54-
MultiBlockChangePacket.self,
54+
MultiBlockUpdatePacket.self,
5555
TabCompleteClientboundPacket.self,
5656
DeclareCommandsPacket.self,
5757
WindowConfirmationClientboundPacket.self,

‎Sources/Core/Sources/Network/Protocol/Packets/Play/Clientbound/MultiBlockChangePacket.swift ‎Sources/Core/Sources/Network/Protocol/Packets/Play/Clientbound/MultiBlockUpdatePacket.swift

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import Foundation
22

3-
public struct MultiBlockChangePacket: ClientboundPacket {
3+
public struct MultiBlockUpdatePacket: ClientboundPacket {
44
public static let id: Int = 0x0f
55

66
/// A block change in a multi-block change.
7-
public struct BlockChangeRecord {
7+
public struct BlockUpdateRecord {
88
/// X coordinate of the block change relative to the chunk.
99
public var x: UInt8
1010
/// Y coordinate of the block change relative to the chunk.
@@ -19,7 +19,7 @@ public struct MultiBlockChangePacket: ClientboundPacket {
1919
/// The position of the chunk the multi-block change occured in.
2020
public var chunkPosition: ChunkPosition
2121
/// The block changes.
22-
public var records: [BlockChangeRecord]
22+
public var records: [BlockUpdateRecord]
2323

2424
public init(from packetReader: inout PacketReader) throws {
2525
let chunkX = try packetReader.readInt()
@@ -35,24 +35,23 @@ public struct MultiBlockChangePacket: ClientboundPacket {
3535
let z = value & 0x0f
3636
let y = try packetReader.readUnsignedByte()
3737
let blockId = try packetReader.readVarInt()
38-
let record = BlockChangeRecord(x: x, y: y, z: z, blockId: blockId)
38+
let record = BlockUpdateRecord(x: x, y: y, z: z, blockId: blockId)
3939
records.append(record)
4040
}
4141
}
4242

4343
public func handle(for client: Client) throws {
44-
print("Multi block change")
4544
let updates = records.map { record in
46-
return (
45+
return World.Event.SingleBlockUpdate(
4746
position: BlockPosition(
4847
x: Int(record.x) + chunkPosition.chunkX * Chunk.width,
4948
y: Int(record.y),
5049
z: Int(record.z) + chunkPosition.chunkZ * Chunk.depth
5150
),
52-
state: record.blockId
51+
newState: record.blockId
5352
)
5453
}
5554

56-
client.game.world.processMultiBlockChange(at: chunkPosition, updates)
55+
client.game.world.processMultiBlockUpdate(updates, inChunkAt: chunkPosition)
5756
}
5857
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Foundation
2+
3+
extension World.Event {
4+
/// An event triggered when multiple blocks are updated at once.
5+
public struct MultiBlockUpdate: Event {
6+
public let updates: [SingleBlockUpdate]
7+
8+
public init(updates: [SingleBlockUpdate]) {
9+
self.updates = updates
10+
}
11+
}
12+
}

‎Sources/Core/Sources/Plugin/Event/World/SetBlock.swift ‎Sources/Core/Sources/Plugin/Event/World/SingleBlockUpdate.swift

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import Foundation
22

33
extension World.Event {
4-
public struct SetBlock: Event {
4+
/// An event triggered when a single block is updated within a chunk. Use in conjunction with
5+
/// MultiBlockUpdate to receive all block updates.
6+
public struct SingleBlockUpdate: Event {
57
public let position: BlockPosition
68
public let newState: Int
7-
9+
810
public init(position: BlockPosition, newState: Int) {
911
self.position = position
1012
self.newState = newState

‎Sources/Core/Sources/World/World.swift

+26-17
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public class World {
143143
chunk.setBlockId(at: position.relativeToChunk, to: state)
144144
lightingEngine.updateLighting(at: position, in: self)
145145

146-
eventBus.dispatch(Event.SetBlock(
146+
eventBus.dispatch(Event.SingleBlockUpdate(
147147
position: position,
148148
newState: state
149149
))
@@ -157,27 +157,36 @@ public class World {
157157
/// Using this method is preferred over just using setBlockId within a for loop because it
158158
/// processes lighting updates in batch which is much more efficient.
159159
/// - Parameters:
160-
/// - chunk: The position of the chunk that all of the updates are in.
161160
/// - updates: The positions and new states of affected blocks.
162-
public func processMultiBlockChange(
163-
at chunkPosition: ChunkPosition,
164-
_ updates: [(position: BlockPosition, state: Int)]
161+
/// - chunkPosition: If all updates occur within a single chunk provide this parameter for more
162+
/// efficient batching.
163+
public func processMultiBlockUpdate(
164+
_ updates: [Event.SingleBlockUpdate],
165+
inChunkAt chunkPosition: ChunkPosition? = nil
165166
) {
166-
if let chunk = chunk(at: chunkPosition) {
167-
for (position, state) in updates {
168-
chunk.setBlockId(at: position.relativeToChunk, to: state)
169-
}
170-
lightingEngine.updateLighting(at: updates.map(\.position), in: self)
171-
172-
for (position, state) in updates {
173-
eventBus.dispatch(Event.SetBlock(
174-
position: position,
175-
newState: state
176-
))
167+
if let chunkPosition = chunkPosition {
168+
if let chunk = chunk(at: chunkPosition) {
169+
for update in updates {
170+
chunk.setBlockId(at: update.position.relativeToChunk, to: update.newState)
171+
}
172+
lightingEngine.updateLighting(at: updates.map(\.position), in: self)
173+
} else {
174+
log.warning("Cannot handle multi-block change in non-existent chunk, chunkPosition=\(chunkPosition)")
175+
return
177176
}
178177
} else {
179-
log.warning("Cannot handle multi-block change in non-existent chunk, chunkPosition=\(chunkPosition)")
178+
for update in updates {
179+
if let chunk = chunk(at: update.position.chunk) {
180+
chunk.setBlockId(at: update.position.relativeToChunk, to: update.newState)
181+
} else {
182+
log.warning("Cannot handle multi-block change in non-existent chunk, chunkPosition=\(update.position.chunk)")
183+
return
184+
}
185+
}
186+
lightingEngine.updateLighting(at: updates.map(\.position), in: self)
180187
}
188+
189+
eventBus.dispatch(Event.MultiBlockUpdate(updates: updates))
181190
}
182191

183192
/// Get the block id of the block at the specified position.

0 commit comments

Comments
 (0)
Please sign in to comment.