Basic framework for vacuum arc furnace multiblock. Moved multiblock methods to MultiblockHelper.

This commit is contained in:
XevianLight
2026-01-18 21:06:14 -07:00
parent 557c2761a7
commit ea998165be
32 changed files with 1335 additions and 245 deletions

View File

@@ -1,6 +1,7 @@
// 1.21.1 2026-01-17T20:45:45.6230298 Loot Tables // 1.21.1 2026-01-18T19:51:57.3558369 Loot Tables
69d8318ddba171526d1fabb87d9d93548ed8598e data/aphelion/loot_table/blocks/arc_furnace_casing.json 69d8318ddba171526d1fabb87d9d93548ed8598e data/aphelion/loot_table/blocks/arc_furnace_casing.json
05f08985e601d30116f67e2f07b48b03b40cdca6 data/aphelion/loot_table/blocks/block_steel.json 05f08985e601d30116f67e2f07b48b03b40cdca6 data/aphelion/loot_table/blocks/block_steel.json
ff43a9c3741faf10b1e156a7a74d5cfb035cc118 data/aphelion/loot_table/blocks/dimension_changer.json ff43a9c3741faf10b1e156a7a74d5cfb035cc118 data/aphelion/loot_table/blocks/dimension_changer.json
b63130d9c10485676303d729807b6fcaac080294 data/aphelion/loot_table/blocks/electric_arc_furnace.json b63130d9c10485676303d729807b6fcaac080294 data/aphelion/loot_table/blocks/electric_arc_furnace.json
1ab50c99e9f478840b9d003fd56ebdcab12fbbce data/aphelion/loot_table/blocks/test_block.json 1ab50c99e9f478840b9d003fd56ebdcab12fbbce data/aphelion/loot_table/blocks/test_block.json
7d8eeb99a1bc942a6e2cf292b21fd4534062b5ab data/aphelion/loot_table/blocks/vacuum_arc_furnace_controller.json

View File

@@ -1,12 +1,15 @@
// 1.21.1 2026-01-17T21:22:18.4335623 Block States: aphelion // 1.21.1 2026-01-18T19:51:57.3548439 Block States: aphelion
851ff42f7b21dec86107c8e0cefb3934ae4ebc08 assets/aphelion/blockstates/block_steel.json 851ff42f7b21dec86107c8e0cefb3934ae4ebc08 assets/aphelion/blockstates/block_steel.json
30b9c0efd7aaadb5412d98e4568f98b3632adbb9 assets/aphelion/blockstates/dimension_changer.json 30b9c0efd7aaadb5412d98e4568f98b3632adbb9 assets/aphelion/blockstates/dimension_changer.json
cb4287104006c80c8396b290ab5258df65d62cef assets/aphelion/blockstates/electric_arc_furnace.json
b86c50fddcf6c8c6c19cb748529239d5962a3ede assets/aphelion/blockstates/test_block.json b86c50fddcf6c8c6c19cb748529239d5962a3ede assets/aphelion/blockstates/test_block.json
a810b97f4dace35d026f28d96cb9c47c93600d75 assets/aphelion/models/block/block_steel.json a810b97f4dace35d026f28d96cb9c47c93600d75 assets/aphelion/models/block/block_steel.json
2d3592b7ab7132908709243e97540151e0fb762e assets/aphelion/models/block/dimension_changer.json 2d3592b7ab7132908709243e97540151e0fb762e assets/aphelion/models/block/dimension_changer.json
5f7e8674070f31a63875b5d6147153bfa0eef61a assets/aphelion/models/block/electric_arc_furnace.json
e0971228b4a1c4bc9dbab58a7dacdc3ae6037e02 assets/aphelion/models/block/test_block.json e0971228b4a1c4bc9dbab58a7dacdc3ae6037e02 assets/aphelion/models/block/test_block.json
cdc831b0f1c462be64825fd34bd446e5b95afac6 assets/aphelion/models/item/arc_furnace_casing.json cdc831b0f1c462be64825fd34bd446e5b95afac6 assets/aphelion/models/item/arc_furnace_casing.json
3599f9037eb2f66de1765318b97ab564c3eae92f assets/aphelion/models/item/block_steel.json 3599f9037eb2f66de1765318b97ab564c3eae92f assets/aphelion/models/item/block_steel.json
db0ec473a016ce05c258cde18a217d47a9ea8324 assets/aphelion/models/item/dimension_changer.json db0ec473a016ce05c258cde18a217d47a9ea8324 assets/aphelion/models/item/dimension_changer.json
279080c06ada87f54fd0a7b885b256dbe25a946a assets/aphelion/models/item/electric_arc_furnace.json 279080c06ada87f54fd0a7b885b256dbe25a946a assets/aphelion/models/item/electric_arc_furnace.json
74418ef1cf678e72e7534924274688ef5a68af0e assets/aphelion/models/item/test_block.json 74418ef1cf678e72e7534924274688ef5a68af0e assets/aphelion/models/item/test_block.json
88ca3602517e99f7feaed57eddfc96965a25761c assets/aphelion/models/item/vacuum_arc_furnace_controller.json

View File

@@ -15,6 +15,7 @@ import net.xevianlight.aphelion.recipe.ModRecipes;
import net.xevianlight.aphelion.screen.ElectricArcFurnaceScreen; import net.xevianlight.aphelion.screen.ElectricArcFurnaceScreen;
import net.xevianlight.aphelion.screen.ModMenuTypes; import net.xevianlight.aphelion.screen.ModMenuTypes;
import net.xevianlight.aphelion.screen.TestBlockScreen; import net.xevianlight.aphelion.screen.TestBlockScreen;
import net.xevianlight.aphelion.screen.VacuumArcFurnaceScreen;
import org.slf4j.Logger; import org.slf4j.Logger;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
@@ -120,6 +121,7 @@ public class Aphelion {
public static void registerScreens(RegisterMenuScreensEvent event) { public static void registerScreens(RegisterMenuScreensEvent event) {
event.register(ModMenuTypes.TEST_BLOCK_MENU.get(), TestBlockScreen::new); event.register(ModMenuTypes.TEST_BLOCK_MENU.get(), TestBlockScreen::new);
event.register(ModMenuTypes.ELECTRIC_ARC_FURNACE_MENU.get(), ElectricArcFurnaceScreen::new); event.register(ModMenuTypes.ELECTRIC_ARC_FURNACE_MENU.get(), ElectricArcFurnaceScreen::new);
event.register(ModMenuTypes.VACUUM_ARC_FURNACE_MENU.get(), VacuumArcFurnaceScreen::new);
} }
} }
} }

View File

@@ -2,6 +2,11 @@ package net.xevianlight.aphelion.block.custom;
import com.mojang.serialization.MapCodec; import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@@ -13,13 +18,17 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.xevianlight.aphelion.block.entity.custom.EAFPartEntity; import net.xevianlight.aphelion.block.entity.custom.EAFPartEntity;
import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity; import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
import net.xevianlight.aphelion.block.entity.custom.VacuumArcFurnaceControllerEntity;
import net.xevianlight.aphelion.util.AphelionBlockStateProperties;
import net.xevianlight.aphelion.util.MultiblockHelper;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class ArcFurnaceCasingBlock extends BaseEntityBlock { public class ArcFurnaceCasingBlock extends BaseEntityBlock {
public static final BooleanProperty FORMED = BooleanProperty.create("formed"); public static final BooleanProperty FORMED = AphelionBlockStateProperties.FORMED;
public ArcFurnaceCasingBlock(Properties properties) { public ArcFurnaceCasingBlock(Properties properties) {
super(properties); super(properties);
@@ -27,6 +36,11 @@ public class ArcFurnaceCasingBlock extends BaseEntityBlock {
.setValue(FORMED, false)); .setValue(FORMED, false));
} }
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
return CODEC;
}
public static Properties getProperties() { public static Properties getProperties() {
return Properties return Properties
.of() .of()
@@ -42,18 +56,18 @@ public class ArcFurnaceCasingBlock extends BaseEntityBlock {
public static final MapCodec<ArcFurnaceCasingBlock> CODEC = simpleCodec(ArcFurnaceCasingBlock::new); public static final MapCodec<ArcFurnaceCasingBlock> CODEC = simpleCodec(ArcFurnaceCasingBlock::new);
@Override // @Override
protected MapCodec<? extends BaseEntityBlock> codec() { // protected MapCodec<? extends BaseEntityBlock> codec() {
return CODEC; // return CODEC;
} // }
@Override // @Override
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) { // public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new EAFPartEntity(blockPos, blockState); // return new EAFPartEntity(blockPos, blockState);
} // }
private void pingNearbyController(Level level, BlockPos pos) { private void pingNearbyController(Level level, BlockPos pos) {
int r = 3; int r = 5;
BlockPos.MutableBlockPos mp = new BlockPos.MutableBlockPos(); BlockPos.MutableBlockPos mp = new BlockPos.MutableBlockPos();
for (int dx=-r; dx<=r; dx++) for (int dx=-r; dx<=r; dx++)
@@ -61,14 +75,28 @@ public class ArcFurnaceCasingBlock extends BaseEntityBlock {
for (int dz=-r; dz<=r; dz++) { for (int dz=-r; dz<=r; dz++) {
mp.set(pos.getX()+dx, pos.getY()+dy, pos.getZ()+dz); mp.set(pos.getX()+dx, pos.getY()+dy, pos.getZ()+dz);
BlockEntity be = level.getBlockEntity(mp); BlockEntity be = level.getBlockEntity(mp);
if (be instanceof ElectricArcFurnaceEntity eaf) { if (be instanceof VacuumArcFurnaceControllerEntity vaf) {
if (level.getBlockState(eaf.getBlockPos()).getBlock() instanceof ElectricArcFurnace) { if (level.getBlockState(vaf.getBlockPos()).getBlock() instanceof VacuumArcFurnaceController) {
eaf.tryForm(); MultiblockHelper.tryForm(level, vaf.getBlockState(), vaf.getBlockPos(), VacuumArcFurnaceControllerEntity.SHAPE, AphelionBlockStateProperties.FORMED);
} }
} }
} }
} }
@Override
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult result) {
if (state.getValue(AphelionBlockStateProperties.FORMED)) {
if (!level.isClientSide && player instanceof ServerPlayer serverPlayer && level.getBlockEntity(pos) instanceof EAFPartEntity eafPartEntity) {
if (eafPartEntity.getControllerPos() != null)
if (level.getBlockEntity(eafPartEntity.getControllerPos()) instanceof VacuumArcFurnaceControllerEntity)
serverPlayer.openMenu(new SimpleMenuProvider((VacuumArcFurnaceControllerEntity) level.getBlockEntity(eafPartEntity.getControllerPos()), Component.literal("Vacuum Arc Furnace")), eafPartEntity.getControllerPos());
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
return InteractionResult.FAIL;
}
@Override @Override
public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston); super.onPlace(state, level, pos, oldState, movedByPiston);
@@ -97,4 +125,9 @@ public class ArcFurnaceCasingBlock extends BaseEntityBlock {
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FORMED); builder.add(FORMED);
} }
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new EAFPartEntity(blockPos, blockState);
}
} }

View File

@@ -27,6 +27,8 @@ import net.minecraft.world.phys.BlockHitResult;
import net.neoforged.neoforge.items.ItemStackHandler; import net.neoforged.neoforge.items.ItemStackHandler;
import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity; import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.util.AphelionBlockStateProperties;
import net.xevianlight.aphelion.util.MultiblockHelper;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -36,7 +38,7 @@ public class ElectricArcFurnace extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
public static final BooleanProperty LIT = BlockStateProperties.LIT; public static final BooleanProperty LIT = BlockStateProperties.LIT;
public static final BooleanProperty FORMED = BooleanProperty.create("formed"); public static final BooleanProperty FORMED = AphelionBlockStateProperties.FORMED;
public ElectricArcFurnace(Properties properties) { public ElectricArcFurnace(Properties properties) {
super(properties); super(properties);
@@ -72,7 +74,7 @@ public class ElectricArcFurnace extends BaseEntityBlock {
@Override @Override
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult result) { public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult result) {
if (!level.isClientSide && player instanceof ServerPlayer serverPlayer && level.getBlockEntity(pos) instanceof ElectricArcFurnaceEntity electricArcFurnaceEntity && state.getValue(FORMED)) { if (!level.isClientSide && player instanceof ServerPlayer serverPlayer && level.getBlockEntity(pos) instanceof ElectricArcFurnaceEntity electricArcFurnaceEntity) {
serverPlayer.openMenu(new SimpleMenuProvider(electricArcFurnaceEntity, Component.literal("Electric Arc Furnace")), pos); serverPlayer.openMenu(new SimpleMenuProvider(electricArcFurnaceEntity, Component.literal("Electric Arc Furnace")), pos);
} }
return InteractionResult.sidedSuccess(level.isClientSide); return InteractionResult.sidedSuccess(level.isClientSide);
@@ -95,7 +97,7 @@ public class ElectricArcFurnace extends BaseEntityBlock {
if (!level.isClientSide && state.getBlock() != newState.getBlock()) { if (!level.isClientSide && state.getBlock() != newState.getBlock()) {
BlockEntity blockEntity= level.getBlockEntity(pos); BlockEntity blockEntity= level.getBlockEntity(pos);
if (blockEntity instanceof ElectricArcFurnaceEntity electricArcFurnaceEntity) { if (blockEntity instanceof ElectricArcFurnaceEntity electricArcFurnaceEntity) {
if(state.getValue(FORMED)) electricArcFurnaceEntity.unformForRemoval(); // if(state.getValue(FORMED)) MultiblockHelper.unformForRemoval(level, state, pos, ElectricArcFurnaceEntity.SHAPE, AphelionBlockStateProperties.FORMED);
electricArcFurnaceEntity.drops(); electricArcFurnaceEntity.drops();
} }
} }
@@ -107,9 +109,9 @@ public class ElectricArcFurnace extends BaseEntityBlock {
super.onPlace(state, level, pos, oldState, movedByPiston); super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide() && oldState.getBlock() != state.getBlock()) { if (!level.isClientSide() && oldState.getBlock() != state.getBlock()) {
BlockEntity blockEntity= level.getBlockEntity(pos); BlockEntity blockEntity= level.getBlockEntity(pos);
if (blockEntity instanceof ElectricArcFurnaceEntity electricArcFurnaceEntity) { // if (blockEntity instanceof ElectricArcFurnaceEntity electricArcFurnaceEntity) {
electricArcFurnaceEntity.tryForm(); // MultiblockHelper.tryForm(level, state, pos, ElectricArcFurnaceEntity.SHAPE, AphelionBlockStateProperties.FORMED);
} // }
} }
} }

View File

@@ -0,0 +1,196 @@
package net.xevianlight.aphelion.block.custom;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.neoforged.neoforge.items.ItemStackHandler;
import net.xevianlight.aphelion.block.entity.custom.VacuumArcFurnaceControllerEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.util.AphelionBlockStateProperties;
import net.xevianlight.aphelion.util.MultiblockHelper;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class VacuumArcFurnaceController extends BaseEntityBlock {
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
public static final BooleanProperty LIT = BlockStateProperties.LIT;
public static final BooleanProperty FORMED = AphelionBlockStateProperties.FORMED;
public VacuumArcFurnaceController(Properties properties) {
super(properties);
this.registerDefaultState(this.getStateDefinition().any()
.setValue(FORMED, false));
}
public static final MapCodec<VacuumArcFurnaceController> CODEC = simpleCodec(VacuumArcFurnaceController::new);
private final int INPUT_SLOT = 0;
private final int SECONDARY_INPUT_SLOT = 1;
private final int OUTPUT_SLOT = 2;
private final int ENERGY_SLOT = 3;
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
return CODEC;
}
public static Properties getProperties() {
return Properties
.of()
.sound(SoundType.METAL)
.destroyTime(2f)
.explosionResistance(10f)
.requiresCorrectToolForDrops();
}
public static Item.Properties getItemProperties() {
return new Item.Properties();
}
@Override
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult result) {
if (!level.isClientSide && player instanceof ServerPlayer serverPlayer && level.getBlockEntity(pos) instanceof VacuumArcFurnaceControllerEntity vacuumArcFurnaceEntity) {
if (vacuumArcFurnaceEntity.isFormed())
serverPlayer.openMenu(new SimpleMenuProvider(vacuumArcFurnaceEntity, Component.literal("Vacuum Arc Furnace")), pos);
}
return InteractionResult.sidedSuccess(level.isClientSide);
}
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
return new VacuumArcFurnaceControllerEntity(blockPos, blockState);
}
@Override
public RenderShape getRenderShape(BlockState pState) {
return RenderShape.MODEL;
}
@Override
protected void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston) {
if (!level.isClientSide && state.getBlock() != newState.getBlock()) {
BlockEntity blockEntity= level.getBlockEntity(pos);
if (blockEntity instanceof VacuumArcFurnaceControllerEntity vacuumArcFurnaceEntity) {
if(state.getValue(FORMED)) MultiblockHelper.unformForRemoval(level, state, pos, vacuumArcFurnaceEntity.SHAPE, AphelionBlockStateProperties.FORMED);
vacuumArcFurnaceEntity.drops();
}
}
super.onRemove(state, level, pos, newState, movedByPiston);
}
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
super.onPlace(state, level, pos, oldState, movedByPiston);
if (!level.isClientSide() && oldState.getBlock() != state.getBlock()) {
BlockEntity blockEntity= level.getBlockEntity(pos);
if (blockEntity instanceof VacuumArcFurnaceControllerEntity vacuumArcFurnaceEntity) {
MultiblockHelper.tryForm(level, state, pos, vacuumArcFurnaceEntity.SHAPE, AphelionBlockStateProperties.FORMED);
}
}
}
public static int getRedstoneSignalFromItemHandler(@javax.annotation.Nullable ItemStackHandler itemStackHandler, List<Integer> slots) {
if (itemStackHandler == null) {
return 0;
} else {
int i = 0;
float f = 0.0F;
for(int slot : slots) {
ItemStack itemstack = itemStackHandler.getStackInSlot(slot);
if (!itemstack.isEmpty()) {
f += (float)itemstack.getCount() / (float)Math.min(itemStackHandler.getSlotLimit(slot), itemstack.getMaxStackSize());
++i;
}
}
f /= (float)slots.size();
return Mth.floor(f * 14.0F) + (i > 0 ? 1 : 0);
}
}
@Override
protected boolean isSignalSource(BlockState state) {
return true;
}
@Override
protected int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) {
return super.getSignal(state, level, pos, direction);
}
@Override
protected boolean hasAnalogOutputSignal(BlockState state) {
return true;
}
@Override
protected int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos pos) {
List<Integer> slots = new ArrayList<>();
slots.add(VacuumArcFurnaceControllerEntity.INPUT_SLOT);
slots.add(VacuumArcFurnaceControllerEntity.SECONDARY_INPUT_SLOT);
slots.add(VacuumArcFurnaceControllerEntity.OUTPUT_SLOT);
VacuumArcFurnaceControllerEntity vacuumArcFurnaceEntity = ((VacuumArcFurnaceControllerEntity) level.getBlockEntity(pos));
if (vacuumArcFurnaceEntity != null)
return getRedstoneSignalFromItemHandler(vacuumArcFurnaceEntity.inventory, slots);
return 0;
}
@Override
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> blockEntityType) {
if (level.isClientSide) {
return null;
}
return createTickerHelper(blockEntityType, ModBlockEntities.VACUUM_ARC_FURNACE_ENTITY.get(), (level1, blockPos, blockState, vacuumArcFurnaceEntity) -> vacuumArcFurnaceEntity.tick(level1, blockPos, blockState));
}
@Override
protected BlockState rotate(BlockState state, Rotation rotation) {
return state.setValue(FACING, rotation.rotate(state.getValue(FACING)));
}
@Override
protected BlockState mirror(BlockState state, Mirror mirror) {
return state.rotate(mirror.getRotation(state.getValue(FACING)));
}
@Override
public @Nullable BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()).setValue(LIT, false).setValue(FORMED, false);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(FACING, LIT, FORMED);
}
}

View File

@@ -7,9 +7,10 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.util.IMultiblockPart;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class EAFPartEntity extends BlockEntity { public class EAFPartEntity extends BlockEntity implements IMultiblockPart {
@Nullable private BlockPos controllerPos; @Nullable private BlockPos controllerPos;
public EAFPartEntity(BlockPos pos, BlockState blockState) { public EAFPartEntity(BlockPos pos, BlockState blockState) {

View File

@@ -8,12 +8,9 @@ import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Containers; import net.minecraft.world.Containers;
import net.minecraft.world.MenuProvider; import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer; import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobSpawnType;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -23,26 +20,24 @@ import net.minecraft.world.item.crafting.*;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.energy.IEnergyStorage; import net.neoforged.neoforge.energy.IEnergyStorage;
import net.neoforged.neoforge.items.IItemHandler; import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.ItemStackHandler; import net.neoforged.neoforge.items.ItemStackHandler;
import net.xevianlight.aphelion.block.custom.ArcFurnaceCasingBlock;
import net.xevianlight.aphelion.block.custom.ElectricArcFurnace; import net.xevianlight.aphelion.block.custom.ElectricArcFurnace;
import net.xevianlight.aphelion.block.entity.energy.ModEnergyStorage; import net.xevianlight.aphelion.block.entity.energy.ModEnergyStorage;
import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.core.init.ModBlocks;
import net.xevianlight.aphelion.recipe.ElectricArcFurnaceRecipe; import net.xevianlight.aphelion.recipe.ElectricArcFurnaceRecipe;
import net.xevianlight.aphelion.recipe.ElectricArcFurnaceRecipeInput; import net.xevianlight.aphelion.recipe.ElectricArcFurnaceRecipeInput;
import net.xevianlight.aphelion.recipe.ModRecipes; import net.xevianlight.aphelion.recipe.ModRecipes;
import net.xevianlight.aphelion.screen.ElectricArcFurnaceMenu; import net.xevianlight.aphelion.screen.ElectricArcFurnaceMenu;
import net.xevianlight.aphelion.util.AphelionBlockStateProperties;
import net.xevianlight.aphelion.util.MultiblockHelper;
import net.xevianlight.aphelion.util.SidedSlotHandler; import net.xevianlight.aphelion.util.SidedSlotHandler;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Optional;
public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvider { public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvider {
@@ -108,7 +103,7 @@ public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvide
public void tick(Level level, BlockPos pos, BlockState blockState) { public void tick(Level level, BlockPos pos, BlockState blockState) {
if (!blockState.getValue(ElectricArcFurnace.FORMED)) if (!blockState.getValue(AphelionBlockStateProperties.FORMED))
return; return;
chargeFromItem(); chargeFromItem();
@@ -316,6 +311,7 @@ public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvide
} }
private final IItemHandler fullHandler = new SidedSlotHandler(inventory, new int[]{INPUT_SLOT, SECONDARY_INPUT_SLOT, OUTPUT_SLOT, ENERGY_SLOT}, true, true); private final IItemHandler fullHandler = new SidedSlotHandler(inventory, new int[]{INPUT_SLOT, SECONDARY_INPUT_SLOT, OUTPUT_SLOT, ENERGY_SLOT}, true, true);
private final IItemHandler emptyJeiHandler = new SidedSlotHandler(inventory, new int[]{}, false, false);
private final IItemHandler inputHandler = new SidedSlotHandler(inventory, new int[]{0,1}, true, true); private final IItemHandler inputHandler = new SidedSlotHandler(inventory, new int[]{0,1}, true, true);
private final IItemHandler outputHandler = new SidedSlotHandler(inventory, new int[]{2,3}, false, true); private final IItemHandler outputHandler = new SidedSlotHandler(inventory, new int[]{2,3}, false, true);
private final IItemHandler jadeHandler = new SidedSlotHandler(inventory, new int[]{0}, false, false); private final IItemHandler jadeHandler = new SidedSlotHandler(inventory, new int[]{0}, false, false);
@@ -325,13 +321,18 @@ public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvide
} }
public IEnergyStorage getEnergyStorage(@Nullable Direction direction) { public IEnergyStorage getEnergyStorage(@Nullable Direction direction) {
return ENERGY_STORAGE;
}
public IEnergyStorage getTrueEnergyStorage(@Nullable Direction direction) {
return this.ENERGY_STORAGE; return this.ENERGY_STORAGE;
} }
private final ModEnergyStorage ENERGY_STORAGE = createEnergyStorage(); private final ModEnergyStorage ENERGY_STORAGE = createEnergyStorage(ENERGY_CAPACITY, MAX_TRANSFER);
private final ModEnergyStorage NULL_ENERGY_STORAGE = createEnergyStorage(0, 0);
private ModEnergyStorage createEnergyStorage() { private ModEnergyStorage createEnergyStorage(int capacity, int transfer) {
return new ModEnergyStorage(ENERGY_CAPACITY, MAX_TRANSFER) { return new ModEnergyStorage(capacity, transfer) {
@Override @Override
public void onEnergyChanged() { public void onEnergyChanged() {
setChanged(); setChanged();
@@ -403,132 +404,8 @@ public class ElectricArcFurnaceEntity extends BlockEntity implements MenuProvide
}; };
} }
public static final MultiblockHelper.ShapePart[] SHAPE = new MultiblockHelper.ShapePart[] {
new MultiblockHelper.ShapePart(new BlockPos(3,0,3), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
/// MULTIBLOCK // new MultiblockHelper.ShapePart(new BlockPos(-1,0,0), s -> s.is(Blocks.AMETHYST_BLOCK))
/// LOGIC
/// BELOW
private boolean formed = false; // cached runtime state
private static final BlockPos[] SHAPE = new BlockPos[] {
new BlockPos(1, 0, 0),
new BlockPos(0, 0, 1),
new BlockPos(1, 0, 1),
new BlockPos(0, 1, 0),
new BlockPos(1, 1, 0),
new BlockPos(0, 1, 1),
new BlockPos(1, 1, 1),
}; };
private List<BlockPos> getPartPositions() {
Direction facing = getBlockState().getValue(BlockStateProperties.HORIZONTAL_FACING);
BlockPos origin = getBlockPos();
List<BlockPos> out = new ArrayList<>(SHAPE.length);
for (BlockPos off : SHAPE) {
BlockPos ro = rotateY(off, facing);
out.add(origin.offset(ro));
}
return out;
}
private boolean structureMatches() {
if (level == null) return false;
for (BlockPos p : getPartPositions()) {
BlockState st = level.getBlockState(p);
// Accept only your casing/part blocks
if (!(st.getBlock() instanceof ArcFurnaceCasingBlock)) {
return false;
}
}
return true;
}
public boolean isFormed() {
return formed;
}
public void tryForm() {
if (level == null || level.isClientSide()) return;
if (!(getBlockState().getBlock() instanceof ElectricArcFurnace)) return; // don't form if not actually present
boolean valid = structureMatches();
if (valid && !formed) {
formed = true;
setFormedState(true);
linkParts();
} else if (!valid && formed) {
unform();
}
}
public void unform() {
if (level == null || level.isClientSide()) return;
formed = false;
setFormedState(false);
unlinkParts();
}
public void unformForRemoval() {
if (level == null || level.isClientSide()) return;
formed = false;
unlinkParts();
}
private void setFormedState(boolean value) {
BlockState state = getBlockState();
if (state.hasProperty(ElectricArcFurnace.FORMED) && state.getValue(ElectricArcFurnace.FORMED) != value) {
level.setBlock(worldPosition, state.setValue(ElectricArcFurnace.FORMED, value), 3);
}
}
private void linkParts() {
if (level == null || level.isClientSide()) return;
for (BlockPos p : getPartPositions()) {
BlockState st = level.getBlockState(p);
if (st.getBlock() instanceof ArcFurnaceCasingBlock && st.hasProperty(ArcFurnaceCasingBlock.FORMED)) {
if (!st.getValue(ArcFurnaceCasingBlock.FORMED)) {
level.setBlock(p, st.setValue(ArcFurnaceCasingBlock.FORMED, true), 3);
}
}
BlockEntity be = level.getBlockEntity(p);
if (be instanceof EAFPartEntity part) {
part.setControllerPos(worldPosition);
part.setChanged();
}
}
}
private void unlinkParts() {
if (level == null || level.isClientSide()) return;
for (BlockPos p : getPartPositions()) {
BlockState st = level.getBlockState(p);
if (st.getBlock() instanceof ArcFurnaceCasingBlock && st.hasProperty(ArcFurnaceCasingBlock.FORMED)) {
if (st.getValue(ArcFurnaceCasingBlock.FORMED)) {
level.setBlock(p, st.setValue(ArcFurnaceCasingBlock.FORMED, false), 3);
}
}
BlockEntity be = level.getBlockEntity(p);
if (be instanceof EAFPartEntity part && worldPosition.equals(part.getControllerPos())) {
part.setControllerPos(null);
part.setChanged();
}
}
}
} }

View File

@@ -0,0 +1,507 @@
package net.xevianlight.aphelion.block.entity.custom;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.world.Containers;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.BlastingRecipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.SingleRecipeInput;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.neoforged.neoforge.capabilities.Capabilities;
import net.neoforged.neoforge.energy.IEnergyStorage;
import net.neoforged.neoforge.items.IItemHandler;
import net.neoforged.neoforge.items.ItemStackHandler;
import net.xevianlight.aphelion.block.custom.ElectricArcFurnace;
import net.xevianlight.aphelion.block.entity.energy.ModEnergyStorage;
import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.core.init.ModBlocks;
import net.xevianlight.aphelion.recipe.ElectricArcFurnaceRecipe;
import net.xevianlight.aphelion.recipe.ElectricArcFurnaceRecipeInput;
import net.xevianlight.aphelion.recipe.ModRecipes;
import net.xevianlight.aphelion.screen.VacuumArcFurnaceMenu;
import net.xevianlight.aphelion.screen.ElectricArcFurnaceMenu;
import net.xevianlight.aphelion.util.AphelionBlockStateProperties;
import net.xevianlight.aphelion.util.IMultiblockController;
import net.xevianlight.aphelion.util.MultiblockHelper;
import net.xevianlight.aphelion.util.SidedSlotHandler;
import org.jetbrains.annotations.Nullable;
import java.util.Optional;
public class VacuumArcFurnaceControllerEntity extends BlockEntity implements MenuProvider, IMultiblockController {
private final int SIZE = 4;
private int ENERGY_CAPACITY = 64000;
private int MAX_TRANSFER = 320;
private int progress = 0;
private int maxProgress = 100;
private final int DEFAULT_MAX_PROGRESS = 100;
private final ContainerData data;
private int MACHINE_ENERGY_COST = 20;
public static final int INPUT_SLOT = 0;
public static final int SECONDARY_INPUT_SLOT = 1;
public static final int OUTPUT_SLOT = 2;
public static final int ENERGY_SLOT = 3;
public VacuumArcFurnaceControllerEntity(BlockPos pos, BlockState blockState) {
super(ModBlockEntities.VACUUM_ARC_FURNACE_ENTITY.get(), pos, blockState);
this.data = new ContainerData() {
@Override
public int get(int index) {
return switch (index) {
case 0 -> VacuumArcFurnaceControllerEntity.this.progress;
case 1 -> VacuumArcFurnaceControllerEntity.this.maxProgress;
default -> 0;
};
}
@Override
public void set(int index, int pValue) {
switch (index) {
case 0: VacuumArcFurnaceControllerEntity.this.progress = pValue;
case 1: VacuumArcFurnaceControllerEntity.this.maxProgress = pValue;
}
}
@Override
public int getCount() {
return 2;
}
};
}
public final ItemStackHandler inventory = new ItemStackHandler(SIZE) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
if(!level.isClientSide()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
}
// @Override
// public boolean isItemValid(int slot, ItemStack stack) {
// if (slot == ENERGY_SLOT) {
// var capability = stack.getCapability(Capabilities.EnergyStorage.ITEM);
// return capability != null;
// }
// return super.isItemValid(slot, stack);
// }
};
public void tick(Level level, BlockPos pos, BlockState blockState) {
if (!blockState.getValue(AphelionBlockStateProperties.FORMED))
return;
chargeFromItem();
if (inventory.getStackInSlot(SECONDARY_INPUT_SLOT).isEmpty()) {
// Secondary slot is empty, try furnace recipes
if (hasFurnaceRecipe(INPUT_SLOT) && hasEnoughEnergyToCraft(MACHINE_ENERGY_COST)) {
// Recipe detected! We have enough energy to process
progress++;
useEnergy();
level.setBlockAndUpdate(pos, blockState.setValue(ElectricArcFurnace.LIT, true));
setChanged(level, pos, blockState);
if (hasCraftingFinished()) {
outputBlastingResult(INPUT_SLOT, OUTPUT_SLOT);
resetProgress();
}
} else if (hasFurnaceRecipe(INPUT_SLOT) && !hasEnoughEnergyToCraft(MACHINE_ENERGY_COST)) {
// Recipe detected but we ran out of power
level.setBlockAndUpdate(pos, blockState.setValue(ElectricArcFurnace.LIT, false));
setChanged(level, pos, blockState);
progress = progress > 0 ? progress - 1 : 0;
} else {
// Invalid recipe
resetProgress();
level.setBlockAndUpdate(pos, blockState.setValue(ElectricArcFurnace.LIT, false));
setChanged(level, pos, blockState);
}
} else {
// Secondary slot is NOT empty, try alloying recipes
if (hasAlloyingRecipe(INPUT_SLOT, SECONDARY_INPUT_SLOT)) {
if (hasEnoughEnergyToCraft(MACHINE_ENERGY_COST)) {
// Alloy recipe detected! We have enough energy to process
progress++;
useEnergy();
level.setBlockAndUpdate(pos, blockState.setValue(ElectricArcFurnace.LIT, true));
setChanged(level, pos, blockState);
if (hasCraftingFinished()) {
outputAlloyingResult(INPUT_SLOT, SECONDARY_INPUT_SLOT, OUTPUT_SLOT);
resetProgress();
}
} else {
// Recipe detected but we ran out of power
level.setBlockAndUpdate(pos, blockState.setValue(ElectricArcFurnace.LIT, false));
setChanged(level, pos, blockState);
progress = progress > 0 ? progress - 1 : 0;
}
} else {
// Invalid recipe
resetProgress();
level.setBlockAndUpdate(pos, blockState.setValue(ElectricArcFurnace.LIT, false));
setChanged(level, pos, blockState);
}
}
}
private void chargeFromItem() {
ItemStack stack;
try {
stack = inventory.getStackInSlot(ENERGY_SLOT);
if (stack.isEmpty()) return;
IEnergyStorage itemEnergy = stack.getCapability(Capabilities.EnergyStorage.ITEM);
if (itemEnergy == null || !itemEnergy.canExtract()) return;
int freeCapacity = ENERGY_STORAGE.getMaxEnergyStored() - ENERGY_STORAGE.getEnergyStored();
if (freeCapacity <= 0) return;
int maxMove = Math.min(MAX_TRANSFER, freeCapacity);
// Simulate extraction first
int canExtract = itemEnergy.extractEnergy(maxMove, true);
if (canExtract <= 0) return;
// Receive into block (simulate then execute is safest)
int canReceive = ENERGY_STORAGE.receiveEnergy(canExtract, true);
if (canReceive <= 0) return;
int extracted = itemEnergy.extractEnergy(canReceive, false);
ENERGY_STORAGE.receiveEnergy(maxMove, false);
setChanged();
} catch (Exception e) {
}
}
private void outputBlastingResult(int slot, int resultSlot) {
Optional<RecipeHolder<BlastingRecipe>> recipe = getFurnaceRecipe(inventory.getStackInSlot(slot));
ItemStack output = recipe.get().value().getResultItem(null);
// 2x multiplier for smelting recipes
inventory.extractItem(slot, 1, false);
inventory.setStackInSlot(resultSlot, new ItemStack(output.getItem(),
inventory.getStackInSlot(resultSlot).getCount() + (output.getCount() * 2)));
}
private void outputAlloyingResult(int inputSlot, int secondaryInputSlot, int outputSlot) {
Optional<RecipeHolder<ElectricArcFurnaceRecipe>> recipe = getAlloyingRecipe(inventory.getStackInSlot(inputSlot), inventory.getStackInSlot(secondaryInputSlot));
ItemStack output = recipe.get().value().getResultItem(null);
inventory.extractItem(inputSlot, recipe.get().value().baseCount(), false);
inventory.extractItem(secondaryInputSlot, recipe.get().value().alloyCount(), false);
inventory.setStackInSlot(outputSlot, new ItemStack(output.getItem(), inventory.getStackInSlot(outputSlot).getCount() + (output.getCount())));
}
private void resetProgress() {
this.progress = 0;
this.maxProgress = DEFAULT_MAX_PROGRESS;
}
private void useEnergy() {
this.ENERGY_STORAGE.extractEnergy(MACHINE_ENERGY_COST, false);
}
private boolean hasEnoughEnergyToCraft(int energyCost) {
return ENERGY_STORAGE.getEnergyStored() >= energyCost;
}
private boolean canInsertItemIntoOutputSlot(ItemStack output, int slot) {
return inventory.getStackInSlot(slot).isEmpty() ||
inventory.getStackInSlot(slot).getItem() == output.getItem();
}
private boolean canInsertAmountIntoOutputSlot(int count, int slot) {
int maxCount = inventory.getStackInSlot(slot).isEmpty() ? 64 : inventory.getStackInSlot(slot).getMaxStackSize();
int currentCount = inventory.getStackInSlot(slot).getCount();
return maxCount >= currentCount + count;
}
private boolean isOutputSlotEmptyOrReceivable(int slot) {
return this.inventory.getStackInSlot(slot).isEmpty() ||
this.inventory.getStackInSlot(slot).getCount() < this.inventory.getStackInSlot(slot).getMaxStackSize();
}
private boolean hasCraftingFinished() {
maxProgress = DEFAULT_MAX_PROGRESS;
return this.progress >= this.maxProgress;
}
private boolean hasAlloyingRecipe(int slotBase, int slotAlloy) {
ItemStack baseStack = inventory.getStackInSlot(slotBase);
ItemStack alloyStack = inventory.getStackInSlot(slotAlloy);
Optional<RecipeHolder<ElectricArcFurnaceRecipe>> opt =
getAlloyingRecipe(baseStack, alloyStack);
if (opt.isEmpty()) return false;
ElectricArcFurnaceRecipe recipe = opt.get().value();
// 1) Check required input counts
if (baseStack.getCount() < recipe.baseCount()) return false;
if (alloyStack.getCount() < recipe.alloyCount()) return false;
// 2) Check output slot compatibility + space
ItemStack output = recipe.getResultItem(null);
maxProgress = recipe.cookTime();
return canInsertItemIntoOutputSlot(output, OUTPUT_SLOT)
&& canInsertAmountIntoOutputSlot(output.getCount(), OUTPUT_SLOT);
}
private Optional<RecipeHolder<ElectricArcFurnaceRecipe>> getAlloyingRecipe(ItemStack base, ItemStack alloy) {
if (base.isEmpty()) return Optional.empty();
if (alloy.isEmpty()) return Optional.empty();
return this.level.getRecipeManager()
.getRecipeFor(
ModRecipes.ELECTRIC_ARC_FURNACE_RECIPE_TYPE.get(),
new ElectricArcFurnaceRecipeInput(base, alloy),
level
);
}
private boolean hasFurnaceRecipe(int slot) {
Optional<RecipeHolder<BlastingRecipe>> recipe = getFurnaceRecipe(new ItemStack(inventory.getStackInSlot(slot).getItem().asItem(), 1));
if (recipe.isEmpty())
return false;
ItemStack output = recipe.get().value().getResultItem(null);
return canInsertAmountIntoOutputSlot(output.getCount() * 2, OUTPUT_SLOT) && canInsertItemIntoOutputSlot(output, OUTPUT_SLOT);
}
private Optional<RecipeHolder<BlastingRecipe>> getFurnaceRecipe(ItemStack stack) {
if (stack.isEmpty()) return Optional.empty();
return this.level.getRecipeManager()
.getRecipeFor(RecipeType.BLASTING, new SingleRecipeInput(stack), level);
}
public void sendUpdate() {
setChanged();
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
private final IItemHandler fullHandler = new SidedSlotHandler(inventory, new int[]{INPUT_SLOT, SECONDARY_INPUT_SLOT, OUTPUT_SLOT, ENERGY_SLOT}, true, true);
private final IItemHandler emptyJeiHandler = new SidedSlotHandler(inventory, new int[]{}, false, false);
private final IItemHandler inputHandler = new SidedSlotHandler(inventory, new int[]{0,1}, true, true);
private final IItemHandler outputHandler = new SidedSlotHandler(inventory, new int[]{2,3}, false, true);
private final IItemHandler jadeHandler = new SidedSlotHandler(inventory, new int[]{0}, false, false);
public IItemHandler getItemHandler(Direction direction) {
if (direction != null)
return isFormed() ? fullHandler : null;
return isFormed() ? fullHandler : emptyJeiHandler;
}
public IEnergyStorage getEnergyStorage(@Nullable Direction direction) {
if (direction == null)
return isFormed() ? ENERGY_STORAGE : NULL_ENERGY_STORAGE;
return isFormed() ? ENERGY_STORAGE : null;
}
public IEnergyStorage getTrueEnergyStorage(@Nullable Direction direction) {
return this.ENERGY_STORAGE;
}
private final ModEnergyStorage ENERGY_STORAGE = createEnergyStorage(ENERGY_CAPACITY, MAX_TRANSFER);
private final ModEnergyStorage NULL_ENERGY_STORAGE = createEnergyStorage(0, 0);
private ModEnergyStorage createEnergyStorage(int capacity, int transfer) {
return new ModEnergyStorage(capacity, transfer) {
@Override
public void onEnergyChanged() {
setChanged();
getLevel().sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 3);
}
};
}
public ItemStackHandler getInventory() {
return inventory;
}
public void drops() {
SimpleContainer inv = new SimpleContainer(inventory.getSlots());
for(int i = 0; i < inventory.getSlots(); i++) {
inv.setItem(i, inventory.getStackInSlot(i));
}
Containers.dropContents(this.level, this.worldPosition, inv);
}
@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider pRegistries) {
tag.put("inventory", inventory.serializeNBT(pRegistries));
tag.putInt("electric_arc_furnace.progress", progress);
tag.putInt("electric_arc_furnace.maxProgress", maxProgress);
tag.putInt("electric_arc_furnace.energy", ENERGY_STORAGE.getEnergyStored());
super.saveAdditional(tag, pRegistries);
}
@Override
protected void loadAdditional(CompoundTag tag, HolderLookup.Provider pRegistries) {
super.loadAdditional(tag, pRegistries);
inventory.deserializeNBT(pRegistries, tag.getCompound("inventory"));
progress = tag.getInt("electric_arc_furnace.progress");
maxProgress = tag.getInt("electric_arc_furnace.maxProgress");
ENERGY_STORAGE.setEnergy(tag.getInt("electric_arc_furnace.energy"));
}
@Override
public Component getDisplayName() {
return null;
}
@Override
public @Nullable AbstractContainerMenu createMenu(int i, Inventory inventory, Player player) {
if (isFormed())
return new VacuumArcFurnaceMenu(i, inventory, this, this.data);
return new ElectricArcFurnaceMenu(i, inventory, this, this.data);
}
@Nullable
@Override
public Packet<ClientGamePacketListener> getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider pRegistries) {
return saveWithoutMetadata(pRegistries);
}
private static BlockPos rotateY(BlockPos off, Direction facing) {
// Assumes "default" shape faces NORTH.
return switch (facing) {
case NORTH -> off;
case EAST -> new BlockPos(-off.getZ(), off.getY(), off.getX());
case SOUTH -> new BlockPos(-off.getX(), off.getY(), -off.getZ());
case WEST -> new BlockPos(off.getZ(), off.getY(), -off.getX());
default -> off;
};
}
public static final MultiblockHelper.ShapePart[] SHAPE = new MultiblockHelper.ShapePart[] {
//Layer -1
new MultiblockHelper.ShapePart(new BlockPos(1,-1,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(1,-1,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(1,-1,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,-1,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,-1,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,-1,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,-1,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,-1,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,-1,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
//Layer 0
new MultiblockHelper.ShapePart(new BlockPos(1,0,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(1,0,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(1,0,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,0,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,0,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,0,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,0,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,0,1), s -> s.is(Blocks.AIR)),
//Layer 1
new MultiblockHelper.ShapePart(new BlockPos(1,1,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(1,1,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(1,1,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,1,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,1,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(-1,1,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,1,0), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,1,1), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
new MultiblockHelper.ShapePart(new BlockPos(0,1,2), s -> s.is(ModBlocks.ARC_FURNACE_CASING_BLOCK)),
// new MultiblockHelper.ShapePart(new BlockPos(-1,0,0), s -> s.is(Blocks.AMETHYST_BLOCK))
};
/// MULTIBLOCK
/// LOGIC
/// BELOW
// record ShapePart (BlockPos offset, Predicate<BlockState> rule) {}
private boolean formed = false; // cached runtime state
// Assumes the default state is NORTH.
// (Left -Right, Up -Down, Back -Front)
// private static final BlockPos[] SHAPE = new BlockPos[] {
// new BlockPos(1, 0, 0),
// new BlockPos(0, 0, 1),
// new BlockPos(1, 0, 1),
//
// new BlockPos(0, 1, 0),
// new BlockPos(1, 1, 0),
// new BlockPos(0, 1, 1),
// new BlockPos(1, 1, 1),
// };
public boolean isFormed() {
return getBlockState().hasProperty(AphelionBlockStateProperties.FORMED)
&& getBlockState().getValue(AphelionBlockStateProperties.FORMED);
}
@Override
public void setFormed(boolean formed) {
this.formed = formed;
invalidateCapabilities();
if (!formed) {
drops();
}
}
private void setFormedState(boolean value) {
BlockState state = getBlockState();
if (state.hasProperty(ElectricArcFurnace.FORMED) && state.getValue(ElectricArcFurnace.FORMED) != value) {
level.setBlock(worldPosition, state.setValue(ElectricArcFurnace.FORMED, value), 3);
}
}
}

View File

@@ -4,10 +4,7 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.neoforged.neoforge.registries.DeferredRegister; import net.neoforged.neoforge.registries.DeferredRegister;
import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.block.entity.custom.DimensionChangerBlockEntity; import net.xevianlight.aphelion.block.entity.custom.*;
import net.xevianlight.aphelion.block.entity.custom.EAFPartEntity;
import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity;
import java.util.function.Supplier; import java.util.function.Supplier;
@@ -33,4 +30,9 @@ public class ModBlockEntities {
BLOCK_ENTITIES.register("eaf_part_entity", () -> BlockEntityType.Builder.of( BLOCK_ENTITIES.register("eaf_part_entity", () -> BlockEntityType.Builder.of(
EAFPartEntity::new, ModBlocks.ARC_FURNACE_CASING_BLOCK.get()).build(null) EAFPartEntity::new, ModBlocks.ARC_FURNACE_CASING_BLOCK.get()).build(null)
); );
public static final Supplier<BlockEntityType<VacuumArcFurnaceControllerEntity>> VACUUM_ARC_FURNACE_ENTITY =
BLOCK_ENTITIES.register("vacuum_arc_furnace_controller_entity", () -> BlockEntityType.Builder.of(
VacuumArcFurnaceControllerEntity::new, ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER.get()).build(null)
);
} }

View File

@@ -14,4 +14,5 @@ public class ModBlocks {
public static final DeferredBlock<Block> DIMENSION_CHANGER = BLOCKS.register("dimension_changer", () -> new DimensionChangerBlock(DimensionChangerBlock.getProperties())); public static final DeferredBlock<Block> DIMENSION_CHANGER = BLOCKS.register("dimension_changer", () -> new DimensionChangerBlock(DimensionChangerBlock.getProperties()));
public static final DeferredBlock<Block> ELECTRIC_ARC_FURNACE = BLOCKS.register("electric_arc_furnace", () -> new ElectricArcFurnace(ElectricArcFurnace.getProperties())); public static final DeferredBlock<Block> ELECTRIC_ARC_FURNACE = BLOCKS.register("electric_arc_furnace", () -> new ElectricArcFurnace(ElectricArcFurnace.getProperties()));
public static final DeferredBlock<Block> ARC_FURNACE_CASING_BLOCK = BLOCKS.register("arc_furnace_casing", () -> new ArcFurnaceCasingBlock(ArcFurnaceCasingBlock.getProperties())); public static final DeferredBlock<Block> ARC_FURNACE_CASING_BLOCK = BLOCKS.register("arc_furnace_casing", () -> new ArcFurnaceCasingBlock(ArcFurnaceCasingBlock.getProperties()));
public static final DeferredBlock<Block> VACUUM_ARC_FURNACE_CONTROLLER = BLOCKS.register("vacuum_arc_furnace_controller", () -> new VacuumArcFurnaceController(VacuumArcFurnaceController.getProperties()));
} }

View File

@@ -33,4 +33,5 @@ public static final DeferredItem<Item> MUSIC_DISC_BIT_SHIFT = ITEMS.register("mu
public static final DeferredItem<BlockItem> ELECTRIC_ARC_FURNACE = ITEMS.register("electric_arc_furnace", () -> new BlockItem(ModBlocks.ELECTRIC_ARC_FURNACE.get(), ElectricArcFurnace.getItemProperties())); public static final DeferredItem<BlockItem> ELECTRIC_ARC_FURNACE = ITEMS.register("electric_arc_furnace", () -> new BlockItem(ModBlocks.ELECTRIC_ARC_FURNACE.get(), ElectricArcFurnace.getItemProperties()));
public static final DeferredItem<BlockItem> BLOCK_STEEL = ITEMS.register("block_steel", () -> new BlockItem(ModBlocks.BLOCK_STEEL.get(), BlockSteel.getItemProperties())); public static final DeferredItem<BlockItem> BLOCK_STEEL = ITEMS.register("block_steel", () -> new BlockItem(ModBlocks.BLOCK_STEEL.get(), BlockSteel.getItemProperties()));
public static final DeferredItem<BlockItem> ARC_FURNACE_CASING_BLOCK = ITEMS.register("arc_furnace_casing", () -> new BlockItem(ModBlocks.ARC_FURNACE_CASING_BLOCK.get(), ArcFurnaceCasingBlock.getItemProperties())); public static final DeferredItem<BlockItem> ARC_FURNACE_CASING_BLOCK = ITEMS.register("arc_furnace_casing", () -> new BlockItem(ModBlocks.ARC_FURNACE_CASING_BLOCK.get(), ArcFurnaceCasingBlock.getItemProperties()));
public static final DeferredItem<BlockItem> VACUUM_ARC_FURNACE_CONTROLLER = ITEMS.register("vacuum_arc_furnace_controller", () -> new BlockItem(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER.get(), VacuumArcFurnaceController.getItemProperties()));
} }

View File

@@ -21,6 +21,7 @@ public class ModBlockLootTableProvider extends BlockLootSubProvider {
dropSelf(ModBlocks.DIMENSION_CHANGER.get()); dropSelf(ModBlocks.DIMENSION_CHANGER.get());
dropSelf(ModBlocks.ELECTRIC_ARC_FURNACE.get()); dropSelf(ModBlocks.ELECTRIC_ARC_FURNACE.get());
dropSelf(ModBlocks.ARC_FURNACE_CASING_BLOCK.get()); dropSelf(ModBlocks.ARC_FURNACE_CASING_BLOCK.get());
dropSelf(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER.get());
} }
@Override @Override

View File

@@ -18,11 +18,12 @@ public class ModBlockStateProvider extends BlockStateProvider {
protected void registerStatesAndModels() { protected void registerStatesAndModels() {
blockWithItem(ModBlocks.TEST_BLOCK); blockWithItem(ModBlocks.TEST_BLOCK);
// horizontalBlock(ModBlocks.ELECTRIC_ARC_FURNACE.get(), models().orientable("aphelion:electric_arc_furnace", horizontalBlock(ModBlocks.ELECTRIC_ARC_FURNACE.get(), models().orientable("aphelion:electric_arc_furnace",
// mcLoc("block/blast_furnace_side"), mcLoc("block/blast_furnace_side"),
// modLoc("block/electric_arc_furnace_front"), modLoc("block/electric_arc_furnace_front"),
// mcLoc("block/blast_furnace_top"))); mcLoc("block/blast_furnace_top")));
blockItem(ModBlocks.ELECTRIC_ARC_FURNACE); blockItem(ModBlocks.ELECTRIC_ARC_FURNACE);
blockItem(ModBlocks.VACUUM_ARC_FURNACE_CONTROLLER);
blockWithItem(ModBlocks.BLOCK_STEEL); blockWithItem(ModBlocks.BLOCK_STEEL);
blockWithItem(ModBlocks.DIMENSION_CHANGER); blockWithItem(ModBlocks.DIMENSION_CHANGER);

View File

@@ -11,6 +11,7 @@ import net.neoforged.neoforge.network.registration.PayloadRegistrar;
import net.xevianlight.aphelion.Aphelion; import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity; import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity; import net.xevianlight.aphelion.block.entity.custom.TestBlockEntity;
import net.xevianlight.aphelion.block.entity.custom.VacuumArcFurnaceControllerEntity;
import net.xevianlight.aphelion.core.init.ModBlockEntities; import net.xevianlight.aphelion.core.init.ModBlockEntities;
import net.xevianlight.aphelion.network.ServerPayloadHandler; import net.xevianlight.aphelion.network.ServerPayloadHandler;
import net.xevianlight.aphelion.network.packet.PartitionData; import net.xevianlight.aphelion.network.packet.PartitionData;
@@ -22,6 +23,8 @@ public class ModBusEvents {
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.TEST_BLOCK_ENTITY.get(), TestBlockEntity::getItemHandler); event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.TEST_BLOCK_ENTITY.get(), TestBlockEntity::getItemHandler);
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.ELECTRIC_ARC_FURNACE_ENTITY.get(), ElectricArcFurnaceEntity::getItemHandler); event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.ELECTRIC_ARC_FURNACE_ENTITY.get(), ElectricArcFurnaceEntity::getItemHandler);
event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.ELECTRIC_ARC_FURNACE_ENTITY.get(), ElectricArcFurnaceEntity::getEnergyStorage); event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.ELECTRIC_ARC_FURNACE_ENTITY.get(), ElectricArcFurnaceEntity::getEnergyStorage);
event.registerBlockEntity(Capabilities.ItemHandler.BLOCK, ModBlockEntities.VACUUM_ARC_FURNACE_ENTITY.get(), VacuumArcFurnaceControllerEntity::getItemHandler);
event.registerBlockEntity(Capabilities.EnergyStorage.BLOCK, ModBlockEntities.VACUUM_ARC_FURNACE_ENTITY.get(), VacuumArcFurnaceControllerEntity::getEnergyStorage);
} }
@SubscribeEvent @SubscribeEvent

View File

@@ -1,9 +1,6 @@
package net.xevianlight.aphelion.screen; package net.xevianlight.aphelion.screen;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -14,7 +11,6 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import net.neoforged.neoforge.items.SlotItemHandler; import net.neoforged.neoforge.items.SlotItemHandler;
import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity; import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
import net.xevianlight.aphelion.util.EnergyItemSlot; import net.xevianlight.aphelion.util.EnergyItemSlot;
import net.xevianlight.aphelion.util.ExtractOnlySlot; import net.xevianlight.aphelion.util.ExtractOnlySlot;

View File

@@ -62,8 +62,8 @@ public class ElectricArcFurnaceScreen extends AbstractContainerScreen<ElectricAr
} }
private void renderEnergyBar(GuiGraphics guiGraphics, int x, int y) { private void renderEnergyBar(GuiGraphics guiGraphics, int x, int y) {
int stored = menu.blockEntity.getEnergyStorage(null).getEnergyStored(); int stored = menu.blockEntity.getTrueEnergyStorage(null).getEnergyStored();
int max = menu.blockEntity.getEnergyStorage(null).getMaxEnergyStored(); int max = menu.blockEntity.getTrueEnergyStorage(null).getMaxEnergyStored();
int h = (max <= 0) ? 0 : (int) Math.round((stored / (double) max) * 42.0); int h = (max <= 0) ? 0 : (int) Math.round((stored / (double) max) * 42.0);
h = Math.max(0, Math.min(42, h)); h = Math.max(0, Math.min(42, h));
@@ -79,7 +79,7 @@ public class ElectricArcFurnaceScreen extends AbstractContainerScreen<ElectricAr
private void assignEnergyInfoArea() { private void assignEnergyInfoArea() {
energyInfoArea = new EnergyDisplayTooltipArea(((width - imageWidth) / 2) + 9, energyInfoArea = new EnergyDisplayTooltipArea(((width - imageWidth) / 2) + 9,
((height - imageHeight) / 2 ) + 9, menu.blockEntity.getEnergyStorage(null), 14, 42); ((height - imageHeight) / 2 ) + 9, menu.blockEntity.getTrueEnergyStorage(null), 14, 42);
} }
private void renderEnergyAreaTooltip(GuiGraphics guiGraphics, int pMouseX, int pMouseY, int x, int y) { private void renderEnergyAreaTooltip(GuiGraphics guiGraphics, int pMouseX, int pMouseY, int x, int y) {

View File

@@ -16,9 +16,13 @@ public class ModMenuTypes {
public static DeferredHolder<MenuType<?>,MenuType<TestBlockMenu>> TEST_BLOCK_MENU = public static DeferredHolder<MenuType<?>,MenuType<TestBlockMenu>> TEST_BLOCK_MENU =
registerMenuType("test_block_menu", TestBlockMenu::new); registerMenuType("test_block_menu", TestBlockMenu::new);
public static DeferredHolder<MenuType<?>,MenuType<ElectricArcFurnaceMenu>> ELECTRIC_ARC_FURNACE_MENU = public static DeferredHolder<MenuType<?>,MenuType<ElectricArcFurnaceMenu>> ELECTRIC_ARC_FURNACE_MENU =
registerMenuType("electric_arc_furnace_menu", ElectricArcFurnaceMenu::new); registerMenuType("electric_arc_furnace_menu", ElectricArcFurnaceMenu::new);
public static DeferredHolder<MenuType<?>,MenuType<VacuumArcFurnaceMenu>> VACUUM_ARC_FURNACE_MENU =
registerMenuType("vacuum_arc_furnace_menu", VacuumArcFurnaceMenu::new);
private static <T extends AbstractContainerMenu>DeferredHolder<MenuType<?>, MenuType<T>> registerMenuType(String name, private static <T extends AbstractContainerMenu>DeferredHolder<MenuType<?>, MenuType<T>> registerMenuType(String name,
IContainerFactory<T> factory) { IContainerFactory<T> factory) {
return MENUS.register(name, () -> IMenuTypeExtension.create(factory)); return MENUS.register(name, () -> IMenuTypeExtension.create(factory));

View File

@@ -0,0 +1,129 @@
package net.xevianlight.aphelion.screen;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.inventory.SimpleContainerData;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.neoforged.neoforge.items.SlotItemHandler;
import net.xevianlight.aphelion.block.custom.VacuumArcFurnaceController;
import net.xevianlight.aphelion.block.entity.custom.ElectricArcFurnaceEntity;
import net.xevianlight.aphelion.block.entity.custom.VacuumArcFurnaceControllerEntity;
import net.xevianlight.aphelion.util.EnergyItemSlot;
import net.xevianlight.aphelion.util.ExtractOnlySlot;
import org.jetbrains.annotations.NotNull;
public class VacuumArcFurnaceMenu extends AbstractContainerMenu {
public final VacuumArcFurnaceControllerEntity blockEntity;
private final Level level;
private final ContainerData data;
public VacuumArcFurnaceMenu(int i, Inventory inventory, FriendlyByteBuf extraData) {
this(i, inventory, inventory.player.level().getBlockEntity(extraData.readBlockPos()), new SimpleContainerData(4));
}
public VacuumArcFurnaceMenu(int i, Inventory inventory, BlockEntity blockEntity, ContainerData data) {
super(ModMenuTypes.VACUUM_ARC_FURNACE_MENU.get(), i);
this.blockEntity = ((VacuumArcFurnaceControllerEntity) blockEntity);
this.level = inventory.player.level();
this.data = data;
addPlayerInventory(inventory);
addPlayerHotbar(inventory);
this.addSlot(new EnergyItemSlot(this.blockEntity.inventory, VacuumArcFurnaceControllerEntity.ENERGY_SLOT, 8, 54));
this.addSlot(new SlotItemHandler(this.blockEntity.inventory, VacuumArcFurnaceControllerEntity.INPUT_SLOT, 63, 35));
this.addSlot(new SlotItemHandler(this.blockEntity.inventory, VacuumArcFurnaceControllerEntity.SECONDARY_INPUT_SLOT, 40, 35));
this.addSlot(new ExtractOnlySlot(this.blockEntity.inventory, VacuumArcFurnaceControllerEntity.OUTPUT_SLOT, 125, 35));
addDataSlots(data);
}
@Override
public boolean stillValid(Player player) {
return true;
}
// CREDIT GOES TO: diesieben07 | https://github.com/diesieben07/SevenCommons
// must assign a slot number to each of the slots used by the GUI.
// For this container, we can see both the tile inventory's slots as well as the player inventory slots and the hotbar.
// Each time we add a Slot to the container, it automatically increases the slotIndex, which means
// 0 - 8 = hotbar slots (which will map to the InventoryPlayer slot numbers 0 - 8)
// 9 - 35 = player inventory slots (which map to the InventoryPlayer slot numbers 9 - 35)
// 36 - 44 = TileInventory slots, which map to our TileEntity slot numbers 0 - 8)
private static final int HOTBAR_SLOT_COUNT = 9;
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT;
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
private static final int VANILLA_FIRST_SLOT_INDEX = 0;
private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT;
// THIS YOU HAVE TO DEFINE!
private static final int TE_INVENTORY_SLOT_COUNT = 3; // must be the number of slots you have!
@Override
public @NotNull ItemStack quickMoveStack(Player playerIn, int pIndex) {
Slot sourceSlot = slots.get(pIndex);
if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEM
ItemStack sourceStack = sourceSlot.getItem();
ItemStack copyOfSourceStack = sourceStack.copy();
// Check if the slot clicked is one of the vanilla container slots
if (pIndex < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) {
// This is a vanilla container slot so merge the stack into the tile inventory
if (!moveItemStackTo(sourceStack, TE_INVENTORY_FIRST_SLOT_INDEX, TE_INVENTORY_FIRST_SLOT_INDEX
+ TE_INVENTORY_SLOT_COUNT, false)) {
blockEntity.sendUpdate();
return ItemStack.EMPTY; // EMPTY_ITEM
}
} else if (pIndex < TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
blockEntity.sendUpdate();
return ItemStack.EMPTY;
}
} else {
System.out.println("Invalid slotIndex:" + pIndex);
return ItemStack.EMPTY;
}
// If stack size == 0 (the entire stack was moved) set slot contents to null
if (sourceStack.getCount() == 0) {
sourceSlot.set(ItemStack.EMPTY);
blockEntity.sendUpdate();
} else {
blockEntity.sendUpdate();
sourceSlot.setChanged();
}
sourceSlot.onTake(playerIn, sourceStack);
blockEntity.sendUpdate();
return copyOfSourceStack;
}
public int getScaledArrowProgress() {
int progress = this.data.get(0);
int maxProgress = this.data.get(1);
int arrowPixelSize = 24;
return maxProgress != 0 && progress != 0 ? progress * arrowPixelSize / maxProgress : 0;
}
private void addPlayerInventory(Inventory playerInventory) {
for (int i = 0; i < 3; ++i) {
for (int l = 0; l < 9; ++l) {
this.addSlot(new Slot(playerInventory, l + i * 9 + 9, 8 + l * 18, 84 + i * 18));
}
}
}
private void addPlayerHotbar(Inventory playerInventory) {
for (int i = 0; i < 9; ++i) {
this.addSlot(new Slot(playerInventory, i, 8 + i * 18, 142));
}
}
}

View File

@@ -0,0 +1,111 @@
package net.xevianlight.aphelion.screen;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.xevianlight.aphelion.Aphelion;
import net.xevianlight.aphelion.screen.renderer.EnergyDisplayTooltipArea;
import net.xevianlight.aphelion.util.MouseUtil;
import java.util.Optional;
public class VacuumArcFurnaceScreen extends AbstractContainerScreen<VacuumArcFurnaceMenu> {
private static final ResourceLocation GUI_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Aphelion.MOD_ID, "textures/gui/vacuum_arc_furnace/gui.png");
private static final ResourceLocation ARROW_TEXTURE =
ResourceLocation.fromNamespaceAndPath(Aphelion.MOD_ID,"textures/gui/base/arrow_progress.png");
private EnergyDisplayTooltipArea energyInfoArea;
public VacuumArcFurnaceScreen(VacuumArcFurnaceMenu menu, Inventory playerInventory, Component title) {
super(menu, playerInventory, title);
}
@Override
protected void init() {
super.init();
// Gets rid of labels
this.inventoryLabelY = 73;
this.titleLabelY = 5;
this.titleLabelX = 35;
assignEnergyInfoArea();
}
@Override
protected void renderBg(GuiGraphics guiGraphics, float partialTick, int mouseX, int mouseY) {
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, GUI_TEXTURE);
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
guiGraphics.blit(GUI_TEXTURE, x, y, 0, 0, imageWidth, imageHeight);
renderProgressArrow(guiGraphics, x, y);
if (menu.blockEntity.getBlockState().getValue(BlockStateProperties.LIT)) {
guiGraphics.blit(GUI_TEXTURE, x + 54, y + 14, 176, 75, 13, 18);
}
renderEnergyBar(guiGraphics, x , y);
}
private void renderProgressArrow(GuiGraphics guiGraphics, int x, int y) {
guiGraphics.blit(ARROW_TEXTURE,x + 88, y + 35, 0, 0, menu.getScaledArrowProgress(), 16, 24, 16);
}
private void renderEnergyBar(GuiGraphics guiGraphics, int x, int y) {
int stored = menu.blockEntity.getTrueEnergyStorage(null).getEnergyStored();
int max = menu.blockEntity.getTrueEnergyStorage(null).getMaxEnergyStored();
int h = (max <= 0) ? 0 : (int) Math.round((stored / (double) max) * 42.0);
h = Math.max(0, Math.min(42, h));
int w = 14;
int drawX = x + 9;
int drawY = y + 9 + (42 - h); // move up as it fills
int u = 176;
int v = 15 + (42 - h); // sample lower part of bar texture
guiGraphics.blit(GUI_TEXTURE, drawX, drawY, u, v, w, h);
}
private void assignEnergyInfoArea() {
energyInfoArea = new EnergyDisplayTooltipArea(((width - imageWidth) / 2) + 9,
((height - imageHeight) / 2 ) + 9, menu.blockEntity.getTrueEnergyStorage(null), 14, 42);
}
private void renderEnergyAreaTooltip(GuiGraphics guiGraphics, int pMouseX, int pMouseY, int x, int y) {
if(isMouseAboveArea(pMouseX, pMouseY, x, y, 9, 9, 14, 42)) {
guiGraphics.renderTooltip(this.font, energyInfoArea.getTooltips(),
Optional.empty(), pMouseX - x, pMouseY - y);
}
}
@Override
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float delta) {
renderBackground(guiGraphics, mouseX, mouseY, delta);
super.render(guiGraphics, mouseX, mouseY, delta);
renderTooltip(guiGraphics, mouseX, mouseY);
}
@Override
protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) {
super.renderLabels(guiGraphics, mouseX, mouseY);
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
renderEnergyAreaTooltip(guiGraphics, mouseX, mouseY, x, y);
}
public static boolean isMouseAboveArea(int pMouseX, int pMouseY, int x, int y, int offsetX, int offsetY, int width, int height) {
return MouseUtil.isMouseOver(pMouseX, pMouseY, x + offsetX, y + offsetY, width, height);
}
}

View File

@@ -0,0 +1,8 @@
package net.xevianlight.aphelion.util;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
public class AphelionBlockStateProperties extends BlockStateProperties {
public static final BooleanProperty FORMED = BooleanProperty.create("formed");
}

View File

@@ -0,0 +1,9 @@
package net.xevianlight.aphelion.util;
import net.minecraft.core.BlockPos;
import org.jetbrains.annotations.Nullable;
public interface IMultiblockController {
boolean isFormed();
void setFormed(boolean formed);
}

View File

@@ -0,0 +1,10 @@
package net.xevianlight.aphelion.util;
import net.minecraft.core.BlockPos;
import org.jetbrains.annotations.Nullable;
public interface IMultiblockPart {
@Nullable BlockPos getControllerPos();
void setControllerPos(@Nullable BlockPos pos);
}

View File

@@ -0,0 +1,192 @@
package net.xevianlight.aphelion.util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.xevianlight.aphelion.Aphelion;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class MultiblockHelper {
public record ShapePart (BlockPos offset, Predicate<BlockState> rule) {}
public static List<BlockPos> getPartPositions(BlockState state, BlockPos pos, ShapePart[] shape) {
Direction facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING);
List<BlockPos> out = new ArrayList<>(shape.length);
for (ShapePart part : shape) {
BlockPos rotate = rotateY(part.offset, facing);
out.add(pos.offset(rotate));
}
return out;
}
private static BlockPos rotateY(BlockPos offset, Direction facing) {
// Assumes default shape faces north
return switch (facing) {
case NORTH -> offset;
case EAST -> new BlockPos(-offset.getZ(), offset.getY(), offset.getX());
case SOUTH -> new BlockPos(-offset.getX(), offset.getY(), -offset.getZ());
case WEST -> new BlockPos(offset.getZ(), offset.getY(), -offset.getX());
default -> offset;
};
}
private static boolean structureMatches(Level level, BlockState state, BlockPos pos, ShapePart[] shape) {
if (level == null || level.isClientSide) return false;
Direction facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING);
for (ShapePart part : shape) {
BlockPos testPos = pos.offset(rotateY(part.offset(), facing));
BlockState check = level.getBlockState(testPos);
if (!part.rule().test(check)) {
return false;
}
}
return true;
}
public static void tryForm(Level level, BlockState state, BlockPos pos, ShapePart[] shape, @Nullable BooleanProperty formedProp) {
if (level == null || level.isClientSide) return;
structureMatchesDebug(level, state, pos, shape);
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof IMultiblockController controller)) return;
boolean valid = structureMatches(level, state, pos, shape);
if (valid && !controller.isFormed()) {
controller.setFormed(true);
linkParts(level, state, pos, shape, formedProp);
if (state.hasProperty(AphelionBlockStateProperties.FORMED) && !state.getValue(AphelionBlockStateProperties.FORMED)) {
level.setBlock(pos, state.setValue(AphelionBlockStateProperties.FORMED, true), 3);
}
} else if (!valid && controller.isFormed()) {
unform(level, state, pos, shape, formedProp);
}
}
public static void unform(Level level, BlockState state, BlockPos pos, ShapePart[] shape, @Nullable BooleanProperty formedProp) {
if (level == null || level.isClientSide) return;
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof IMultiblockController controller)) return;
controller.setFormed(false);
if (state.hasProperty(AphelionBlockStateProperties.FORMED) && state.getValue(AphelionBlockStateProperties.FORMED)) {
level.setBlock(pos, state.setValue(AphelionBlockStateProperties.FORMED, false), 3);
}
unlinkParts(level, state, pos, shape, formedProp);
}
public static void unformForRemoval(Level level, BlockState state, BlockPos pos, ShapePart[] shape, @Nullable BooleanProperty formedProp) {
if (level == null || level.isClientSide) return;
BlockEntity be = level.getBlockEntity(pos);
if (!(be instanceof IMultiblockController controller)) return;
controller.setFormed(false);
unlinkParts(level, state, pos, shape, formedProp);
}
private static void unlinkParts(Level level, BlockState state, BlockPos pos, ShapePart[] shape, @Nullable BooleanProperty formedProp) {
if (level == null || level.isClientSide) return;
Direction facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING);
for (ShapePart part : shape) {
BlockPos partPos = pos.offset(rotateY(part.offset(), facing));
BlockState st = level.getBlockState(partPos);
if (formedProp != null && st.hasProperty(formedProp) && st.getValue(formedProp)) {
level.setBlock(partPos, st.setValue(formedProp, false), 3);
}
BlockEntity be = level.getBlockEntity(partPos);
if (be instanceof IMultiblockPart mbPart) {
if (pos.equals(mbPart.getControllerPos())) {
mbPart.setControllerPos(null);
be.setChanged();
}
}
}
}
private static void linkParts(Level level, BlockState state, BlockPos pos, ShapePart[] shape, @Nullable BooleanProperty formedProp) {
if (level == null || level.isClientSide) return;
Direction facing = state.getValue(BlockStateProperties.HORIZONTAL_FACING);
for (ShapePart part : shape) {
BlockPos partPos = pos.offset(rotateY(part.offset(), facing));
BlockState st = level.getBlockState(partPos);
Aphelion.LOGGER.debug("[Multiblock] partPos={} block={} hasFormed={} formedVal={}",
partPos,
st.getBlock(),
(formedProp != null && st.hasProperty(formedProp)),
(formedProp != null && st.hasProperty(formedProp)) ? st.getValue(formedProp) : "n/a"
);
if (formedProp != null && st.hasProperty(formedProp) && !st.getValue(formedProp)) {
level.setBlock(partPos, st.setValue(formedProp, true), 3);
st = level.getBlockState(partPos);
}
BlockEntity be = level.getBlockEntity(partPos);
if (be instanceof IMultiblockPart mbPart) {
if (!pos.equals(mbPart.getControllerPos())) {
mbPart.setControllerPos(pos);
be.setChanged();
}
}
}
}
public static boolean structureMatchesDebug(
Level level,
BlockState controllerState,
BlockPos controllerPos,
ShapePart[] shape
) {
Direction facing = controllerState.getValue(BlockStateProperties.HORIZONTAL_FACING);
for (ShapePart part : shape) {
BlockPos rotated = rotateY(part.offset(), facing);
BlockPos worldPos = controllerPos.offset(rotated);
BlockState found = level.getBlockState(worldPos);
if (!part.rule().test(found)) {
Aphelion.LOGGER.debug("[Multiblock] FAIL at offset=" + part.offset()
+ " facing=" + facing
+ " rotated=" + rotated
+ " worldPos=" + worldPos
+ " found=" + found.getBlock());
return false;
}
}
Aphelion.LOGGER.debug("[Multiblock] OK facing={} controllerPos={}", controllerState.getValue(BlockStateProperties.HORIZONTAL_FACING), controllerPos);
return true;
}
}

View File

@@ -1,64 +0,0 @@
{
"variants": {
"facing=east,formed=false,lit=false": {
"model": "aphelion:block/electric_arc_furnace",
"y": 90
},
"facing=east,formed=false,lit=true": {
"model": "aphelion:block/electric_arc_furnace",
"y": 90
},
"facing=east,formed=true,lit=false": {
"model": "aphelion:block/electric_arc_furnace_formed",
"y": 90
},
"facing=east,formed=true,lit=true": {
"model": "aphelion:block/electric_arc_furnace_formed",
"y": 90
},
"facing=north,formed=false,lit=false": {
"model": "aphelion:block/electric_arc_furnace"
},
"facing=north,formed=false,lit=true": {
"model": "aphelion:block/electric_arc_furnace"
},
"facing=north,formed=true,lit=false": {
"model": "aphelion:block/electric_arc_furnace_formed"
},
"facing=north,formed=true,lit=true": {
"model": "aphelion:block/electric_arc_furnace_formed"
},
"facing=south,formed=false,lit=false": {
"model": "aphelion:block/electric_arc_furnace",
"y": 180
},
"facing=south,formed=false,lit=true": {
"model": "aphelion:block/electric_arc_furnace",
"y": 180
},
"facing=south,formed=true,lit=false": {
"model": "aphelion:block/electric_arc_furnace_formed",
"y": 180
},
"facing=south,formed=true,lit=true": {
"model": "aphelion:block/electric_arc_furnace_formed",
"y": 180
},
"facing=west,formed=false,lit=false": {
"model": "aphelion:block/electric_arc_furnace",
"y": 270
},
"facing=west,formed=false,lit=true": {
"model": "aphelion:block/electric_arc_furnace",
"y": 270
},
"facing=west,formed=true,lit=false": {
"model": "aphelion:block/electric_arc_furnace_formed",
"y": 270
},
"facing=west,formed=true,lit=true": {
"model": "aphelion:block/electric_arc_furnace_formed",
"y": 270
}
}
}

View File

@@ -0,0 +1,64 @@
{
"variants": {
"facing=east,formed=false,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller",
"y": 90
},
"facing=east,formed=false,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller",
"y": 90
},
"facing=east,formed=true,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed",
"y": 90
},
"facing=east,formed=true,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed",
"y": 90
},
"facing=north,formed=false,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller"
},
"facing=north,formed=false,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller"
},
"facing=north,formed=true,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed"
},
"facing=north,formed=true,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed"
},
"facing=south,formed=false,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller",
"y": 180
},
"facing=south,formed=false,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller",
"y": 180
},
"facing=south,formed=true,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed",
"y": 180
},
"facing=south,formed=true,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed",
"y": 180
},
"facing=west,formed=false,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller",
"y": 270
},
"facing=west,formed=false,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller",
"y": 270
},
"facing=west,formed=true,lit=false": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed",
"y": 270
},
"facing=west,formed=true,lit=true": {
"model": "aphelion:block/vacuum_arc_furnace_controller_formed",
"y": 270
}
}
}

View File

@@ -1,7 +1,7 @@
{ {
"parent": "minecraft:block/orientable", "parent": "minecraft:block/orientable",
"textures": { "textures": {
"front": "aphelion:block/electric_arc_furnace_front", "front": "aphelion:block/vacuum_arc_furnace_controller_front",
"side": "minecraft:block/blast_furnace_side", "side": "minecraft:block/blast_furnace_side",
"top": "minecraft:block/blast_furnace_top" "top": "minecraft:block/blast_furnace_top"
} }

View File

@@ -1,7 +1,7 @@
{ {
"parent": "minecraft:block/orientable", "parent": "minecraft:block/orientable",
"textures": { "textures": {
"front": "aphelion:block/electric_arc_furnace_front_formed", "front": "aphelion:block/vacuum_arc_furnace_controller_front_formed",
"side": "minecraft:block/blast_furnace_side", "side": "minecraft:block/blast_furnace_side",
"top": "minecraft:block/blast_furnace_top" "top": "minecraft:block/blast_furnace_top"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB