Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ protected void addTranslations() {
addTooltip("fluid_content_empty", "Empty");
addTooltip("fluid_content", "Contains: %smB of %s");

add(BMBlocks.ARCANE_ASHES, "Arcane Ashes");

add(BMBlocks.IMPERFECT_RITUAL_BLOCK, "Imperfect Ritual Stone");

add(BMBlocks.HELLFIRE_FORGE, "Hellfire Forge");
Expand Down
1 change: 1 addition & 0 deletions src/generated/resources/assets/bloodmagic/lang/en_us.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"block.bloodmagic.alchemy_table": "Alchemy Table",
"block.bloodmagic.arc": "Alchemical Reaction Chamber",
"block.bloodmagic.arcane_ashes": "Arcane Ashes",
"block.bloodmagic.blood_altar": "Blood Altar",
"block.bloodmagic.blood_tank": "Blood Tank",
"block.bloodmagic.bloodstone": "Polished Bloodstone",
Expand Down
195 changes: 195 additions & 0 deletions src/main/java/wayoftime/bloodmagic/common/block/ArcaneAshesBlock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
package wayoftime.bloodmagic.common.block;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.DustParticleOptions;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.ItemInteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.neoforged.neoforge.items.wrapper.RecipeWrapper;
import org.jetbrains.annotations.Nullable;
import wayoftime.bloodmagic.common.blockentity.ArcaneAshesTile;
import wayoftime.bloodmagic.common.item.BMItems;
import wayoftime.bloodmagic.common.recipe.BMRecipes;
import wayoftime.bloodmagic.common.recipe.ash.AshCraftingRecipe;
import wayoftime.bloodmagic.common.recipe.ash.AshInput;
import wayoftime.bloodmagic.common.recipe.ash.AshRecipe;
import wayoftime.bloodmagic.util.BlockEntityHelper;

public class ArcaneAshesBlock extends Block implements EntityBlock {

public static final DirectionProperty FACING = BlockStateProperties.FACING;
public static final EnumProperty<AshMode> MODE = EnumProperty.create("state", AshMode.class);

public ArcaneAshesBlock() {
super(Properties.of()
.instabreak() // feels right not to have to mine it
.noCollission()
.ignitedByLava()
);
}

protected static final VoxelShape BOX = Block.box(0, 0, 0, 16, 1, 16);
@Override
protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) {
return BOX;
}

@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, MODE);
}

private static RecipeManager.CachedCheck<AshInput, AshRecipe> lookup = null;
@Override
protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult) {
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof ArcaneAshesTile ashes)) {
return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}
ItemStack heldItem = player.getItemInHand(hand);
if (heldItem.is(BMBlocks.ARCANE_ASHES.asItem())) {
return ItemInteractionResult.CONSUME; // do not want to place ashes
}
if (ashes.inv.getStackInSlot(0).isEmpty()) {
ashes.inv.setStackInSlot(0, heldItem.split(1));
return ItemInteractionResult.sidedSuccess(level.isClientSide);
} else if (ashes.inv.getStackInSlot(1).isEmpty()) {
ashes.inv.setStackInSlot(1, heldItem.split(1));

if (ashes.inv.getStackInSlot(0).is(Items.POTION /*BMItems.FLASK.get()*/)) {
// TODO implement beacon effect
} else {
AshInput input = new AshInput(ashes.inv);
if (lookup == null) {
lookup = RecipeManager.createCheck(BMRecipes.ASH_TYPE.get());
}
RecipeHolder<AshRecipe> holder = lookup.getRecipeFor(input, level).orElse(null);
if (holder != null) {
ashes.inv.setStackInSlot(2, holder.value().assemble(input, level.registryAccess()));
level.sendBlockUpdated(pos, state, state.setValue(MODE, AshMode.CRAFTING), UPDATE_ALL);
level.scheduleTick(pos, state.getBlock(), 1);
}
}
return ItemInteractionResult.sidedSuccess(level.isClientSide);
}

return ItemInteractionResult.PASS_TO_DEFAULT_BLOCK_INTERACTION;
}

@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof ArcaneAshesTile ashes)) {
return;
}

AshMode mode = state.getValue(MODE);
switch (mode) {
case CRAFTING -> {
if (++ashes.progress >= 200) {
ItemStack output = ashes.inv.getStackInSlot(2);
if (level.isClientSide) {
Vec3 vec3 = Vec3.atLowerCornerWithOffset(pos, 0.5, 1 / 16f, 0.5).offsetRandom(level.random, 0.7f);
ItemEntity itementity = new ItemEntity(level, vec3.x(), vec3.y(), vec3.z(), output);
itementity.setDefaultPickUpDelay();
level.addFreshEntity(itementity);
}
ashes.progress = 0;
ashes.inv.setStackInSlot(0, ItemStack.EMPTY);
ashes.inv.setStackInSlot(1, ItemStack.EMPTY);
ashes.inv.setStackInSlot(2, ItemStack.EMPTY);
level.sendBlockUpdated(pos, state, state.setValue(MODE, AshMode.IDLE), UPDATE_ALL);
return;
}
level.scheduleTick(pos, state.getBlock(), 1);
}

case BEACON -> {
// TODO implement
}

case IDLE -> {
// why has tick when idle?
}
}
}

@Override
public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) {
super.animateTick(state, level, pos, random);
if (random.nextFloat() < 0.3f) {
switch (state.getValue(MODE)) {
case CRAFTING -> level.addParticle(new DustParticleOptions(DustParticleOptions.REDSTONE_PARTICLE_COLOR, 1.1f), pos.getX() + 0.5, pos.getY() + 0.1f, pos.getZ() + 0.5, 0.2, 0.2, 0.2);
case BEACON -> {
}
case IDLE -> {
}
}
}
}

@Override
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
// TODO implement
// check if valid trap items -> do trap; else do nothing
}

@Nullable
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().
setValue(MODE, AshMode.IDLE)
.setValue(FACING, context.getHorizontalDirection().getOpposite());
}

@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!state.is(newState.getBlock())) {
if (level.getBlockEntity(pos) instanceof ArcaneAshesTile ash) {
BlockEntityHelper.dropContents(level, pos, ash.inv, 2);
}
}
super.onRemove(state, level, pos, newState, movedByPiston);
}

@Override
public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new ArcaneAshesTile(pos, state);
}

public enum AshMode implements StringRepresentable {
IDLE,
CRAFTING,
BEACON;

@Override
public String getSerializedName() {
return name().toLowerCase();
}
}
}
2 changes: 2 additions & 0 deletions src/main/java/wayoftime/bloodmagic/common/block/BMBlocks.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import wayoftime.bloodmagic.common.datamap.BMDataMaps;
import wayoftime.bloodmagic.common.datamap.BloodRune;
import wayoftime.bloodmagic.api.altar.EnumRuneType;
import wayoftime.bloodmagic.common.item.ArcaneAshesItem;
import wayoftime.bloodmagic.util.BlockEntityHelper;
import wayoftime.bloodmagic.util.blockitem.BlockWithItemHolder;
import wayoftime.bloodmagic.util.blockitem.BlockWithItemRegister;
Expand All @@ -38,6 +39,7 @@ public class BMBlocks {
public static final BlockWithItemHolder<BloodTankBlock, BlockItem> BLOOD_TANK = BLOCK_REG.register("blood_tank", BloodTankBlock::new, block -> new BlockItem(block, new Item.Properties().component(BMDataComponents.CONTAINER_TIER, 1)));
public static final BlockWithItemHolder<HellfireForgeBlock, BlockItem> HELLFIRE_FORGE = BLOCK_REG.register("hellfire_forge", HellfireForgeBlock::new);
public static final BlockWithItemHolder<ARCBlock, BlockItem> ARC_BLOCK = BLOCK_REG.register("arc", ARCBlock::new);
public static final BlockWithItemHolder<ArcaneAshesBlock, ArcaneAshesItem> ARCANE_ASHES = BLOCK_REG.register("arcane_ashes", ArcaneAshesBlock::new, ArcaneAshesItem::new);
public static final BlockWithItemHolder<AlchemyTableBlock, BlockItem> ALCHEMY_TABLE = BLOCK_REG.register("alchemy_table", AlchemyTableBlock::new);

// TODO add model/textures for this and change registry to BASIC_REG
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package wayoftime.bloodmagic.common.blockentity;

import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeInput;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.items.ItemStackHandler;
import wayoftime.bloodmagic.common.recipe.ash.AshRecipe;

public class ArcaneAshesTile extends BlockEntity {

public ItemStackHandler inv = new ItemStackHandler(3) {
@Override
protected void onContentsChanged(int slot) {
super.onContentsChanged(slot);
setChanged();
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_ALL);
}
};

public int progress = 0;

public ArcaneAshesTile(BlockPos pos, BlockState blockState) {
super(BMTiles.ARCANE_ASHES.get(), pos, blockState);
}

@Override
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
inv.deserializeNBT(registries, tag.getCompound("inv"));
progress = tag.getInt("progress");
}

@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
tag.put("inv", inv.serializeNBT(registries));
tag.putInt("progress", progress);
}
}
14 changes: 14 additions & 0 deletions src/main/java/wayoftime/bloodmagic/common/blockentity/BMTiles.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import net.neoforged.neoforge.items.ItemStackHandler;
import net.neoforged.neoforge.items.wrapper.RangedWrapper;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
Expand Down Expand Up @@ -36,6 +37,9 @@ public class BMTiles {
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<LivingStationTile>> LIVING_STATION_TYPE = TILES.register("living_station",
() -> new BlockEntityType<>(LivingStationTile::new, Set.of(BMBlocks.LIVING_STATION.block().get()), null));

public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<ArcaneAshesTile>> ARCANE_ASHES = TILES.register("arcane_ashes",
() -> new BlockEntityType<>(ArcaneAshesTile::new, Set.of(BMBlocks.ARCANE_ASHES.block().get()), null));

public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<AlchemyTableTile>> ALCHEMY_TABLE_TYPE = TILES.register("alchemy_table",
() -> new BlockEntityType<>(AlchemyTableTile::new, Set.of(BMBlocks.ALCHEMY_TABLE.block().get()), null));

Expand Down Expand Up @@ -83,6 +87,16 @@ private static void registerTileCapabilities(RegisterCapabilitiesEvent event) {
return new RangedWrapper(tile.itemCap, start, end);
}
);
event.registerBlockEntity(
Capabilities.ItemHandler.BLOCK,
ARCANE_ASHES.get(),
(tile, side) -> {
if (side == null) {
return tile.inv; // jade & co only. no automation
}
return null;
}
);
event.registerBlockEntity(
Capabilities.ItemHandler.BLOCK,
ALCHEMY_TABLE_TYPE.get(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package wayoftime.bloodmagic.common.item;

import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;

public class ArcaneAshesItem extends BlockItem {
public ArcaneAshesItem(Block block) {
super(block, new Properties()
.stacksTo(1)
.durability(42) // 1.20 has 20 but that seems low given that we want to give it more stuff to do
);
}

@Override
public InteractionResult useOn(UseOnContext context) {
return place(new BlockPlaceContext(context));
}

@Override
public InteractionResult place(BlockPlaceContext context) {
if (!this.getBlock().isEnabled(context.getLevel().enabledFeatures())) {
return InteractionResult.FAIL;
} else if (!context.canPlace()) {
return InteractionResult.FAIL;
} else {
BlockPlaceContext blockplacecontext = this.updatePlacementContext(context);
if (blockplacecontext == null) {
return InteractionResult.FAIL;
} else {
BlockState blockstate = this.getPlacementState(blockplacecontext);
if (blockstate == null) {
return InteractionResult.FAIL;
} else if (!this.placeBlock(blockplacecontext, blockstate)) {
return InteractionResult.FAIL;
} else {
BlockPos blockpos = blockplacecontext.getClickedPos();
Level level = blockplacecontext.getLevel();
Player player = blockplacecontext.getPlayer();
ItemStack itemstack = blockplacecontext.getItemInHand();
BlockState blockstate1 = level.getBlockState(blockpos);

SoundType soundtype = blockstate1.getSoundType(level, blockpos, context.getPlayer());
level.playSound(
player,
blockpos,
this.getPlaceSound(blockstate1, level, blockpos, context.getPlayer()),
SoundSource.BLOCKS,
(soundtype.getVolume() + 1.0F) / 2.0F,
soundtype.getPitch() * 0.8F
);
level.gameEvent(GameEvent.BLOCK_PLACE, blockpos, GameEvent.Context.of(player, blockstate1));
itemstack.hurtAndBreak(1, player, context.getHand() == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND);
return InteractionResult.sidedSuccess(level.isClientSide);
}
}
}
}
}
Loading