mc173/block_entity/
furnace.rs1use glam::IVec3;
4
5use crate::item::{self, ItemStack};
6use crate::world::{World, Event, BlockEntityEvent, BlockEntityStorage, BlockEntityProgress};
7use crate::{smelt, block};
8
9
10#[derive(Debug, Clone, Default)]
11pub struct FurnaceBlockEntity {
12 pub input_stack: ItemStack,
14 pub fuel_stack: ItemStack,
16 pub output_stack: ItemStack,
18 pub burn_max_ticks: u16,
20 pub burn_remaining_ticks: u16,
22 pub smelt_ticks: u16,
24 last_input_stack: ItemStack,
26 last_output_stack: ItemStack,
28 active_output_stack: Option<ItemStack>,
31}
32
33impl FurnaceBlockEntity {
34
35 fn find_new_output_stack(&self) -> Option<ItemStack> {
39
40 if self.input_stack.size == 0 {
41 return None;
42 }
43
44 let input_id = self.input_stack.id;
45 let input_damage = self.input_stack.damage;
46 let mut output_stack = smelt::find_smelting_output(input_id, input_damage)?;
47
48 if !self.output_stack.is_empty() {
49 if (self.output_stack.id, self.output_stack.damage) != (output_stack.id, output_stack.damage) {
50 return None;
51 } else if self.output_stack.size + output_stack.size > item::from_id(output_stack.id).max_stack_size {
52 return None;
53 } else {
54 output_stack.size += self.output_stack.size;
55 }
56 }
57
58 Some(output_stack)
59
60 }
61
62 pub fn tick(&mut self, world: &mut World, pos: IVec3) {
64
65 if self.input_stack != self.last_input_stack || self.output_stack != self.last_output_stack {
68 self.active_output_stack = self.find_new_output_stack();
69 self.last_input_stack = self.input_stack;
70 self.last_output_stack = self.output_stack;
71 }
72
73 let mut smelt_modified = false;
74 let mut fuel_modified = false;
75
76 let initial_burning = self.burn_remaining_ticks != 0;
77 if initial_burning {
78 self.burn_remaining_ticks -= 1;
79 fuel_modified = true;
80 }
81
82 if let Some(active_output_stack) = &self.active_output_stack {
83
84 if self.burn_remaining_ticks == 0 && !self.fuel_stack.is_empty() {
85
86 self.burn_max_ticks = smelt::get_burn_ticks(self.fuel_stack.id);
87 self.burn_remaining_ticks = self.burn_max_ticks;
88
89 if self.burn_max_ticks != 0 {
90
91 self.fuel_stack.size -= 1;
92 fuel_modified = true;
93
94 world.push_event(Event::BlockEntity {
95 pos,
96 inner: BlockEntityEvent::Storage {
97 storage: BlockEntityStorage::FurnaceFuel,
98 stack: self.fuel_stack,
99 },
100 });
101
102 world.push_event(Event::BlockEntity {
103 pos,
104 inner: BlockEntityEvent::Progress {
105 progress: BlockEntityProgress::FurnaceBurnMaxTime,
106 value: self.burn_max_ticks,
107 },
108 });
109
110 }
111
112 }
113
114 if self.burn_remaining_ticks == 0 {
115 if self.smelt_ticks != 0 {
116 self.smelt_ticks = 0;
117 smelt_modified = true;
118 }
119 } else {
120
121 self.smelt_ticks += 1;
122 if self.smelt_ticks == 200 {
123
124 self.smelt_ticks = 0;
125 self.input_stack.size -= 1;
130 self.output_stack = *active_output_stack;
131
132 world.push_event(Event::BlockEntity {
133 pos,
134 inner: BlockEntityEvent::Storage {
135 storage: BlockEntityStorage::FurnaceInput,
136 stack: self.input_stack,
137 },
138 });
139
140 world.push_event(Event::BlockEntity {
141 pos,
142 inner: BlockEntityEvent::Storage {
143 storage: BlockEntityStorage::FurnaceOutput,
144 stack: self.output_stack,
145 },
146 });
147
148 }
149
150 smelt_modified = true;
151
152 }
153
154 } else if self.smelt_ticks != 0 {
155 self.smelt_ticks = 0;
156 smelt_modified = true;
157 }
158
159 if smelt_modified {
160 world.push_event(Event::BlockEntity {
161 pos,
162 inner: BlockEntityEvent::Progress {
163 progress: BlockEntityProgress::FurnaceSmeltTime,
164 value: self.smelt_ticks,
165 },
166 });
167 }
168
169 if fuel_modified {
170 world.push_event(Event::BlockEntity {
171 pos,
172 inner: BlockEntityEvent::Progress {
173 progress: BlockEntityProgress::FurnaceBurnRemainingTime,
174 value: self.burn_remaining_ticks,
175 },
176 });
177 }
178
179 if initial_burning != (self.burn_remaining_ticks != 0) {
180 let (_id, metadata) = world.get_block(pos).expect("should not be ticking if not loaded");
181 if initial_burning {
182 world.set_block_notify(pos, block::FURNACE, metadata);
184 } else {
185 world.set_block_notify(pos, block::FURNACE_LIT, metadata);
187 }
188 }
189
190 }
191
192}