Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d31b689
Add world difficulty type, APIs, and packets
Joniii11 Mar 3, 2026
a98fe7a
Add player food/hunger system
Joniii11 Mar 3, 2026
e5e4c65
fmt + clippy
Joniii11 Mar 3, 2026
4017f17
fixes
Joniii11 Mar 3, 2026
f85f7f1
more fixes
Joniii11 Mar 3, 2026
8b9c2f9
fix bug where it was draining to fast hunger cause one missing thingy
Joniii11 Mar 3, 2026
4349883
grrr
Joniii11 Mar 3, 2026
df8cc51
missing todo
Joniii11 Mar 4, 2026
3cf140f
make it look better
Joniii11 Mar 5, 2026
3a6e629
hm
Joniii11 Mar 5, 2026
eaad070
clippy
Joniii11 Mar 5, 2026
aa0a930
use WriteTo instead of manually do impl WriteTo for CUpdateAttributes
Joniii11 Mar 5, 2026
aa5fa51
feat: add Difficulty command
Joniii11 Mar 5, 2026
6e4162a
ye
Joniii11 Mar 13, 2026
356ade3
revert
Joniii11 Mar 13, 2026
cb8afd7
Revert "revert"
Joniii11 Mar 13, 2026
26fbbab
redo some stuff since i flipping force pushed grrr
Joniii11 Mar 13, 2026
b2395f9
fix clippy & fmt
Joniii11 Mar 13, 2026
0ab5eac
redo difficultiy cmd hehge
Joniii11 Mar 13, 2026
a2f4d90
remove pesky getters and setters (not all of them hehehe)
Joniii11 Mar 13, 2026
380b56a
Merge branch 'Steel-Foundation:master' into hunger
Joniii11 Mar 14, 2026
2ebd3fc
Merge branch 'Steel-Foundation:master' into hunger
Joniii11 Mar 15, 2026
c7fc989
Merge branch 'Steel-Foundation:master' into hunger
Joniii11 Mar 15, 2026
8fc6475
Merge commit 'refs/pull/108/head' of https://github.com/Steel-Foundat…
CuzImClicks Mar 16, 2026
d601df4
normal and candle cakes
CuzImClicks Mar 17, 2026
cef99ed
fix block updating and destroying
CuzImClicks Mar 17, 2026
f3c4b35
Merge branch 'fix_destroy_block' into cakes
CuzImClicks Mar 17, 2026
4e84c96
Merge branch 'Steel-Foundation:master' into hunger
Joniii11 Mar 18, 2026
2c3e9c3
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Mar 19, 2026
b9a40aa
dropping candle now work
CuzImClicks Mar 19, 2026
f85a881
Merge branch 'master' into hunger
4lve Mar 19, 2026
2a3305f
Small fixes
4lve Mar 19, 2026
e6831ee
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Mar 24, 2026
318052c
Merge branch 'dev' into cakes
CuzImClicks Mar 25, 2026
29a1aca
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Mar 30, 2026
c6a7d79
Merge steel-foundation/dev into hunger - resolve conflicts
Joniii11 Mar 31, 2026
ba42dd6
Merge origin/hunger - resolve spawn_pos conflict
Joniii11 Mar 31, 2026
c5f40e8
feat: impl entity attribute system
Joniii11 Apr 1, 2026
16acd94
fix ci
Joniii11 Apr 1, 2026
8986fa2
extract recipe property sets
CuzImClicks Apr 1, 2026
f9fb185
use static instead of const
CuzImClicks Apr 1, 2026
4cdb3e1
Merge branch 'recipe_property_sets' into campfires
CuzImClicks Apr 1, 2026
e28748e
add inventory access to use_item_on
CuzImClicks Apr 2, 2026
eb0419c
add lighting of candles, cakes and campfires
CuzImClicks Apr 2, 2026
8d43b90
Merge branch 'hunger' into cakes
CuzImClicks Apr 2, 2026
1ce3f09
Merge branch 'cakes' into campfires
CuzImClicks Apr 2, 2026
d7d413b
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Apr 2, 2026
3748478
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Apr 2, 2026
f6487eb
fix ci
CuzImClicks Apr 2, 2026
a8f1afc
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Apr 5, 2026
7a915a1
fix ci
CuzImClicks Apr 5, 2026
e0f638d
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Apr 7, 2026
ddf9e68
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Apr 7, 2026
17b6ecf
add inventory access to use_item_on and use_without_item
CuzImClicks Apr 7, 2026
da7dedf
fix small bugs
CuzImClicks Apr 7, 2026
e19dc79
Merge branch 'cakes' into campfires
CuzImClicks Apr 7, 2026
6a7d105
fix small bugs
CuzImClicks Apr 7, 2026
cc3437c
Merge branch 'dev' of https://github.com/Steel-Foundation/SteelMC int…
CuzImClicks Apr 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions steel-core/build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::fs;
use syn::Ident;

mod blocks;
mod candle_cakes;
mod common;
mod items;
mod strippables;
Expand Down Expand Up @@ -40,6 +41,8 @@ pub fn main() {
blocks::build(&classes.blocks),
)
.expect("Failed to write blocks.rs");
fs::write(format!("{out_dir}/candle_cakes.rs"), candle_cakes::build())
.expect("Failed to write candle_cakes.rs");
fs::write(format!("{out_dir}/items.rs"), items::build(&classes.items))
.expect("Failed to write items.rs");
fs::write(format!("{out_dir}/waxables.rs"), waxables::build())
Expand Down
19 changes: 19 additions & 0 deletions steel-core/build/candle_cakes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"blue_candle": "blue_candle_cake",
"green_candle": "green_candle_cake",
"red_candle": "red_candle_cake",
"pink_candle": "pink_candle_cake",
"yellow_candle": "yellow_candle_cake",
"magenta_candle": "magenta_candle_cake",
"brown_candle": "brown_candle_cake",
"light_gray_candle": "light_gray_candle_cake",
"candle": "candle_cake",
"white_candle": "white_candle_cake",
"gray_candle": "gray_candle_cake",
"cyan_candle": "cyan_candle_cake",
"lime_candle": "lime_candle_cake",
"orange_candle": "orange_candle_cake",
"black_candle": "black_candle_cake",
"light_blue_candle": "light_blue_candle_cake",
"purple_candle": "purple_candle_cake"
}
35 changes: 35 additions & 0 deletions steel-core/build/candle_cakes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use std::{collections::BTreeMap, fs};

use proc_macro2::Span;
use quote::quote;
use syn::Ident;

use crate::to_block_ident;

pub fn build() -> String {
println!("cargo:rerun-if-changed=build/candle_cakes.json");

let candle_cakes_json =
fs::read_to_string("build/candle_cakes.json").expect("Failed to read candle_cakes.json");
let candle_cakes_raw: BTreeMap<String, String> =
serde_json::from_str(&candle_cakes_json).expect("Failed to parse candle_cakes.json");

let by_candle: Vec<proc_macro2::TokenStream> = candle_cakes_raw
.iter()
.map(|(key, value)| (Ident::new(key.to_lowercase().as_str(), Span::call_site()), to_block_ident(value)))
.map(|(key, value)| quote! { i if i == &vanilla_items::ITEMS.#key => Some(&vanilla_blocks::#value), })
.collect();

let output = quote! {
use steel_registry::{blocks::BlockRef, items::ItemRef, vanilla_blocks, vanilla_items};

pub fn candle_to_candle_cake(item: ItemRef) -> Option<BlockRef> {
match item {
#(#by_candle)*
_ => None
}
}
};

output.to_string()
}
6 changes: 4 additions & 2 deletions steel-core/src/behavior/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use steel_registry::{REGISTRY, RegistryEntry, RegistryExt};
use steel_utils::types::{InteractionHand, UpdateFlags};
use steel_utils::{BlockPos, BlockStateId};

use crate::behavior::InventoryAccess;
use crate::behavior::context::{BlockHitResult, BlockPlaceContext, InteractionResult};
use crate::block_entity::SharedBlockEntity;
use crate::entity::Entity;
Expand Down Expand Up @@ -144,13 +145,13 @@ pub trait BlockBehavior: Send + Sync {
)]
fn use_item_on(
&self,
item_stack: &ItemStack,
state: BlockStateId,
world: &Arc<World>,
pos: BlockPos,
player: &Player,
hand: InteractionHand,
hit_result: &BlockHitResult,
inv: &mut InventoryAccess,
) -> InteractionResult {
InteractionResult::TryEmptyHandInteraction
}
Expand All @@ -171,6 +172,7 @@ pub trait BlockBehavior: Send + Sync {
pos: BlockPos,
player: &Player,
hit_result: &BlockHitResult,
inv: &mut InventoryAccess,
) -> InteractionResult {
InteractionResult::Pass
}
Expand Down Expand Up @@ -398,7 +400,7 @@ pub trait BlockBehavior: Send + Sync {
/// Vanilla parity: `LiquidBlockContainer.canPlaceLiquid()`.
///
/// Returns `true` if the given fluid type may be placed into this block at the
/// given state. Called by the fluid-spread logic; there is no player context
/// given state. Called by the fluid-spread logic; there is no player context
/// here (fluid spreading has no associated player).
///
/// Default (`SimpleWaterloggedBlock`): accepts water when the block has a
Expand Down
221 changes: 221 additions & 0 deletions steel-core/src/behavior/blocks/building/campfire.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
use std::sync::{Arc, Weak};

use steel_macros::block_behavior;
use steel_registry::{
REGISTRY, TaggedRegistryExt,
blocks::{BlockRef, block_state_ext::BlockStateExt, properties::BlockStateProperties},
fluid::{FluidState, FluidStateExt},
items::item::BlockHitResult,
sound_events, vanilla_block_entity_types, vanilla_block_tags, vanilla_blocks,
vanilla_damage_types, vanilla_fluids, vanilla_recipe_property_sets,
};
use steel_utils::{
BlockPos, BlockStateId, Direction,
types::{InteractionHand, UpdateFlags},
};

use crate::{
behavior::{BlockBehavior, BlockPlaceContext, InteractionResult, InventoryAccess},
block_entity::{BLOCK_ENTITIES, SharedBlockEntity, entities::CampfireBlockEntity},
entity::{Entity, damage::DamageSource},
player::Player,
world::World,
};

/// Behavior for Campfires
/// - [ ] projectile hit
/// - [ ] getTicker to run cooking ticks
#[block_behavior]
pub struct CampfireBlock {
block: BlockRef,
#[json_arg(value)]
fire_damage: i32,
}

impl CampfireBlock {
/// Creates a new Campfire Block Behavior
#[must_use]
pub const fn new(block: BlockRef, fire_damage: i32) -> Self {
Self { block, fire_damage }
}

/// Whether or not the Campfire can be lit
#[must_use]
pub fn can_light(state: BlockStateId) -> bool {
REGISTRY
.blocks
.is_in_tag(state.get_block(), &vanilla_block_tags::CAMPFIRES_TAG)
&& !state
.try_get_value(&BlockStateProperties::WATERLOGGED)
.unwrap_or(true)
&& !state
.try_get_value(&BlockStateProperties::LIT)
.unwrap_or(true)
}
}

impl BlockBehavior for CampfireBlock {
fn get_state_for_placement(
&self,
context: &BlockPlaceContext<'_>,
) -> Option<steel_utils::BlockStateId> {
let is_replacing_water = context.is_water_source();

Some(
self.block
.default_state()
.set_value(&BlockStateProperties::WATERLOGGED, is_replacing_water)
.set_value(
&BlockStateProperties::SIGNAL_FIRE,
context
.world
.get_block_state(context.relative_pos.below())
.get_block()
== &vanilla_blocks::HAY_BLOCK,
)
.set_value(&BlockStateProperties::LIT, !is_replacing_water)
.set_value(
&BlockStateProperties::HORIZONTAL_FACING,
context.horizontal_direction,
),
)
}

fn update_shape(
&self,
state: BlockStateId,
world: &Arc<World>,
pos: BlockPos,
direction: Direction,
_neighbor_pos: BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
if state.get_value(&BlockStateProperties::WATERLOGGED) {
world.schedule_fluid_tick_default(
pos,
&vanilla_fluids::WATER,
vanilla_fluids::WATER.tick_delay as i32,
);
}

if direction == Direction::Down {
return state.set_value(
&BlockStateProperties::SIGNAL_FIRE,
world.get_block_state(pos.below()).get_block() == &vanilla_blocks::HAY_BLOCK,
);
}
state
}

fn entity_inside(
&self,
state: BlockStateId,
_world: &Arc<World>,
_pos: BlockPos,
entity: &dyn Entity,
) {
if state.get_value(&BlockStateProperties::LIT)
&& let Some(living) = entity.as_living()
{
living.hurt(
&DamageSource::environment(&vanilla_damage_types::CAMPFIRE),
self.fire_damage as f32,
);
}
}

fn get_fluid_state(&self, state: BlockStateId) -> FluidState {
if state.get_value(&BlockStateProperties::WATERLOGGED) {
FluidState::source(&vanilla_fluids::WATER)
} else {
FluidState::EMPTY
}
}

fn place_liquid(
&self,
world: &Arc<World>,
pos: BlockPos,
state: BlockStateId,
fluid_state: FluidState,
) -> bool {
if state.get_value(&BlockStateProperties::WATERLOGGED) || !fluid_state.is_water() {
return false;
}

if !fluid_state.is_source() {
// this is a really weird fix for placing campfires not being destroyed when being placed under a water source
return true;
}

if state.get_value(&BlockStateProperties::LIT) {
world.play_block_sound(
sound_events::ENTITY_GENERIC_EXTINGUISH_FIRE,
pos,
1.0,
1.0,
None,
);
}
world.set_block(
pos,
state
.set_value(&BlockStateProperties::WATERLOGGED, true)
.set_value(&BlockStateProperties::LIT, false),
UpdateFlags::UPDATE_ALL,
);

world.schedule_fluid_tick_default(
pos,
fluid_state.fluid_id,
fluid_state.fluid_id.tick_delay as i32,
);

true
}

fn has_block_entity(&self) -> bool {
true
}

fn new_block_entity(
&self,
level: Weak<World>,
pos: BlockPos,
state: BlockStateId,
) -> Option<SharedBlockEntity> {
BLOCK_ENTITIES.create(&vanilla_block_entity_types::CAMPFIRE, level, pos, state)
}

fn use_item_on(
&self,
_state: BlockStateId,
world: &Arc<World>,
pos: BlockPos,
player: &Player,
_hand: InteractionHand,
_hit_result: &BlockHitResult,
inv: &mut InventoryAccess,
) -> InteractionResult {
let item_stack = inv.item();
let Some(block_entity) = world.get_block_entity(pos) else {
return InteractionResult::Fail;
};

if !vanilla_recipe_property_sets::CAMPFIRE_INPUT.contains(&item_stack.item()) {
return InteractionResult::TryEmptyHandInteraction;
}

let mut lock = block_entity.lock();

let Some(campfire_entity) = lock.as_any_mut().downcast_mut::<CampfireBlockEntity>() else {
return InteractionResult::Fail;
};

if campfire_entity.place_food(item_stack, player.has_infinite_materials()) {
return InteractionResult::Success;
}

InteractionResult::TryEmptyHandInteraction
}
}
2 changes: 2 additions & 0 deletions steel-core/src/behavior/blocks/building/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
mod campfire;
mod fence_block;
mod rotated_pillar_block;
mod weathering_block;

pub use campfire::CampfireBlock;
pub use fence_block::FenceBlock;
pub use rotated_pillar_block::RotatedPillarBlock;
pub use weathering_block::{WeatherState, WeatheringCopper, WeatheringCopperFullBlock};
2 changes: 2 additions & 0 deletions steel-core/src/behavior/blocks/container/barrel_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use steel_registry::vanilla_block_entity_types;
use steel_utils::{BlockPos, BlockStateId, translations};
use text_components::TextComponent;

use crate::behavior::InventoryAccess;
use crate::behavior::block::BlockBehavior;
use crate::behavior::context::{BlockHitResult, BlockPlaceContext, InteractionResult};
use crate::block_entity::{BLOCK_ENTITIES, SharedBlockEntity};
Expand Down Expand Up @@ -57,6 +58,7 @@ impl BlockBehavior for BarrelBlock {
pos: BlockPos,
player: &Player,
_hit_result: &BlockHitResult,
_inv: &mut InventoryAccess,
) -> InteractionResult {
// Get the block entity
let Some(block_entity) = world.get_block_entity(pos) else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use steel_macros::block_behavior;
use steel_registry::blocks::BlockRef;
use steel_utils::{BlockPos, BlockStateId};

use crate::behavior::InventoryAccess;
use crate::behavior::block::BlockBehavior;
use crate::behavior::context::{BlockHitResult, BlockPlaceContext, InteractionResult};
use crate::inventory::CraftingMenuProvider;
Expand Down Expand Up @@ -43,6 +44,7 @@ impl BlockBehavior for CraftingTableBlock {
pos: BlockPos,
player: &Player,
_hit_result: &BlockHitResult,
_inv: &mut InventoryAccess,
) -> InteractionResult {
player.open_menu(&CraftingMenuProvider::new(player.inventory.clone(), pos));
// TODO: Award stat INTERACT_WITH_CRAFTING_TABLE
Expand Down
Loading
Loading