Skip to main content

steel_core/chunk/chunk_map/
scheduled_ticks.rs

1use super::{
2    Arc, BLOCK_BEHAVIORS, BlockStateExt, BlockTick, BlockTickBatchGuard, ChunkMap, ChunkStatus,
3    FLUID_BEHAVIORS, FluidTick, FluidTickBatchGuard, MAX_SCHEDULED_TICKS_PER_TICK,
4    TickingChunkSnapshot, World,
5};
6
7impl ChunkMap {
8    /// Collects this tick's block batch from sparse live-container heads.
9    pub(super) fn collect_scheduled_block_ticks(
10        world: &World,
11        tickable_chunks: &TickingChunkSnapshot,
12        current_tick: i64,
13    ) -> Vec<BlockTick> {
14        let collected =
15            world.begin_scheduled_tick_phase(current_tick, MAX_SCHEDULED_TICKS_PER_TICK);
16        for index in collected.changed_containers {
17            let tickable = &tickable_chunks.block[index];
18            let Some(chunk) = tickable.holder.try_chunk(ChunkStatus::Full) else {
19                panic!("published ticking snapshot lost a Full chunk");
20            };
21            chunk.mark_dirty();
22        }
23
24        collected.ticks
25    }
26
27    /// Collects this tick's fluid batch after block callbacks have run.
28    pub(super) fn collect_scheduled_fluid_ticks(
29        world: &World,
30        tickable_chunks: &TickingChunkSnapshot,
31        current_tick: i64,
32    ) -> Vec<FluidTick> {
33        let collected =
34            world.collect_scheduled_fluid_tick_batch(current_tick, MAX_SCHEDULED_TICKS_PER_TICK);
35        for index in collected.changed_containers {
36            let tickable = &tickable_chunks.block[index];
37            let Some(chunk) = tickable.holder.try_chunk(ChunkStatus::Full) else {
38                panic!("published ticking snapshot lost a Full chunk");
39            };
40            chunk.mark_dirty();
41        }
42        collected.ticks
43    }
44
45    /// Executes ready scheduled block ticks in their collected order.
46    pub(super) fn execute_scheduled_block_ticks(
47        world: &Arc<World>,
48        ready_block_ticks: Vec<BlockTick>,
49    ) {
50        if !ready_block_ticks.is_empty() {
51            let batch = BlockTickBatchGuard::new(world, ready_block_ticks);
52            let block_behaviors = &*BLOCK_BEHAVIORS;
53            for (index, tick) in batch.ticks().iter().enumerate() {
54                batch.start(index);
55                let state = world.get_block_state(tick.pos);
56                if state.get_block() != tick.tick_type {
57                    continue;
58                }
59                block_behaviors
60                    .get_behavior(tick.tick_type)
61                    .tick(state, world, tick.pos);
62            }
63        }
64    }
65
66    /// Executes ready scheduled fluid ticks in their collected order.
67    pub(super) fn execute_scheduled_fluid_ticks(
68        world: &Arc<World>,
69        ready_fluid_ticks: Vec<FluidTick>,
70    ) {
71        if !ready_fluid_ticks.is_empty() {
72            let batch = FluidTickBatchGuard::new(world, ready_fluid_ticks);
73            let fluid_behaviors = &*FLUID_BEHAVIORS;
74            for (index, tick) in batch.ticks().iter().enumerate() {
75                batch.start(index);
76                let state = world.get_block_state(tick.pos);
77                let fluid_state = state.get_fluid_state();
78
79                // Only execute if the fluid at this location still matches the scheduled tick
80                if fluid_state.fluid_id != tick.tick_type {
81                    continue;
82                }
83
84                fluid_behaviors.get_behavior(tick.tick_type).tick(
85                    world,
86                    tick.pos,
87                    state,
88                    fluid_state,
89                );
90            }
91        }
92    }
93}