diff --git a/src/datagen/java/wayoftime/bloodmagic/datagen/provider/BMLanguageProvider.java b/src/datagen/java/wayoftime/bloodmagic/datagen/provider/BMLanguageProvider.java index bb0fa47b03..5dfe1570cf 100644 --- a/src/datagen/java/wayoftime/bloodmagic/datagen/provider/BMLanguageProvider.java +++ b/src/datagen/java/wayoftime/bloodmagic/datagen/provider/BMLanguageProvider.java @@ -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"); diff --git a/src/generated/resources/assets/bloodmagic/lang/en_us.json b/src/generated/resources/assets/bloodmagic/lang/en_us.json index 9e795b0ca3..86ce9445bc 100644 --- a/src/generated/resources/assets/bloodmagic/lang/en_us.json +++ b/src/generated/resources/assets/bloodmagic/lang/en_us.json @@ -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", diff --git a/src/main/java/wayoftime/bloodmagic/common/block/ArcaneAshesBlock.java b/src/main/java/wayoftime/bloodmagic/common/block/ArcaneAshesBlock.java new file mode 100644 index 0000000000..bd9555e504 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/block/ArcaneAshesBlock.java @@ -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 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 builder) { + builder.add(FACING, MODE); + } + + private static RecipeManager.CachedCheck 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 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(); + } + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/block/BMBlocks.java b/src/main/java/wayoftime/bloodmagic/common/block/BMBlocks.java index 05efdde40b..8c4d02b909 100644 --- a/src/main/java/wayoftime/bloodmagic/common/block/BMBlocks.java +++ b/src/main/java/wayoftime/bloodmagic/common/block/BMBlocks.java @@ -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; @@ -38,6 +39,7 @@ public class BMBlocks { public static final BlockWithItemHolder 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 HELLFIRE_FORGE = BLOCK_REG.register("hellfire_forge", HellfireForgeBlock::new); public static final BlockWithItemHolder ARC_BLOCK = BLOCK_REG.register("arc", ARCBlock::new); + public static final BlockWithItemHolder ARCANE_ASHES = BLOCK_REG.register("arcane_ashes", ArcaneAshesBlock::new, ArcaneAshesItem::new); public static final BlockWithItemHolder ALCHEMY_TABLE = BLOCK_REG.register("alchemy_table", AlchemyTableBlock::new); // TODO add model/textures for this and change registry to BASIC_REG diff --git a/src/main/java/wayoftime/bloodmagic/common/blockentity/ArcaneAshesTile.java b/src/main/java/wayoftime/bloodmagic/common/blockentity/ArcaneAshesTile.java new file mode 100644 index 0000000000..e6775aff87 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/blockentity/ArcaneAshesTile.java @@ -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); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/blockentity/BMTiles.java b/src/main/java/wayoftime/bloodmagic/common/blockentity/BMTiles.java index c5b4f3c795..7e3b88a5ab 100644 --- a/src/main/java/wayoftime/bloodmagic/common/blockentity/BMTiles.java +++ b/src/main/java/wayoftime/bloodmagic/common/blockentity/BMTiles.java @@ -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; @@ -36,6 +37,9 @@ public class BMTiles { public static final DeferredHolder, BlockEntityType> LIVING_STATION_TYPE = TILES.register("living_station", () -> new BlockEntityType<>(LivingStationTile::new, Set.of(BMBlocks.LIVING_STATION.block().get()), null)); + public static final DeferredHolder, BlockEntityType> ARCANE_ASHES = TILES.register("arcane_ashes", + () -> new BlockEntityType<>(ArcaneAshesTile::new, Set.of(BMBlocks.ARCANE_ASHES.block().get()), null)); + public static final DeferredHolder, BlockEntityType> ALCHEMY_TABLE_TYPE = TILES.register("alchemy_table", () -> new BlockEntityType<>(AlchemyTableTile::new, Set.of(BMBlocks.ALCHEMY_TABLE.block().get()), null)); @@ -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(), diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ArcaneAshesItem.java b/src/main/java/wayoftime/bloodmagic/common/item/ArcaneAshesItem.java new file mode 100644 index 0000000000..4092bbe769 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ArcaneAshesItem.java @@ -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); + } + } + } + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/recipe/BMRecipes.java b/src/main/java/wayoftime/bloodmagic/common/recipe/BMRecipes.java index ee1d6d5ea9..b4f80f160d 100644 --- a/src/main/java/wayoftime/bloodmagic/common/recipe/BMRecipes.java +++ b/src/main/java/wayoftime/bloodmagic/common/recipe/BMRecipes.java @@ -12,6 +12,9 @@ import wayoftime.bloodmagic.common.recipe.alchemy_table.AlchemyTableSerializer; import wayoftime.bloodmagic.common.recipe.arc.ARCRecipe; import wayoftime.bloodmagic.common.recipe.arc.ARCSerializer; +import wayoftime.bloodmagic.common.recipe.ash.AshCraftingRecipe; +import wayoftime.bloodmagic.common.recipe.ash.AshCraftingSerializer; +import wayoftime.bloodmagic.common.recipe.ash.AshRecipe; import wayoftime.bloodmagic.common.recipe.bloodaltar.BloodAltarRecipe; import wayoftime.bloodmagic.common.recipe.bloodaltar.BloodAltarRecipeSerializer; import wayoftime.bloodmagic.common.recipe.forge.ForgeRecipe; @@ -42,6 +45,9 @@ public class BMRecipes { public static final DeferredHolder, RecipeType> ENERGY_TIERED_TYPE = TYPES.register(EnergyTieredRecipe.NAME, () -> RecipeType.simple(bm(EnergyTieredRecipe.NAME))); public static final DeferredHolder, RecipeSerializer> ENERGY_TIERED_SERIALIZER = SERIALIZERS.register(EnergyTieredRecipe.NAME, EnergyTieredSerializer::new); + public static final DeferredHolder, RecipeType> ASH_TYPE = TYPES.register(AshRecipe.NAME, () -> RecipeType.simple(bm(AshRecipe.NAME))); + public static final DeferredHolder, RecipeSerializer> ASH_CRAFTING_SERIALIZER = SERIALIZERS.register(AshCraftingSerializer.NAME, AshCraftingSerializer::new); + public static final DeferredHolder, RecipeType> ALCHEMY_TABLE_TYPE = TYPES.register(AlchemyTableRecipe.RECIPE_TYPE_NAME, () -> RecipeType.simple(bm(AlchemyTableRecipe.RECIPE_TYPE_NAME))); public static final DeferredHolder, RecipeSerializer> ALCHEMY_TABLE_SERIALIZER = SERIALIZERS.register(AlchemyTableRecipe.RECIPE_TYPE_NAME, AlchemyTableSerializer::new); diff --git a/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshCraftingRecipe.java b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshCraftingRecipe.java new file mode 100644 index 0000000000..35a31f24e7 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshCraftingRecipe.java @@ -0,0 +1,30 @@ +package wayoftime.bloodmagic.common.recipe.ash; + +import net.minecraft.core.HolderLookup; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.level.Level; +import wayoftime.bloodmagic.common.recipe.BMRecipes; + +public record AshCraftingRecipe(Ingredient first, Ingredient second, ItemStack output) implements AshRecipe { + @Override + public boolean matches(AshInput input, Level level) { + return first.test(input.getItem(0)) && second.test(input.getItem(1)); + } + + @Override + public ItemStack assemble(AshInput input, HolderLookup.Provider registries) { + return output.copy(); + } + + @Override + public ItemStack getResultItem(HolderLookup.Provider registries) { + return output.copy(); + } + + @Override + public RecipeSerializer getSerializer() { + return BMRecipes.ASH_CRAFTING_SERIALIZER.get(); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshCraftingSerializer.java b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshCraftingSerializer.java new file mode 100644 index 0000000000..d4c87a6612 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshCraftingSerializer.java @@ -0,0 +1,37 @@ +package wayoftime.bloodmagic.common.recipe.ash; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.item.crafting.RecipeSerializer; + +public class AshCraftingSerializer implements RecipeSerializer { + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(builder -> builder.group( + Ingredient.CODEC.fieldOf("first").forGetter(AshCraftingRecipe::first), + Ingredient.CODEC.fieldOf("second").forGetter(AshCraftingRecipe::second), + ItemStack.CODEC.fieldOf("result").forGetter(AshCraftingRecipe::output) + ).apply(builder, AshCraftingRecipe::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + Ingredient.CONTENTS_STREAM_CODEC, AshCraftingRecipe::first, + Ingredient.CONTENTS_STREAM_CODEC, AshCraftingRecipe::second, + ItemStack.STREAM_CODEC, AshCraftingRecipe::output, + AshCraftingRecipe::new + ); + + public static final String NAME = "ash_crafting"; + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + public StreamCodec streamCodec() { + return STREAM_CODEC; + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshInput.java b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshInput.java new file mode 100644 index 0000000000..7f91670986 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshInput.java @@ -0,0 +1,15 @@ +package wayoftime.bloodmagic.common.recipe.ash; + +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.wrapper.RecipeWrapper; + +public class AshInput extends RecipeWrapper { + public AshInput(IItemHandler inv) { + super(inv); + } + + @Override + public int size() { + return 2; + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshRecipe.java b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshRecipe.java new file mode 100644 index 0000000000..eb9967e6b1 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/recipe/ash/AshRecipe.java @@ -0,0 +1,19 @@ +package wayoftime.bloodmagic.common.recipe.ash; + +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeType; +import wayoftime.bloodmagic.common.recipe.BMRecipes; + +public interface AshRecipe extends Recipe { + String NAME = "arcane_ash"; + + @Override + default RecipeType getType() { + return BMRecipes.ASH_TYPE.get(); + } + + @Override + default boolean canCraftInDimensions(int width, int height) { + return false; + } +} diff --git a/src/main/java/wayoftime/bloodmagic/util/BlockEntityHelper.java b/src/main/java/wayoftime/bloodmagic/util/BlockEntityHelper.java index beb1a85b2f..8713467117 100644 --- a/src/main/java/wayoftime/bloodmagic/util/BlockEntityHelper.java +++ b/src/main/java/wayoftime/bloodmagic/util/BlockEntityHelper.java @@ -29,4 +29,10 @@ public static void dropContents(Level level, BlockPos pos, IItemHandler handler) Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), handler.getStackInSlot(i)); } } + + public static void dropContents(Level level, BlockPos pos, IItemHandler handler, int maxIndex) { + for (int i = 0; i < maxIndex; i++) { + Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), handler.getStackInSlot(i)); + } + } } diff --git a/src/main/resources/assets/bloodmagic/blockstates/arcane_ashes.json b/src/main/resources/assets/bloodmagic/blockstates/arcane_ashes.json new file mode 100755 index 0000000000..532b96d027 --- /dev/null +++ b/src/main/resources/assets/bloodmagic/blockstates/arcane_ashes.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=south": { + "model": "bloodmagic:block/arcane_ashes" + }, + "facing=west": { + "model": "bloodmagic:block/arcane_ashes", + "y": 90 + }, + "facing=north": { + "model": "bloodmagic:block/arcane_ashes", + "y": 180 + }, + "facing=east": { + "model": "bloodmagic:block/arcane_ashes", + "y": 270 + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/bloodmagic/models/block/arcane_ashes.json b/src/main/resources/assets/bloodmagic/models/block/arcane_ashes.json new file mode 100644 index 0000000000..7987280d79 --- /dev/null +++ b/src/main/resources/assets/bloodmagic/models/block/arcane_ashes.json @@ -0,0 +1,17 @@ +{ + "parent": "minecraft:block/block", + "render_type": "minecraft:translucent", + "textures": { + "particle": "bloodmagic:block/wip_array", + "top": "bloodmagic:block/wip_array" + }, + "elements": [ + { + "from": [0, 0, 0], + "to": [16, 0, 16], + "faces": { + "up": {"uv": [0, 0, 16, 16], "texture": "#top"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/bloodmagic/models/item/arcane_ashes.json b/src/main/resources/assets/bloodmagic/models/item/arcane_ashes.json new file mode 100644 index 0000000000..c664c909f4 --- /dev/null +++ b/src/main/resources/assets/bloodmagic/models/item/arcane_ashes.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "bloodmagic:item/arcane_ashes" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/bloodmagic/textures/block/wip_array.png b/src/main/resources/assets/bloodmagic/textures/block/wip_array.png new file mode 100755 index 0000000000..1129738269 Binary files /dev/null and b/src/main/resources/assets/bloodmagic/textures/block/wip_array.png differ diff --git a/src/main/resources/assets/bloodmagic/textures/item/arcane_ashes.png b/src/main/resources/assets/bloodmagic/textures/item/arcane_ashes.png new file mode 100755 index 0000000000..43025e282b Binary files /dev/null and b/src/main/resources/assets/bloodmagic/textures/item/arcane_ashes.png differ