mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-07-01 01:23:30 +00:00
Post multi-loader cleanup
This commit got away from me, okay? No, I'm not proud of it either. - Remove our overrides of handleUpdate tag: we now try to detect whether we're on the client or server inside BlockEntity.load. Alas, this is needed for Fabric. - Remove BlockGeneric/TileGeneric entirely: we've slowly whittled this down over the years, and nowadays we can get away with putting most of its functionality into subclasses. This allows us to do some nice things with overriding HorizontalBlock (or our new HorizontalContainerBlock class), rather than reimplementing functionality in each class. Though it would be nice if Java had some sort of trait system :D: - Simplify a lot of our container class so it's just defined in terms of a NonNullList<ItemStack>. This also includes a total rewrite of the disk drive which I'm not ... thrilled about. It ended up being easier to copy the code from the mc-next branch :D:. - Try to test some of the gnarly bits of this. Still a /lot/ more to be done with testing this. Closes #658
This commit is contained in:
parent
77624fc6fd
commit
8360e8234d
|
@ -117,6 +117,7 @@ fun appendUnique(x: String) {
|
||||||
|
|
||||||
if (newClasses.any { it.startsWith("cctest%%") }) {
|
if (newClasses.any { it.startsWith("cctest%%") }) {
|
||||||
appendUnique(forgeModEntry("cctest", "core", "testFixtures"))
|
appendUnique(forgeModEntry("cctest", "core", "testFixtures"))
|
||||||
|
appendUnique(forgeModEntry("cctest", "common", "testFixtures"))
|
||||||
appendUnique(forgeModEntry("cctest", "common", "testMod"))
|
appendUnique(forgeModEntry("cctest", "common", "testMod"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,5 +32,6 @@ dependencies {
|
||||||
testRuntimeOnly(libs.bundles.testRuntime)
|
testRuntimeOnly(libs.bundles.testRuntime)
|
||||||
|
|
||||||
testModImplementation(testFixtures(project(":core")))
|
testModImplementation(testFixtures(project(":core")))
|
||||||
|
testModImplementation(testFixtures(project(":common")))
|
||||||
testModImplementation(libs.bundles.kotlin)
|
testModImplementation(libs.bundles.kotlin)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,11 +27,8 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
|
||||||
private static final int TEX_WIDTH = 254;
|
private static final int TEX_WIDTH = 254;
|
||||||
private static final int TEX_HEIGHT = 217;
|
private static final int TEX_HEIGHT = 217;
|
||||||
|
|
||||||
private final ComputerFamily family;
|
|
||||||
|
|
||||||
public TurtleScreen(TurtleMenu container, Inventory player, Component title) {
|
public TurtleScreen(TurtleMenu container, Inventory player, Component title) {
|
||||||
super(container, player, title, BORDER);
|
super(container, player, title, BORDER);
|
||||||
family = container.getFamily();
|
|
||||||
|
|
||||||
imageWidth = TEX_WIDTH + AbstractComputerMenu.SIDEBAR_WIDTH;
|
imageWidth = TEX_WIDTH + AbstractComputerMenu.SIDEBAR_WIDTH;
|
||||||
imageHeight = TEX_HEIGHT;
|
imageHeight = TEX_HEIGHT;
|
||||||
|
|
|
@ -107,7 +107,7 @@ public static void drawBorder(PoseStack transform, MultiBufferSource bufferSourc
|
||||||
double thisWidth = Math.min(right - borderX, X_SIZE);
|
double thisWidth = Math.min(right - borderX, X_SIZE);
|
||||||
drawTexture(matrix, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE, light);
|
drawTexture(matrix, buffer, borderX, y - 8, z - 0.02f, 0, COVER_Y, (float) thisWidth, COVER_SIZE, light);
|
||||||
drawTexture(matrix, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE, light);
|
drawTexture(matrix, buffer, borderX, y + Y_SIZE - 4, z - 0.02f, 0, COVER_Y + COVER_SIZE, (float) thisWidth, COVER_SIZE, light);
|
||||||
borderX += thisWidth;
|
borderX = (float) (borderX + thisWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -229,6 +229,7 @@ private static void renderTerminal(
|
||||||
|
|
||||||
RenderSystem.setInverseViewRotationMatrix(oldInverseRotation);
|
RenderSystem.setInverseViewRotationMatrix(oldInverseRotation);
|
||||||
}
|
}
|
||||||
|
case BEST -> throw new IllegalStateException("Impossible: Should never use BEST renderer");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,6 +108,7 @@ public String toString() {
|
||||||
return "WiredNode{@" + element.getPosition() + " (" + element.getClass().getSimpleName() + ")}";
|
return "WiredNode{@" + element.getPosition() + " (" + element.getClass().getSimpleName() + ")}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("LockNotBeforeTry")
|
||||||
private void acquireReadLock() {
|
private void acquireReadLock() {
|
||||||
var currentNetwork = network;
|
var currentNetwork = network;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.common;
|
||||||
|
|
||||||
|
import dan200.computercraft.shared.container.BasicContainer;
|
||||||
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link BlockEntity} which exposes an inventory.
|
||||||
|
*/
|
||||||
|
public abstract class AbstractContainerBlockEntity extends BaseContainerBlockEntity implements BasicContainer {
|
||||||
|
protected AbstractContainerBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
|
||||||
|
super(type, pos, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final Component getDefaultName() {
|
||||||
|
return Component.translatable(getBlockState().getBlock().getDescriptionId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean stillValid(Player player) {
|
||||||
|
return BlockEntityHelpers.isUsable(this, player, BlockEntityHelpers.DEFAULT_INTERACT_RANGE);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,85 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
|
||||||
*/
|
|
||||||
package dan200.computercraft.shared.common;
|
|
||||||
|
|
||||||
import dan200.computercraft.annotations.ForgeOverride;
|
|
||||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.util.RandomSource;
|
|
||||||
import net.minecraft.world.InteractionHand;
|
|
||||||
import net.minecraft.world.InteractionResult;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.LevelReader;
|
|
||||||
import net.minecraft.world.level.block.BaseEntityBlock;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.RenderShape;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public abstract class GenericBlock extends BaseEntityBlock {
|
|
||||||
private final RegistryEntry<? extends BlockEntityType<? extends GenericTile>> type;
|
|
||||||
|
|
||||||
public GenericBlock(Properties settings, RegistryEntry<? extends BlockEntityType<? extends GenericTile>> type) {
|
|
||||||
super(settings);
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public final void onRemove(BlockState block, Level world, BlockPos pos, BlockState replace, boolean bool) {
|
|
||||||
if (block.getBlock() == replace.getBlock()) return;
|
|
||||||
|
|
||||||
var tile = world.getBlockEntity(pos);
|
|
||||||
super.onRemove(block, world, pos, replace, bool);
|
|
||||||
world.removeBlockEntity(pos);
|
|
||||||
if (tile instanceof GenericTile generic) generic.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public final InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
|
||||||
var tile = world.getBlockEntity(pos);
|
|
||||||
return tile instanceof GenericTile generic ? generic.onActivate(player, hand, hit) : InteractionResult.PASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) {
|
|
||||||
var tile = world.getBlockEntity(pos);
|
|
||||||
if (tile instanceof GenericTile generic) generic.onNeighbourChange(neighbourPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ForgeOverride
|
|
||||||
public final void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbour) {
|
|
||||||
var tile = world.getBlockEntity(pos);
|
|
||||||
if (tile instanceof GenericTile generic) generic.onNeighbourTileEntityChange(neighbour);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
|
|
||||||
var te = world.getBlockEntity(pos);
|
|
||||||
if (te instanceof GenericTile generic) generic.blockTick();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
|
||||||
return type.get().create(pos, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public RenderShape getRenderShape(BlockState state) {
|
|
||||||
return RenderShape.MODEL;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
|
||||||
*/
|
|
||||||
package dan200.computercraft.shared.common;
|
|
||||||
|
|
||||||
import dan200.computercraft.annotations.ForgeOverride;
|
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.network.Connection;
|
|
||||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
|
||||||
import net.minecraft.world.InteractionHand;
|
|
||||||
import net.minecraft.world.InteractionResult;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
|
|
||||||
public abstract class GenericTile extends BlockEntity {
|
|
||||||
public GenericTile(BlockEntityType<? extends GenericTile> type, BlockPos pos, BlockState state) {
|
|
||||||
super(type, pos, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public final void updateBlock() {
|
|
||||||
setChanged();
|
|
||||||
var pos = getBlockPos();
|
|
||||||
var state = getBlockState();
|
|
||||||
getLevel().sendBlockUpdated(pos, state, state, Block.UPDATE_ALL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
|
||||||
return InteractionResult.PASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onNeighbourChange(BlockPos neighbour) {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void blockTick() {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected double getInteractRange(Player player) {
|
|
||||||
return 8.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isUsable(Player player) {
|
|
||||||
if (player == null || !player.isAlive() || getLevel().getBlockEntity(getBlockPos()) != this) return false;
|
|
||||||
|
|
||||||
var range = getInteractRange(player);
|
|
||||||
var pos = getBlockPos();
|
|
||||||
return player.getCommandSenderWorld() == getLevel() &&
|
|
||||||
player.distanceToSqr(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5) <= range * range;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ForgeOverride // FIXME: Implement this: I'd forgotten about this
|
|
||||||
public final void onDataPacket(Connection net, ClientboundBlockEntityDataPacket packet) {
|
|
||||||
var tag = packet.getTag();
|
|
||||||
if (tag != null) handleUpdateTag(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ForgeOverride
|
|
||||||
public void handleUpdateTag(CompoundTag tag) {
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.common;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.Containers;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
|
import net.minecraft.world.level.block.Mirror;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.Rotation;
|
||||||
|
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||||
|
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.DirectionProperty;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block which has a container and can be placed in a horizontal direction.
|
||||||
|
*
|
||||||
|
* @see AbstractContainerBlockEntity The container class which should be used on the block entity.
|
||||||
|
*/
|
||||||
|
public abstract class HorizontalContainerBlock extends BaseEntityBlock {
|
||||||
|
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||||
|
|
||||||
|
public HorizontalContainerBlock(Properties properties) {
|
||||||
|
super(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final BlockState getStateForPlacement(BlockPlaceContext placement) {
|
||||||
|
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final BlockState mirror(BlockState state, Mirror mirrorIn) {
|
||||||
|
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final BlockState rotate(BlockState state, Rotation rot) {
|
||||||
|
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
if (level.isClientSide) return InteractionResult.SUCCESS;
|
||||||
|
|
||||||
|
if (level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) {
|
||||||
|
player.openMenu(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InteractionResult.CONSUME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||||
|
if (state.is(newState.getBlock())) return;
|
||||||
|
|
||||||
|
if (level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) {
|
||||||
|
Containers.dropContents(level, pos, container);
|
||||||
|
level.updateNeighbourForOutputSignal(pos, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onRemove(state, level, pos, newState, isMoving);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
|
||||||
|
if (stack.hasCustomHoverName() && world.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) {
|
||||||
|
container.setCustomName(stack.getHoverName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final boolean hasAnalogOutputSignal(BlockState pState) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos pPos) {
|
||||||
|
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(pLevel.getBlockEntity(pPos));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public RenderShape getRenderShape(BlockState state) {
|
||||||
|
return RenderShape.MODEL;
|
||||||
|
}
|
||||||
|
}
|
|
@ -147,7 +147,7 @@ public final List<String> list(IArguments args) throws LuaException {
|
||||||
for (CommandNode<?> child : node.getChildren()) {
|
for (CommandNode<?> child : node.getChildren()) {
|
||||||
if (child instanceof LiteralCommandNode<?>) result.add(child.getName());
|
if (child instanceof LiteralCommandNode<?>) result.add(child.getName());
|
||||||
}
|
}
|
||||||
return result;
|
return Collections.unmodifiableList(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,34 +5,42 @@
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.computer.blocks;
|
package dan200.computercraft.shared.computer.blocks;
|
||||||
|
|
||||||
|
import dan200.computercraft.annotations.ForgeOverride;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
|
||||||
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||||
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.stats.Stats;
|
import net.minecraft.stats.Stats;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.MenuProvider;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.BaseEntityBlock;
|
import net.minecraft.world.level.LevelReader;
|
||||||
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
|
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
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.minecraft.world.level.storage.loot.LootContext;
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntity> extends GenericBlock implements IBundledRedstoneBlock {
|
public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntity> extends HorizontalDirectionalBlock implements IBundledRedstoneBlock, EntityBlock {
|
||||||
private static final ResourceLocation DROP = new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer");
|
private static final ResourceLocation DROP = new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer");
|
||||||
|
|
||||||
private final ComputerFamily family;
|
private final ComputerFamily family;
|
||||||
|
@ -40,7 +48,7 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
||||||
private final BlockEntityTicker<T> serverTicker = (level, pos, state, computer) -> computer.serverTick();
|
private final BlockEntityTicker<T> serverTicker = (level, pos, state, computer) -> computer.serverTick();
|
||||||
|
|
||||||
protected AbstractComputerBlock(Properties settings, ComputerFamily family, RegistryEntry<BlockEntityType<T>> type) {
|
protected AbstractComputerBlock(Properties settings, ComputerFamily family, RegistryEntry<BlockEntityType<T>> type) {
|
||||||
super(settings, type);
|
super(settings);
|
||||||
this.family = family;
|
this.family = family;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
@ -160,9 +168,41 @@ public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
return world.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer ? computer.use(player, hand) : InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) {
|
||||||
|
var be = world.getBlockEntity(pos);
|
||||||
|
if (be instanceof AbstractComputerBlockEntity computer) computer.neighborChanged(neighbourPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ForgeOverride
|
||||||
|
public final void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbour) {
|
||||||
|
var be = world.getBlockEntity(pos);
|
||||||
|
if (be instanceof AbstractComputerBlockEntity computer) computer.neighborChanged(neighbour);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public MenuProvider getMenuProvider(BlockState state, Level level, BlockPos pos) {
|
||||||
|
return level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer ? computer : null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
return level.isClientSide ? null : BaseEntityBlock.createTickerHelper(type, this.type.get(), serverTicker);
|
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, this.type.get(), serverTicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return type.get().create(pos, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.computer.ComputerSide;
|
import dan200.computercraft.core.computer.ComputerSide;
|
||||||
import dan200.computercraft.impl.BundledRedstone;
|
import dan200.computercraft.impl.BundledRedstone;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
|
@ -18,6 +17,7 @@
|
||||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||||
import dan200.computercraft.shared.platform.ComponentAccess;
|
import dan200.computercraft.shared.platform.ComponentAccess;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
import dan200.computercraft.shared.util.DirectionUtil;
|
import dan200.computercraft.shared.util.DirectionUtil;
|
||||||
import dan200.computercraft.shared.util.IDAssigner;
|
import dan200.computercraft.shared.util.IDAssigner;
|
||||||
import dan200.computercraft.shared.util.RedstoneUtil;
|
import dan200.computercraft.shared.util.RedstoneUtil;
|
||||||
|
@ -32,14 +32,14 @@
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||||
|
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.minecraft.world.phys.BlockHitResult;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public abstract class AbstractComputerBlockEntity extends GenericTile implements IComputerBlockEntity, Nameable, MenuProvider {
|
public abstract class AbstractComputerBlockEntity extends BlockEntity implements IComputerBlockEntity, Nameable, MenuProvider {
|
||||||
private static final String NBT_ID = "ComputerId";
|
private static final String NBT_ID = "ComputerId";
|
||||||
private static final String NBT_LABEL = "Label";
|
private static final String NBT_LABEL = "Label";
|
||||||
private static final String NBT_ON = "On";
|
private static final String NBT_ON = "On";
|
||||||
|
@ -58,7 +58,7 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||||
|
|
||||||
private final ComputerFamily family;
|
private final ComputerFamily family;
|
||||||
|
|
||||||
public AbstractComputerBlockEntity(BlockEntityType<? extends GenericTile> type, BlockPos pos, BlockState state, ComputerFamily family) {
|
public AbstractComputerBlockEntity(BlockEntityType<? extends AbstractComputerBlockEntity> type, BlockPos pos, BlockState state, ComputerFamily family) {
|
||||||
super(type, pos, state);
|
super(type, pos, state);
|
||||||
this.family = family;
|
this.family = family;
|
||||||
}
|
}
|
||||||
|
@ -71,31 +71,26 @@ protected void unload() {
|
||||||
instanceID = -1;
|
instanceID = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
unload();
|
|
||||||
for (var dir : DirectionUtil.FACINGS) {
|
|
||||||
RedstoneUtil.propagateRedstoneOutput(getLevel(), getBlockPos(), dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRemoved() {
|
public void setRemoved() {
|
||||||
unload();
|
|
||||||
super.setRemoved();
|
super.setRemoved();
|
||||||
|
unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean canNameWithTag(Player player) {
|
protected boolean canNameWithTag(Player player) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected double getInteractRange() {
|
||||||
public boolean isUsable(Player player) {
|
return BlockEntityHelpers.DEFAULT_INTERACT_RANGE;
|
||||||
return super.isUsable(player) && BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean isUsable(Player player) {
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
return BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName())
|
||||||
|
&& BlockEntityHelpers.isUsable(this, player, getInteractRange());
|
||||||
|
}
|
||||||
|
|
||||||
|
public InteractionResult use(Player player, InteractionHand hand) {
|
||||||
var currentItem = player.getItemInHand(hand);
|
var currentItem = player.getItemInHand(hand);
|
||||||
if (!currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag(player) && currentItem.hasCustomHoverName()) {
|
if (!currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag(player) && currentItem.hasCustomHoverName()) {
|
||||||
// Label to rename computer
|
// Label to rename computer
|
||||||
|
@ -120,13 +115,7 @@ public InteractionResult onActivate(Player player, InteractionHand hand, BlockHi
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void neighborChanged(BlockPos neighbour) {
|
||||||
public void onNeighbourChange(BlockPos neighbour) {
|
|
||||||
updateInputAt(neighbour);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
|
||||||
updateInputAt(neighbour);
|
updateInputAt(neighbour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,9 +168,16 @@ public void saveAdditional(CompoundTag nbt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(CompoundTag nbt) {
|
public final void load(CompoundTag nbt) {
|
||||||
super.load(nbt);
|
super.load(nbt);
|
||||||
|
if (level != null && level.isClientSide) {
|
||||||
|
loadClient(nbt);
|
||||||
|
} else {
|
||||||
|
loadServer(nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loadServer(CompoundTag nbt) {
|
||||||
// Load ID, label and power state
|
// Load ID, label and power state
|
||||||
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
||||||
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
||||||
|
@ -268,7 +264,7 @@ private void updateInputAt(BlockPos neighbour) {
|
||||||
* Update the block's state and propagate redstone output.
|
* Update the block's state and propagate redstone output.
|
||||||
*/
|
*/
|
||||||
public void updateOutput() {
|
public void updateOutput() {
|
||||||
updateBlock();
|
BlockEntityHelpers.updateBlock(this);
|
||||||
for (var dir : DirectionUtil.FACINGS) {
|
for (var dir : DirectionUtil.FACINGS) {
|
||||||
RedstoneUtil.propagateRedstoneOutput(getLevel(), getBlockPos(), dir);
|
RedstoneUtil.propagateRedstoneOutput(getLevel(), getBlockPos(), dir);
|
||||||
}
|
}
|
||||||
|
@ -319,7 +315,7 @@ public final ServerComputer createServerComputer() {
|
||||||
if (computer == null) {
|
if (computer == null) {
|
||||||
if (computerID < 0) {
|
if (computerID < 0) {
|
||||||
computerID = ComputerCraftAPI.createUniqueNumberedSaveDir(level, IDAssigner.COMPUTER);
|
computerID = ComputerCraftAPI.createUniqueNumberedSaveDir(level, IDAssigner.COMPUTER);
|
||||||
updateBlock();
|
BlockEntityHelpers.updateBlock(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
computer = createComputer(computerID);
|
computer = createComputer(computerID);
|
||||||
|
@ -353,8 +349,7 @@ public CompoundTag getUpdateTag() {
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected void loadClient(CompoundTag nbt) {
|
||||||
public void handleUpdateTag(CompoundTag nbt) {
|
|
||||||
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
||||||
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
||||||
}
|
}
|
||||||
|
@ -368,7 +363,7 @@ protected void transferStateFrom(AbstractComputerBlockEntity copy) {
|
||||||
on = copy.on;
|
on = copy.on;
|
||||||
startOn = copy.startOn;
|
startOn = copy.startOn;
|
||||||
lockCode = copy.lockCode;
|
lockCode = copy.lockCode;
|
||||||
updateBlock();
|
BlockEntityHelpers.updateBlock(this);
|
||||||
}
|
}
|
||||||
copy.instanceID = -1;
|
copy.instanceID = -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Mirror;
|
|
||||||
import net.minecraft.world.level.block.Rotation;
|
|
||||||
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.minecraft.world.level.block.state.StateDefinition;
|
import net.minecraft.world.level.block.state.StateDefinition;
|
||||||
|
@ -47,18 +45,6 @@ public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
||||||
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite());
|
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
|
||||||
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState rotate(BlockState state, Rotation rot) {
|
|
||||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ItemStack getItem(AbstractComputerBlockEntity tile) {
|
protected ItemStack getItem(AbstractComputerBlockEntity tile) {
|
||||||
return tile instanceof ComputerBlockEntity ? ComputerItemFactory.create((ComputerBlockEntity) tile) : ItemStack.EMPTY;
|
return tile instanceof ComputerBlockEntity ? ComputerItemFactory.create((ComputerBlockEntity) tile) : ItemStack.EMPTY;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||||
import dan200.computercraft.shared.util.SingleIntArray;
|
import dan200.computercraft.shared.container.SingleContainerData;
|
||||||
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;
|
||||||
import net.minecraft.world.inventory.ContainerData;
|
import net.minecraft.world.inventory.ContainerData;
|
||||||
|
@ -46,7 +46,7 @@ public AbstractComputerMenu(
|
||||||
super(type, id);
|
super(type, id);
|
||||||
this.canUse = canUse;
|
this.canUse = canUse;
|
||||||
this.family = family;
|
this.family = family;
|
||||||
data = computer == null ? new SimpleContainerData(1) : (SingleIntArray) () -> computer.isOn() ? 1 : 0;
|
data = computer == null ? new SimpleContainerData(1) : (SingleContainerData) () -> computer.isOn() ? 1 : 0;
|
||||||
addDataSlots(data);
|
addDataSlots(data);
|
||||||
|
|
||||||
this.computer = computer;
|
this.computer = computer;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||||
import dan200.computercraft.shared.util.InvisibleSlot;
|
import dan200.computercraft.shared.container.InvisibleSlot;
|
||||||
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.MenuType;
|
import net.minecraft.world.inventory.MenuType;
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.container;
|
||||||
|
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
|
import net.minecraft.world.Container;
|
||||||
|
import net.minecraft.world.ContainerHelper;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic implementation of {@link Container} which operates on a {@linkplain #getContents() stack of items}.
|
||||||
|
*/
|
||||||
|
public interface BasicContainer extends Container {
|
||||||
|
NonNullList<ItemStack> getContents();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default int getMaxStackSize() {
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void startOpen(Player player) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void stopOpen(Player player) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean canPlaceItem(int slot, ItemStack stack) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default int getContainerSize() {
|
||||||
|
return getContents().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean isEmpty() {
|
||||||
|
for (var stack : getContents()) {
|
||||||
|
if (!stack.isEmpty()) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default ItemStack getItem(int slot) {
|
||||||
|
var contents = getContents();
|
||||||
|
return slot >= 0 && slot < contents.size() ? contents.get(slot) : ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default ItemStack removeItemNoUpdate(int slot) {
|
||||||
|
return ContainerHelper.takeItem(getContents(), slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default ItemStack removeItem(int slot, int count) {
|
||||||
|
return ContainerHelper.removeItem(getContents(), slot, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void setItem(int slot, ItemStack itemStack) {
|
||||||
|
getContents().set(slot, itemStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void clearContent() {
|
||||||
|
getContents().clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.container;
|
||||||
|
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.WorldlyContainer;
|
import net.minecraft.world.WorldlyContainer;
|
||||||
|
@ -11,7 +11,10 @@
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public interface DefaultSidedInventory extends DefaultInventory, WorldlyContainer {
|
/**
|
||||||
|
* A basic implementation of {@link WorldlyContainer} which operates on a {@linkplain #getContents() stack of items}.
|
||||||
|
*/
|
||||||
|
public interface BasicWorldlyContainer extends BasicContainer, WorldlyContainer {
|
||||||
@Override
|
@Override
|
||||||
default boolean canPlaceItemThroughFace(int slot, ItemStack stack, @Nullable Direction side) {
|
default boolean canPlaceItemThroughFace(int slot, ItemStack stack, @Nullable Direction side) {
|
||||||
return canPlaceItem(slot, stack);
|
return canPlaceItem(slot, stack);
|
|
@ -3,7 +3,7 @@
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.container;
|
||||||
|
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a delegate over inventories.
|
* Provides a delegate over inventories.
|
||||||
|
@ -97,4 +98,9 @@ default int countItem(Item stack) {
|
||||||
default boolean hasAnyOf(Set<Item> set) {
|
default boolean hasAnyOf(Set<Item> set) {
|
||||||
return getInventory().hasAnyOf(set);
|
return getInventory().hasAnyOf(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default boolean hasAnyMatching(Predicate<ItemStack> predicate) {
|
||||||
|
return getInventory().hasAnyMatching(predicate);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.container;
|
||||||
|
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
|
@ -3,12 +3,15 @@
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.container;
|
||||||
|
|
||||||
import net.minecraft.world.inventory.ContainerData;
|
import net.minecraft.world.inventory.ContainerData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A basic {@link ContainerData} implementation which provides a single value.
|
||||||
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface SingleIntArray extends ContainerData {
|
public interface SingleContainerData extends ContainerData {
|
||||||
int get();
|
int get();
|
||||||
|
|
||||||
@Override
|
@Override
|
|
@ -3,7 +3,7 @@
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.container;
|
||||||
|
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.inventory.Slot;
|
import net.minecraft.world.inventory.Slot;
|
|
@ -5,40 +5,34 @@
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.diskdrive;
|
package dan200.computercraft.shared.peripheral.diskdrive;
|
||||||
|
|
||||||
|
import dan200.computercraft.impl.MediaProviders;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
import dan200.computercraft.shared.common.HorizontalContainerBlock;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.stats.Stats;
|
import net.minecraft.world.InteractionHand;
|
||||||
import net.minecraft.world.Nameable;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.BaseEntityBlock;
|
import net.minecraft.world.level.block.BaseEntityBlock;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Mirror;
|
|
||||||
import net.minecraft.world.level.block.Rotation;
|
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
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.minecraft.world.level.block.state.StateDefinition;
|
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.level.block.state.properties.EnumProperty;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class DiskDriveBlock extends GenericBlock {
|
public class DiskDriveBlock extends HorizontalContainerBlock {
|
||||||
static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
|
||||||
public static final EnumProperty<DiskDriveState> STATE = EnumProperty.create("state", DiskDriveState.class);
|
public static final EnumProperty<DiskDriveState> STATE = EnumProperty.create("state", DiskDriveState.class);
|
||||||
|
|
||||||
private static final BlockEntityTicker<DiskDriveBlockEntity> serverTicker = (level, pos, state, drive) -> drive.serverTick();
|
private static final BlockEntityTicker<DiskDriveBlockEntity> serverTicker = (level, pos, state, drive) -> drive.serverTick();
|
||||||
|
|
||||||
public DiskDriveBlock(Properties settings) {
|
public DiskDriveBlock(Properties settings) {
|
||||||
super(settings, ModRegistry.BlockEntities.DISK_DRIVE);
|
super(settings);
|
||||||
registerDefaultState(getStateDefinition().any()
|
registerDefaultState(getStateDefinition().any()
|
||||||
.setValue(FACING, Direction.NORTH)
|
.setValue(FACING, Direction.NORTH)
|
||||||
.setValue(STATE, DiskDriveState.EMPTY));
|
.setValue(STATE, DiskDriveState.EMPTY));
|
||||||
|
@ -52,41 +46,25 @@ protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockSt
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
if (player.isCrouching() && level.getBlockEntity(pos) instanceof DiskDriveBlockEntity drive) {
|
||||||
|
// Try to put a disk into the drive
|
||||||
|
var disk = player.getItemInHand(hand);
|
||||||
|
if (disk.isEmpty()) return InteractionResult.PASS;
|
||||||
|
|
||||||
|
if (!level.isClientSide && drive.getDiskStack().isEmpty() && MediaProviders.get(disk) != null) {
|
||||||
|
drive.setDiskStack(disk.split(1));
|
||||||
|
}
|
||||||
|
return InteractionResult.sidedSuccess(level.isClientSide);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
return super.use(state, level, pos, player, hand, hit);
|
||||||
@Deprecated
|
|
||||||
public BlockState rotate(BlockState state, Rotation rot) {
|
|
||||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite());
|
return ModRegistry.BlockEntities.DISK_DRIVE.get().create(pos, state);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity te, ItemStack stack) {
|
|
||||||
if (te instanceof Nameable nameable && nameable.hasCustomName()) {
|
|
||||||
player.awardStat(Stats.BLOCK_MINED.get(this));
|
|
||||||
player.causeFoodExhaustion(0.005F);
|
|
||||||
|
|
||||||
var result = new ItemStack(this);
|
|
||||||
result.setHoverName(nameable.getCustomName());
|
|
||||||
popResource(world, pos, result);
|
|
||||||
} else {
|
|
||||||
super.playerDestroy(world, player, pos, state, te, stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
|
|
||||||
if (stack.hasCustomHoverName() && world.getBlockEntity(pos) instanceof DiskDriveBlockEntity drive) {
|
|
||||||
drive.customName = stack.getHoverName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -5,42 +5,34 @@
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.diskdrive;
|
package dan200.computercraft.shared.peripheral.diskdrive;
|
||||||
|
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import com.google.errorprone.annotations.concurrent.GuardedBy;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
import dan200.computercraft.api.media.IMedia;
|
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.impl.MediaProviders;
|
import dan200.computercraft.shared.common.AbstractContainerBlockEntity;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.network.client.PlayRecordClientMessage;
|
import dan200.computercraft.shared.network.client.PlayRecordClientMessage;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import dan200.computercraft.shared.util.DefaultInventory;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.core.NonNullList;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.*;
|
|
||||||
import net.minecraft.world.entity.item.ItemEntity;
|
|
||||||
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.inventory.AbstractContainerMenu;
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
import net.minecraft.world.level.block.LevelEvent;
|
||||||
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.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity {
|
||||||
|
|
||||||
public final class DiskDriveBlockEntity extends GenericTile implements DefaultInventory, Nameable, MenuProvider {
|
|
||||||
private static final String NBT_NAME = "CustomName";
|
|
||||||
private static final String NBT_ITEM = "Item";
|
private static final String NBT_ITEM = "Item";
|
||||||
|
|
||||||
private static class MountInfo {
|
private static class MountInfo {
|
||||||
|
@ -48,54 +40,37 @@ private static class MountInfo {
|
||||||
String mountPath;
|
String mountPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private final DiskDrivePeripheral peripheral = new DiskDrivePeripheral(this);
|
||||||
Component customName;
|
|
||||||
private LockCode lockCode = LockCode.NO_LOCK;
|
|
||||||
|
|
||||||
private final Map<IComputerAccess, MountInfo> computers = new HashMap<>();
|
private final @GuardedBy("this") Map<IComputerAccess, MountInfo> computers = new HashMap<>();
|
||||||
|
|
||||||
private ItemStack diskStack = ItemStack.EMPTY;
|
private final NonNullList<ItemStack> inventory = NonNullList.withSize(1, ItemStack.EMPTY);
|
||||||
private @Nullable IPeripheral peripheral;
|
|
||||||
private @Nullable IMount diskMount = null;
|
|
||||||
|
|
||||||
private boolean recordQueued = false;
|
private MediaStack media = MediaStack.EMPTY;
|
||||||
private boolean recordPlaying = false;
|
private boolean recordPlaying = false;
|
||||||
private boolean restartRecord = false;
|
// In order to avoid main-thread calls in the peripheral, we set flags to mark which operation should be performed,
|
||||||
private boolean ejectQueued;
|
// then read them when ticking.
|
||||||
|
private final AtomicReference<RecordCommand> recordQueued = new AtomicReference<>(null);
|
||||||
|
private final AtomicBoolean ejectQueued = new AtomicBoolean(false);
|
||||||
|
|
||||||
public DiskDriveBlockEntity(BlockEntityType<DiskDriveBlockEntity> type, BlockPos pos, BlockState state) {
|
public DiskDriveBlockEntity(BlockEntityType<DiskDriveBlockEntity> type, BlockPos pos, BlockState state) {
|
||||||
super(type, pos, state);
|
super(type, pos, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IPeripheral peripheral() {
|
||||||
|
return peripheral;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void clearRemoved() {
|
||||||
ejectContents(true);
|
updateItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRemoved() {
|
||||||
if (recordPlaying) stopRecord();
|
if (recordPlaying) stopRecord();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUsable(Player player) {
|
|
||||||
return super.isUsable(player) && BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
|
||||||
if (player.isCrouching()) {
|
|
||||||
// Try to put a disk into the drive
|
|
||||||
var disk = player.getItemInHand(hand);
|
|
||||||
if (disk.isEmpty()) return InteractionResult.PASS;
|
|
||||||
if (!getLevel().isClientSide && getItem(0).isEmpty() && MediaProviders.get(disk) != null) {
|
|
||||||
setDiskStack(disk);
|
|
||||||
player.setItemInHand(hand, ItemStack.EMPTY);
|
|
||||||
}
|
|
||||||
return InteractionResult.SUCCESS;
|
|
||||||
} else {
|
|
||||||
// Open the GUI
|
|
||||||
if (!getLevel().isClientSide && isUsable(player)) player.openMenu(this);
|
|
||||||
return InteractionResult.SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Direction getDirection() {
|
public Direction getDirection() {
|
||||||
return getBlockState().getValue(DiskDriveBlock.FACING);
|
return getBlockState().getValue(DiskDriveBlock.FACING);
|
||||||
}
|
}
|
||||||
|
@ -103,52 +78,32 @@ public Direction getDirection() {
|
||||||
@Override
|
@Override
|
||||||
public void load(CompoundTag nbt) {
|
public void load(CompoundTag nbt) {
|
||||||
super.load(nbt);
|
super.load(nbt);
|
||||||
customName = nbt.contains(NBT_NAME) ? Component.Serializer.fromJson(nbt.getString(NBT_NAME)) : null;
|
setDiskStack(nbt.contains(NBT_ITEM) ? ItemStack.of(nbt.getCompound(NBT_ITEM)) : ItemStack.EMPTY);
|
||||||
if (nbt.contains(NBT_ITEM)) {
|
|
||||||
var item = nbt.getCompound(NBT_ITEM);
|
|
||||||
diskStack = ItemStack.of(item);
|
|
||||||
diskMount = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
lockCode = LockCode.fromTag(nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveAdditional(CompoundTag nbt) {
|
public void saveAdditional(CompoundTag tag) {
|
||||||
if (customName != null) nbt.putString(NBT_NAME, Component.Serializer.toJson(customName));
|
super.saveAdditional(tag);
|
||||||
|
|
||||||
if (!diskStack.isEmpty()) {
|
var stack = getDiskStack();
|
||||||
var item = new CompoundTag();
|
if (!stack.isEmpty()) tag.put(NBT_ITEM, stack.save(new CompoundTag()));
|
||||||
diskStack.save(item);
|
|
||||||
nbt.put(NBT_ITEM, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
lockCode.addToTag(nbt);
|
|
||||||
|
|
||||||
super.saveAdditional(nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void serverTick() {
|
void serverTick() {
|
||||||
// Ejection
|
if (ejectQueued.getAndSet(false)) ejectContents();
|
||||||
if (ejectQueued) {
|
|
||||||
ejectContents(false);
|
|
||||||
ejectQueued = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Music
|
var recordQueued = this.recordQueued.getAndSet(null);
|
||||||
synchronized (this) {
|
if (recordQueued != null) {
|
||||||
if (recordPlaying != recordQueued || restartRecord) {
|
switch (recordQueued) {
|
||||||
restartRecord = false;
|
case PLAY -> {
|
||||||
if (recordQueued) {
|
var record = media.getAudio();
|
||||||
var contents = getDiskMedia();
|
|
||||||
var record = contents != null ? contents.getAudio(diskStack) : null;
|
|
||||||
if (record != null) {
|
if (record != null) {
|
||||||
recordPlaying = true;
|
recordPlaying = true;
|
||||||
playRecord();
|
var title = media.getAudioTitle();
|
||||||
} else {
|
sendMessage(new PlayRecordClientMessage(getBlockPos(), record, title));
|
||||||
recordQueued = false;
|
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
case STOP -> {
|
||||||
stopRecord();
|
stopRecord();
|
||||||
recordPlaying = false;
|
recordPlaying = false;
|
||||||
}
|
}
|
||||||
|
@ -156,115 +111,61 @@ var record = contents != null ? contents.getAudio(diskStack) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IInventory implementation
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getContainerSize() {
|
public NonNullList<ItemStack> getContents() {
|
||||||
return 1;
|
return inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public void setChanged() {
|
||||||
return diskStack.isEmpty();
|
if (level != null && !level.isClientSide) updateItem();
|
||||||
|
super.setChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void updateItem() {
|
||||||
public ItemStack getItem(int slot) {
|
var newDisk = getDiskStack();
|
||||||
return diskStack;
|
if (ItemStack.isSame(newDisk, media.stack)) return;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
var media = new MediaStack(newDisk.copy());
|
||||||
public ItemStack removeItemNoUpdate(int slot) {
|
|
||||||
var result = diskStack;
|
|
||||||
diskStack = ItemStack.EMPTY;
|
|
||||||
diskMount = null;
|
|
||||||
|
|
||||||
return result;
|
if (newDisk.isEmpty()) {
|
||||||
}
|
updateBlockState(DiskDriveState.EMPTY);
|
||||||
|
} else {
|
||||||
@Override
|
updateBlockState(media.media != null ? DiskDriveState.FULL : DiskDriveState.INVALID);
|
||||||
public ItemStack removeItem(int slot, int count) {
|
|
||||||
if (diskStack.isEmpty()) return ItemStack.EMPTY;
|
|
||||||
|
|
||||||
if (diskStack.getCount() <= count) {
|
|
||||||
var disk = diskStack;
|
|
||||||
setItem(slot, ItemStack.EMPTY);
|
|
||||||
return disk;
|
|
||||||
}
|
|
||||||
|
|
||||||
var part = diskStack.split(count);
|
|
||||||
setItem(slot, diskStack.isEmpty() ? ItemStack.EMPTY : diskStack);
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(int slot, ItemStack stack) {
|
|
||||||
if (getLevel().isClientSide) {
|
|
||||||
diskStack = stack;
|
|
||||||
diskMount = null;
|
|
||||||
setChanged();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (ItemStack.isSameItemSameTags(stack, diskStack)) {
|
|
||||||
diskStack = stack;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unmount old disk
|
// Unmount old disk
|
||||||
if (!diskStack.isEmpty()) {
|
if (!this.media.stack.isEmpty()) {
|
||||||
// TODO: Is this iteration thread safe?
|
for (var computer : computers.entrySet()) unmountDisk(computer.getKey(), computer.getValue());
|
||||||
var computers = this.computers.keySet();
|
|
||||||
for (var computer : computers) unmountDisk(computer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop music
|
// Stop music
|
||||||
if (recordPlaying) {
|
if (recordPlaying) {
|
||||||
stopRecord();
|
stopRecord();
|
||||||
recordPlaying = false;
|
recordPlaying = false;
|
||||||
recordQueued = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swap disk over
|
this.media = media;
|
||||||
diskStack = stack;
|
|
||||||
diskMount = null;
|
|
||||||
setChanged();
|
|
||||||
|
|
||||||
// Mount new disk
|
// Mount new disk
|
||||||
if (!diskStack.isEmpty()) {
|
if (!this.media.stack.isEmpty()) {
|
||||||
var computers = this.computers.keySet();
|
for (var computer : computers.entrySet()) mountDisk(computer.getKey(), computer.getValue(), this.media);
|
||||||
for (var computer : computers) mountDisk(computer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setChanged() {
|
|
||||||
if (!level.isClientSide) updateBlockState();
|
|
||||||
super.setChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean stillValid(Player player) {
|
|
||||||
return isUsable(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearContent() {
|
|
||||||
setItem(0, ItemStack.EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemStack getDiskStack() {
|
ItemStack getDiskStack() {
|
||||||
return getItem(0);
|
return getItem(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDiskStack(ItemStack stack) {
|
MediaStack getMedia() {
|
||||||
setItem(0, stack);
|
return media;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable IMedia getDiskMedia() {
|
void setDiskStack(ItemStack stack) {
|
||||||
return MediaProviders.get(getDiskStack());
|
setItem(0, stack);
|
||||||
|
setChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -277,96 +178,63 @@ String getDiskMountPath(IComputerAccess computer) {
|
||||||
|
|
||||||
void mount(IComputerAccess computer) {
|
void mount(IComputerAccess computer) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
computers.put(computer, new MountInfo());
|
var info = new MountInfo();
|
||||||
mountDisk(computer);
|
computers.put(computer, info);
|
||||||
|
mountDisk(computer, info, media);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unmount(IComputerAccess computer) {
|
void unmount(IComputerAccess computer) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
unmountDisk(computer);
|
unmountDisk(computer, computers.remove(computer));
|
||||||
computers.remove(computer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void playDiskAudio() {
|
void playDiskAudio() {
|
||||||
synchronized (this) {
|
recordQueued.set(RecordCommand.PLAY);
|
||||||
var media = getDiskMedia();
|
|
||||||
if (media != null && media.getAudioTitle(diskStack) != null) {
|
|
||||||
recordQueued = true;
|
|
||||||
restartRecord = recordPlaying;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopDiskAudio() {
|
void stopDiskAudio() {
|
||||||
synchronized (this) {
|
recordQueued.set(RecordCommand.STOP);
|
||||||
recordQueued = false;
|
|
||||||
restartRecord = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ejectDisk() {
|
void ejectDisk() {
|
||||||
synchronized (this) {
|
ejectQueued.set(true);
|
||||||
ejectQueued = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// private methods
|
private void mountDisk(IComputerAccess computer, MountInfo info, MediaStack disk) {
|
||||||
|
var mount = disk.getMount((ServerLevel) getLevel());
|
||||||
private synchronized void mountDisk(IComputerAccess computer) {
|
if (mount != null) {
|
||||||
if (!diskStack.isEmpty()) {
|
if (mount instanceof IWritableMount writable) {
|
||||||
var info = assertNonNull(computers.get(computer));
|
|
||||||
var contents = getDiskMedia();
|
|
||||||
if (contents != null) {
|
|
||||||
if (diskMount == null) {
|
|
||||||
diskMount = contents.createDataMount(diskStack, getLevel());
|
|
||||||
}
|
|
||||||
if (diskMount != null) {
|
|
||||||
if (diskMount instanceof IWritableMount) {
|
|
||||||
// Try mounting at the lowest numbered "disk" name we can
|
// Try mounting at the lowest numbered "disk" name we can
|
||||||
var n = 1;
|
var n = 1;
|
||||||
while (info.mountPath == null) {
|
while (info.mountPath == null) {
|
||||||
info.mountPath = computer.mountWritable(n == 1 ? "disk" : "disk" + n, (IWritableMount) diskMount);
|
info.mountPath = computer.mountWritable(n == 1 ? "disk" : "disk" + n, writable);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Try mounting at the lowest numbered "disk" name we can
|
// Try mounting at the lowest numbered "disk" name we can
|
||||||
var n = 1;
|
var n = 1;
|
||||||
while (info.mountPath == null) {
|
while (info.mountPath == null) {
|
||||||
info.mountPath = computer.mount(n == 1 ? "disk" : "disk" + n, diskMount);
|
info.mountPath = computer.mount(n == 1 ? "disk" : "disk" + n, mount);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info.mountPath = null;
|
info.mountPath = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
computer.queueEvent("disk", computer.getAttachmentName());
|
computer.queueEvent("disk", computer.getAttachmentName());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void unmountDisk(IComputerAccess computer) {
|
private static void unmountDisk(IComputerAccess computer, MountInfo info) {
|
||||||
if (!diskStack.isEmpty()) {
|
|
||||||
var info = Objects.requireNonNull(computers.get(computer), "No mount info");
|
|
||||||
if (info.mountPath != null) {
|
if (info.mountPath != null) {
|
||||||
computer.unmount(info.mountPath);
|
computer.unmount(info.mountPath);
|
||||||
info.mountPath = null;
|
info.mountPath = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
computer.queueEvent("disk_eject", computer.getAttachmentName());
|
computer.queueEvent("disk_eject", computer.getAttachmentName());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBlockState() {
|
|
||||||
if (remove || level == null) return;
|
|
||||||
|
|
||||||
if (!diskStack.isEmpty()) {
|
|
||||||
var contents = getDiskMedia();
|
|
||||||
updateBlockState(contents != null ? DiskDriveState.FULL : DiskDriveState.INVALID);
|
|
||||||
} else {
|
|
||||||
updateBlockState(DiskDriveState.EMPTY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBlockState(DiskDriveState state) {
|
private void updateBlockState(DiskDriveState state) {
|
||||||
var blockState = getBlockState();
|
var blockState = getBlockState();
|
||||||
|
@ -375,81 +243,32 @@ private void updateBlockState(DiskDriveState state) {
|
||||||
getLevel().setBlockAndUpdate(getBlockPos(), blockState.setValue(DiskDriveBlock.STATE, state));
|
getLevel().setBlockAndUpdate(getBlockPos(), blockState.setValue(DiskDriveBlock.STATE, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void ejectContents(boolean destroyed) {
|
private void ejectContents() {
|
||||||
if (getLevel().isClientSide || diskStack.isEmpty()) return;
|
if (getLevel().isClientSide) return;
|
||||||
|
|
||||||
// Remove the disks from the inventory
|
var stack = getDiskStack();
|
||||||
var disks = diskStack;
|
if (stack.isEmpty()) return;
|
||||||
setDiskStack(ItemStack.EMPTY);
|
setDiskStack(ItemStack.EMPTY);
|
||||||
|
|
||||||
// Spawn the item in the world
|
WorldUtil.dropItemStack(stack, getLevel(), getBlockPos(), getDirection());
|
||||||
var xOff = 0;
|
getLevel().levelEvent(LevelEvent.SOUND_DISPENSER_DISPENSE, getBlockPos(), 0);
|
||||||
var zOff = 0;
|
|
||||||
if (!destroyed) {
|
|
||||||
var dir = getDirection();
|
|
||||||
xOff = dir.getStepX();
|
|
||||||
zOff = dir.getStepZ();
|
|
||||||
}
|
|
||||||
|
|
||||||
var pos = getBlockPos();
|
|
||||||
var x = pos.getX() + 0.5 + xOff * 0.5;
|
|
||||||
var y = pos.getY() + 0.75;
|
|
||||||
var z = pos.getZ() + 0.5 + zOff * 0.5;
|
|
||||||
var entityitem = new ItemEntity(getLevel(), x, y, z, disks);
|
|
||||||
entityitem.setDeltaMovement(xOff * 0.15, 0, zOff * 0.15);
|
|
||||||
|
|
||||||
getLevel().addFreshEntity(entityitem);
|
|
||||||
if (!destroyed) getLevel().globalLevelEvent(1000, getBlockPos(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Private methods
|
|
||||||
|
|
||||||
private void playRecord() {
|
|
||||||
var contents = getDiskMedia();
|
|
||||||
var record = contents != null ? contents.getAudio(diskStack) : null;
|
|
||||||
if (record != null) {
|
|
||||||
playRecord(new PlayRecordClientMessage(getBlockPos(), record, assertNonNull(contents).getAudioTitle(diskStack)));
|
|
||||||
} else {
|
|
||||||
stopRecord();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopRecord() {
|
private void stopRecord() {
|
||||||
playRecord(new PlayRecordClientMessage(getBlockPos()));
|
sendMessage(new PlayRecordClientMessage(getBlockPos()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void playRecord(PlayRecordClientMessage message) {
|
private void sendMessage(PlayRecordClientMessage message) {
|
||||||
PlatformHelper.get().sendToAllAround(message, (ServerLevel) getLevel(), Vec3.atCenterOf(getBlockPos()), 64);
|
PlatformHelper.get().sendToAllAround(message, (ServerLevel) getLevel(), Vec3.atCenterOf(getBlockPos()), 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasCustomName() {
|
protected AbstractContainerMenu createMenu(int id, Inventory inventory) {
|
||||||
return customName != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Component getCustomName() {
|
|
||||||
return customName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getName() {
|
|
||||||
return customName != null ? customName : Component.translatable(getBlockState().getBlock().getDescriptionId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getDisplayName() {
|
|
||||||
return Nameable.super.getDisplayName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
|
|
||||||
return new DiskDriveMenu(id, inventory, this);
|
return new DiskDriveMenu(id, inventory, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPeripheral peripheral() {
|
private enum RecordCommand {
|
||||||
if (peripheral != null) return peripheral;
|
PLAY,
|
||||||
return peripheral = new DiskDrivePeripheral(this);
|
STOP,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.util.StringUtil;
|
import dan200.computercraft.core.util.StringUtil;
|
||||||
import dan200.computercraft.impl.MediaProviders;
|
|
||||||
import dan200.computercraft.shared.media.items.DiskItem;
|
import dan200.computercraft.shared.media.items.DiskItem;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -53,20 +52,20 @@ public String getType() {
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final boolean isDiskPresent() {
|
public final boolean isDiskPresent() {
|
||||||
return !diskDrive.getDiskStack().isEmpty();
|
return !diskDrive.getMedia().stack.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the label of the disk in the drive if available.
|
* Returns the label of the disk in the drive if available.
|
||||||
*
|
*
|
||||||
* @return The label of the disk, or {@code nil} if either no disk is inserted or the disk doesn't have a label.
|
* @return The label of the disk, or {@code nil} if either no disk is inserted or the disk doesn't have a label.
|
||||||
* @cc.treturn string The label of the disk, or {@code nil} if either no disk is inserted or the disk doesn't have a label.
|
* @cc.treturn string|nil The label of the disk, or {@code nil} if either no disk is inserted or the disk doesn't have a label.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final @Nullable Object[] getDiskLabel() {
|
public final Object[] getDiskLabel() {
|
||||||
var stack = diskDrive.getDiskStack();
|
var media = diskDrive.getMedia();
|
||||||
var media = MediaProviders.get(stack);
|
return media.media == null ? null : new Object[]{ media.media.getLabel(media.stack) };
|
||||||
return media == null ? null : new Object[]{ media.getLabel(stack) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,11 +81,11 @@ public final boolean isDiskPresent() {
|
||||||
*/
|
*/
|
||||||
@LuaFunction(mainThread = true)
|
@LuaFunction(mainThread = true)
|
||||||
public final void setDiskLabel(Optional<String> label) throws LuaException {
|
public final void setDiskLabel(Optional<String> label) throws LuaException {
|
||||||
var stack = diskDrive.getDiskStack();
|
var media = diskDrive.getMedia();
|
||||||
var media = MediaProviders.get(stack);
|
if (media.media == null) return;
|
||||||
if (media == null) return;
|
|
||||||
|
|
||||||
if (!media.setLabel(stack, label.map(StringUtil::normaliseLabel).orElse(null))) {
|
var stack = media.stack.copy();
|
||||||
|
if (!media.media.setLabel(stack, label.map(StringUtil::normaliseLabel).orElse(null))) {
|
||||||
throw new LuaException("Disk label cannot be changed");
|
throw new LuaException("Disk label cannot be changed");
|
||||||
}
|
}
|
||||||
diskDrive.setDiskStack(stack);
|
diskDrive.setDiskStack(stack);
|
||||||
|
@ -122,9 +121,7 @@ public final String getMountPath(IComputerAccess computer) {
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final boolean hasAudio() {
|
public final boolean hasAudio() {
|
||||||
var stack = diskDrive.getDiskStack();
|
return diskDrive.getMedia().getAudio() != null;
|
||||||
var media = MediaProviders.get(stack);
|
|
||||||
return media != null && media.getAudio(stack) != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,9 +133,7 @@ public final boolean hasAudio() {
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
@Nullable
|
@Nullable
|
||||||
public final Object getAudioTitle() {
|
public final Object getAudioTitle() {
|
||||||
var stack = diskDrive.getDiskStack();
|
return diskDrive.getMedia().getAudioTitle();
|
||||||
var media = MediaProviders.get(stack);
|
|
||||||
return media != null ? media.getAudioTitle(stack) : false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,12 +166,13 @@ public final void ejectDisk() {
|
||||||
* Returns the ID of the disk inserted in the drive.
|
* Returns the ID of the disk inserted in the drive.
|
||||||
*
|
*
|
||||||
* @return The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted.
|
* @return The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted.
|
||||||
* @cc.treturn number The The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted.
|
* @cc.treturn number|nil The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted.
|
||||||
* @cc.since 1.4
|
* @cc.since 1.4
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final @Nullable Object[] getDiskID() {
|
public final Object[] getDiskID() {
|
||||||
var disk = diskDrive.getDiskStack();
|
var disk = diskDrive.getMedia().stack;
|
||||||
return disk.getItem() instanceof DiskItem ? new Object[]{ DiskItem.getDiskID(disk) } : null;
|
return disk.getItem() instanceof DiskItem ? new Object[]{ DiskItem.getDiskID(disk) } : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.peripheral.diskdrive;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
|
import dan200.computercraft.api.media.IMedia;
|
||||||
|
import dan200.computercraft.impl.MediaProviders;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.sounds.SoundEvent;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An immutable snapshot of the current disk. This allows us to read the stack in a thread-safe manner.
|
||||||
|
*/
|
||||||
|
class MediaStack {
|
||||||
|
static final MediaStack EMPTY = new MediaStack(ItemStack.EMPTY);
|
||||||
|
|
||||||
|
final ItemStack stack;
|
||||||
|
final @Nullable IMedia media;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private IMount mount;
|
||||||
|
|
||||||
|
MediaStack(ItemStack stack) {
|
||||||
|
this.stack = stack;
|
||||||
|
media = MediaProviders.get(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
SoundEvent getAudio() {
|
||||||
|
return media != null ? media.getAudio(stack) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
String getAudioTitle() {
|
||||||
|
return media != null ? media.getAudioTitle(stack) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public IMount getMount(ServerLevel level) {
|
||||||
|
if (media == null) return null;
|
||||||
|
|
||||||
|
if (mount == null) mount = media.createDataMount(stack, level);
|
||||||
|
return mount;
|
||||||
|
}
|
||||||
|
}
|
|
@ -109,7 +109,7 @@ private synchronized void setNetwork(@Nullable IPacketNetwork network) {
|
||||||
if (this.network != null) this.network.addReceiver(this);
|
if (this.network != null) this.network.addReceiver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy() {
|
public void removed() {
|
||||||
setNetwork(null);
|
setNetwork(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,24 +8,30 @@
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import dan200.computercraft.annotations.ForgeOverride;
|
import dan200.computercraft.annotations.ForgeOverride;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
import dan200.computercraft.shared.util.WorldUtil;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
import net.minecraft.world.level.*;
|
import net.minecraft.world.level.*;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
||||||
|
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.level.block.state.properties.EnumProperty;
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
@ -36,7 +42,7 @@
|
||||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
||||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.getFluidStateForPlacement;
|
import static dan200.computercraft.shared.util.WaterloggableHelpers.getFluidStateForPlacement;
|
||||||
|
|
||||||
public class CableBlock extends GenericBlock implements SimpleWaterloggedBlock {
|
public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityBlock {
|
||||||
public static final EnumProperty<CableModemVariant> MODEM = EnumProperty.create("modem", CableModemVariant.class);
|
public static final EnumProperty<CableModemVariant> MODEM = EnumProperty.create("modem", CableModemVariant.class);
|
||||||
public static final BooleanProperty CABLE = BooleanProperty.create("cable");
|
public static final BooleanProperty CABLE = BooleanProperty.create("cable");
|
||||||
|
|
||||||
|
@ -55,7 +61,7 @@ public class CableBlock extends GenericBlock implements SimpleWaterloggedBlock {
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
public CableBlock(Properties settings) {
|
public CableBlock(Properties settings) {
|
||||||
super(settings, ModRegistry.BlockEntities.CABLE);
|
super(settings);
|
||||||
|
|
||||||
registerDefaultState(getStateDefinition().any()
|
registerDefaultState(getStateDefinition().any()
|
||||||
.setValue(MODEM, CableModemVariant.None)
|
.setValue(MODEM, CableModemVariant.None)
|
||||||
|
@ -218,4 +224,33 @@ public static BlockState correctConnections(Level world, BlockPos pos, BlockStat
|
||||||
.setValue(WEST, false).setValue(UP, false).setValue(DOWN, false);
|
.setValue(WEST, false).setValue(UP, false).setValue(DOWN, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
return world.getBlockEntity(pos) instanceof CableBlockEntity modem ? modem.use(player) : InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) {
|
||||||
|
if (world.getBlockEntity(pos) instanceof CableBlockEntity modem) modem.neighborChanged(neighbourPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ForgeOverride
|
||||||
|
public final void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbour) {
|
||||||
|
if (world.getBlockEntity(pos) instanceof CableBlockEntity modem) modem.neighborChanged(neighbour);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
|
||||||
|
if (world.getBlockEntity(pos) instanceof CableBlockEntity modem) modem.blockTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return ModRegistry.BlockEntities.CABLE.get().create(pos, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.command.text.ChatHelpers;
|
import dan200.computercraft.shared.command.text.ChatHelpers;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||||
import dan200.computercraft.shared.platform.ComponentAccess;
|
import dan200.computercraft.shared.platform.ComponentAccess;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
|
@ -22,21 +21,20 @@
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.InteractionHand;
|
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
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.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public class CableBlockEntity extends GenericTile {
|
public class CableBlockEntity extends BlockEntity {
|
||||||
private static final String NBT_PERIPHERAL_ENABLED = "PeirpheralAccess";
|
private static final String NBT_PERIPHERAL_ENABLED = "PeirpheralAccess";
|
||||||
|
|
||||||
private class CableElement extends WiredModemElement {
|
private class CableElement extends WiredModemElement {
|
||||||
|
@ -66,8 +64,6 @@ protected void detachPeripheral(String name) {
|
||||||
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral(this::queueRefreshPeripheral);
|
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral(this::queueRefreshPeripheral);
|
||||||
private @Nullable Runnable modemChanged;
|
private @Nullable Runnable modemChanged;
|
||||||
|
|
||||||
private boolean destroyed = false;
|
|
||||||
|
|
||||||
private boolean connectionsFormed = false;
|
private boolean connectionsFormed = false;
|
||||||
|
|
||||||
private final WiredModemElement cable = new CableElement();
|
private final WiredModemElement cable = new CableElement();
|
||||||
|
@ -106,24 +102,16 @@ private void onRemove() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
if (!destroyed) {
|
|
||||||
destroyed = true;
|
|
||||||
modem.destroy();
|
|
||||||
onRemove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRemoved() {
|
public void setRemoved() {
|
||||||
super.setRemoved();
|
super.setRemoved();
|
||||||
|
modem.removed();
|
||||||
onRemove();
|
onRemove();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearRemoved() {
|
public void clearRemoved() {
|
||||||
super.clearRemoved(); // TODO: Replace with onLoad
|
super.clearRemoved();
|
||||||
TickScheduler.schedule(tickToken);
|
TickScheduler.schedule(tickToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,8 +135,7 @@ private Direction getDirection() {
|
||||||
return direction == null ? Direction.NORTH : direction;
|
return direction == null ? Direction.NORTH : direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void neighborChanged(BlockPos neighbour) {
|
||||||
public void onNeighbourChange(BlockPos neighbour) {
|
|
||||||
var dir = getDirection();
|
var dir = getDirection();
|
||||||
if (neighbour.equals(getBlockPos().relative(dir)) && hasModem() && !getBlockState().canSurvive(getLevel(), getBlockPos())) {
|
if (neighbour.equals(getBlockPos().relative(dir)) && hasModem() && !getBlockState().canSurvive(getLevel(), getBlockPos())) {
|
||||||
if (hasCable()) {
|
if (hasCable()) {
|
||||||
|
@ -167,12 +154,6 @@ public void onNeighbourChange(BlockPos neighbour) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onNeighbourTileEntityChange(neighbour);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
|
||||||
super.onNeighbourTileEntityChange(neighbour);
|
|
||||||
if (!level.isClientSide && peripheralAccessAllowed) {
|
if (!level.isClientSide && peripheralAccessAllowed) {
|
||||||
var facing = getDirection();
|
var facing = getDirection();
|
||||||
if (getBlockPos().relative(facing).equals(neighbour)) queueRefreshPeripheral();
|
if (getBlockPos().relative(facing).equals(neighbour)) queueRefreshPeripheral();
|
||||||
|
@ -192,8 +173,7 @@ private void refreshPeripheral() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
InteractionResult use(Player player) {
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
|
||||||
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
||||||
if (!canAttachPeripheral()) return InteractionResult.FAIL;
|
if (!canAttachPeripheral()) return InteractionResult.FAIL;
|
||||||
|
|
||||||
|
@ -241,8 +221,7 @@ private void updateBlockState() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void blockTick() {
|
||||||
public void blockTick() {
|
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide) return;
|
||||||
|
|
||||||
if (invalidPeripheral) refreshPeripheral();
|
if (invalidPeripheral) refreshPeripheral();
|
||||||
|
@ -331,13 +310,11 @@ private void updateConnectedPeripherals() {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public IWiredElement getWiredElement(@Nullable Direction direction) {
|
public IWiredElement getWiredElement(@Nullable Direction direction) {
|
||||||
if (destroyed) return null;
|
|
||||||
return direction == null || CableBlock.canConnectIn(getBlockState(), direction) ? cable : null;
|
return direction == null || CableBlock.canConnectIn(getBlockState(), direction) ? cable : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
||||||
if (destroyed) return null;
|
|
||||||
return direction == null || getMaybeDirection() == direction ? modem : null;
|
return direction == null || getMaybeDirection() == direction ? modem : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,19 +5,32 @@
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.modem.wired;
|
package dan200.computercraft.shared.peripheral.modem.wired;
|
||||||
|
|
||||||
|
import dan200.computercraft.annotations.ForgeOverride;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.block.Block;
|
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.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;
|
||||||
|
|
||||||
public class WiredModemFullBlock extends GenericBlock {
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public class WiredModemFullBlock extends Block implements EntityBlock {
|
||||||
public static final BooleanProperty MODEM_ON = BooleanProperty.create("modem");
|
public static final BooleanProperty MODEM_ON = BooleanProperty.create("modem");
|
||||||
public static final BooleanProperty PERIPHERAL_ON = BooleanProperty.create("peripheral");
|
public static final BooleanProperty PERIPHERAL_ON = BooleanProperty.create("peripheral");
|
||||||
|
|
||||||
public WiredModemFullBlock(Properties settings) {
|
public WiredModemFullBlock(Properties settings) {
|
||||||
super(settings, ModRegistry.BlockEntities.WIRED_MODEM_FULL);
|
super(settings);
|
||||||
registerDefaultState(getStateDefinition().any()
|
registerDefaultState(getStateDefinition().any()
|
||||||
.setValue(MODEM_ON, false)
|
.setValue(MODEM_ON, false)
|
||||||
.setValue(PERIPHERAL_ON, false)
|
.setValue(PERIPHERAL_ON, false)
|
||||||
|
@ -28,4 +41,33 @@ public WiredModemFullBlock(Properties settings) {
|
||||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||||
builder.add(MODEM_ON, PERIPHERAL_ON);
|
builder.add(MODEM_ON, PERIPHERAL_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
return world.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem ? modem.use(player) : InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final void neighborChanged(BlockState state, Level world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos, boolean isMoving) {
|
||||||
|
if (world.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) modem.neighborChanged(neighbourPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ForgeOverride
|
||||||
|
public final void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbour) {
|
||||||
|
if (world.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) modem.neighborChanged(neighbour);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
|
||||||
|
if (world.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) modem.blockTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return ModRegistry.BlockEntities.WIRED_MODEM_FULL.get().create(pos, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
import dan200.computercraft.api.network.wired.IWiredNode;
|
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.shared.command.text.ChatHelpers;
|
import dan200.computercraft.shared.command.text.ChatHelpers;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||||
import dan200.computercraft.shared.platform.ComponentAccess;
|
import dan200.computercraft.shared.platform.ComponentAccess;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
|
@ -21,13 +20,12 @@
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.InteractionHand;
|
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
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.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.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -36,7 +34,7 @@
|
||||||
import static dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlock.MODEM_ON;
|
import static dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlock.MODEM_ON;
|
||||||
import static dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlock.PERIPHERAL_ON;
|
import static dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlock.PERIPHERAL_ON;
|
||||||
|
|
||||||
public class WiredModemFullBlockEntity extends GenericTile {
|
public class WiredModemFullBlockEntity extends BlockEntity {
|
||||||
private static final String NBT_PERIPHERAL_ENABLED = "PeripheralAccess";
|
private static final String NBT_PERIPHERAL_ENABLED = "PeripheralAccess";
|
||||||
|
|
||||||
private static final class FullElement extends WiredModemElement {
|
private static final class FullElement extends WiredModemElement {
|
||||||
|
@ -78,7 +76,6 @@ public Vec3 getPosition() {
|
||||||
private boolean peripheralAccessAllowed = false;
|
private boolean peripheralAccessAllowed = false;
|
||||||
private final WiredModemLocalPeripheral[] peripherals = new WiredModemLocalPeripheral[6];
|
private final WiredModemLocalPeripheral[] peripherals = new WiredModemLocalPeripheral[6];
|
||||||
|
|
||||||
private boolean destroyed = false;
|
|
||||||
private boolean connectionsFormed = false;
|
private boolean connectionsFormed = false;
|
||||||
|
|
||||||
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
||||||
|
@ -98,35 +95,16 @@ public WiredModemFullBlockEntity(BlockEntityType<WiredModemFullBlockEntity> type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doRemove() {
|
@Override
|
||||||
|
public void setRemoved() {
|
||||||
|
super.setRemoved();
|
||||||
if (level == null || !level.isClientSide) {
|
if (level == null || !level.isClientSide) {
|
||||||
node.remove();
|
node.remove();
|
||||||
connectionsFormed = false;
|
connectionsFormed = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void neighborChanged(BlockPos neighbour) {
|
||||||
public void destroy() {
|
|
||||||
if (!destroyed) {
|
|
||||||
destroyed = true;
|
|
||||||
doRemove();
|
|
||||||
}
|
|
||||||
super.destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setRemoved() {
|
|
||||||
super.setRemoved();
|
|
||||||
doRemove();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNeighbourChange(BlockPos neighbour) {
|
|
||||||
onNeighbourTileEntityChange(neighbour);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
|
||||||
if (!level.isClientSide && peripheralAccessAllowed) {
|
if (!level.isClientSide && peripheralAccessAllowed) {
|
||||||
for (var facing : DirectionUtil.FACINGS) {
|
for (var facing : DirectionUtil.FACINGS) {
|
||||||
if (getBlockPos().relative(facing).equals(neighbour)) queueRefreshPeripheral(facing);
|
if (getBlockPos().relative(facing).equals(neighbour)) queueRefreshPeripheral(facing);
|
||||||
|
@ -147,8 +125,7 @@ private void refreshPeripheral(Direction facing) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public InteractionResult use(Player player) {
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
|
||||||
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
||||||
if (getLevel().isClientSide) return InteractionResult.SUCCESS;
|
if (getLevel().isClientSide) return InteractionResult.SUCCESS;
|
||||||
|
|
||||||
|
@ -204,12 +181,11 @@ private void updateBlockState() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearRemoved() {
|
public void clearRemoved() {
|
||||||
super.clearRemoved(); // TODO: Replace with onLoad
|
super.clearRemoved();
|
||||||
TickScheduler.schedule(tickToken);
|
TickScheduler.schedule(tickToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void blockTick() {
|
||||||
public void blockTick() {
|
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide) return;
|
||||||
|
|
||||||
if (invalidSides != 0) {
|
if (invalidSides != 0) {
|
||||||
|
@ -288,7 +264,7 @@ private Map<String, IPeripheral> getConnectedPeripherals() {
|
||||||
|
|
||||||
Map<String, IPeripheral> peripherals = new HashMap<>(6);
|
Map<String, IPeripheral> peripherals = new HashMap<>(6);
|
||||||
for (var peripheral : this.peripherals) peripheral.extendMap(peripherals);
|
for (var peripheral : this.peripherals) peripheral.extendMap(peripherals);
|
||||||
return peripherals;
|
return Collections.unmodifiableMap(peripherals);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateConnectedPeripherals() {
|
private void updateConnectedPeripherals() {
|
||||||
|
|
|
@ -219,6 +219,7 @@ public final MethodResult callRemote(IComputerAccess computer, ILuaContext conte
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
|
||||||
public void attach(IComputerAccess computer) {
|
public void attach(IComputerAccess computer) {
|
||||||
super.attach(computer);
|
super.attach(computer);
|
||||||
|
|
||||||
|
@ -236,6 +237,7 @@ public void attach(IComputerAccess computer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
|
||||||
public void detach(IComputerAccess computer) {
|
public void detach(IComputerAccess computer) {
|
||||||
Map<String, RemotePeripheralWrapper> wrappers;
|
Map<String, RemotePeripheralWrapper> wrappers;
|
||||||
synchronized (peripheralWrappers) {
|
synchronized (peripheralWrappers) {
|
||||||
|
|
|
@ -5,26 +5,23 @@
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.modem.wireless;
|
package dan200.computercraft.shared.peripheral.modem.wireless;
|
||||||
|
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
|
||||||
import dan200.computercraft.shared.peripheral.modem.ModemShapes;
|
import dan200.computercraft.shared.peripheral.modem.ModemShapes;
|
||||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||||
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.LevelReader;
|
import net.minecraft.world.level.LevelReader;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.*;
|
||||||
import net.minecraft.world.level.block.Mirror;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.Rotation;
|
|
||||||
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
|
||||||
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.minecraft.world.level.block.state.StateDefinition;
|
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.BooleanProperty;
|
||||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
@ -34,12 +31,15 @@
|
||||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
||||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.getFluidStateForPlacement;
|
import static dan200.computercraft.shared.util.WaterloggableHelpers.getFluidStateForPlacement;
|
||||||
|
|
||||||
public class WirelessModemBlock extends GenericBlock implements SimpleWaterloggedBlock {
|
public class WirelessModemBlock extends DirectionalBlock implements SimpleWaterloggedBlock, EntityBlock {
|
||||||
public static final DirectionProperty FACING = BlockStateProperties.FACING;
|
|
||||||
public static final BooleanProperty ON = BooleanProperty.create("on");
|
public static final BooleanProperty ON = BooleanProperty.create("on");
|
||||||
|
|
||||||
|
private final RegistryEntry<? extends BlockEntityType<? extends WirelessModemBlockEntity>> type;
|
||||||
|
|
||||||
public WirelessModemBlock(Properties settings, RegistryEntry<? extends BlockEntityType<? extends WirelessModemBlockEntity>> type) {
|
public WirelessModemBlock(Properties settings, RegistryEntry<? extends BlockEntityType<? extends WirelessModemBlockEntity>> type) {
|
||||||
super(settings, type);
|
super(settings);
|
||||||
|
this.type = type;
|
||||||
|
|
||||||
registerDefaultState(getStateDefinition().any()
|
registerDefaultState(getStateDefinition().any()
|
||||||
.setValue(FACING, Direction.NORTH)
|
.setValue(FACING, Direction.NORTH)
|
||||||
.setValue(ON, false)
|
.setValue(ON, false)
|
||||||
|
@ -98,4 +98,17 @@ public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
||||||
public BlockState rotate(BlockState state, Rotation rot) {
|
public BlockState rotate(BlockState state, Rotation rot) {
|
||||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource rand) {
|
||||||
|
var te = level.getBlockEntity(pos);
|
||||||
|
if (te instanceof WirelessModemBlockEntity modem) modem.blockTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
|
||||||
|
return type.get().create(blockPos, blockState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,20 +6,20 @@
|
||||||
package dan200.computercraft.shared.peripheral.modem.wireless;
|
package dan200.computercraft.shared.peripheral.modem.wireless;
|
||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
|
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
|
||||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||||
import dan200.computercraft.shared.util.TickScheduler;
|
import dan200.computercraft.shared.util.TickScheduler;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
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.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.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class WirelessModemBlockEntity extends GenericTile {
|
public class WirelessModemBlockEntity extends BlockEntity {
|
||||||
private static class Peripheral extends WirelessModemPeripheral {
|
private static class Peripheral extends WirelessModemPeripheral {
|
||||||
private final WirelessModemBlockEntity entity;
|
private final WirelessModemBlockEntity entity;
|
||||||
|
|
||||||
|
@ -52,7 +52,6 @@ public Object getTarget() {
|
||||||
private final boolean advanced;
|
private final boolean advanced;
|
||||||
|
|
||||||
private final ModemPeripheral modem;
|
private final ModemPeripheral modem;
|
||||||
private boolean destroyed = false;
|
|
||||||
private @Nullable Runnable modemChanged;
|
private @Nullable Runnable modemChanged;
|
||||||
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
||||||
|
|
||||||
|
@ -63,17 +62,15 @@ public WirelessModemBlockEntity(BlockEntityType<? extends WirelessModemBlockEnti
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearRemoved() {
|
public void setRemoved() {
|
||||||
super.clearRemoved(); // TODO: Replace with onLoad
|
super.setRemoved();
|
||||||
TickScheduler.schedule(tickToken);
|
modem.removed();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void clearRemoved() {
|
||||||
if (!destroyed) {
|
super.clearRemoved();
|
||||||
modem.destroy();
|
TickScheduler.schedule(tickToken);
|
||||||
destroyed = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -84,8 +81,7 @@ public void setBlockState(BlockState state) {
|
||||||
if (getDirection() != direction && modemChanged != null) modemChanged.run();
|
if (getDirection() != direction && modemChanged != null) modemChanged.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void blockTick() {
|
||||||
public void blockTick() {
|
|
||||||
if (modem.getModemState().pollChanged()) updateBlockState();
|
if (modem.getModemState().pollChanged()) updateBlockState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +99,6 @@ private void updateBlockState() {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
||||||
if (destroyed) return null;
|
|
||||||
return direction == null || getDirection() == direction ? modem : null;
|
return direction == null || getDirection() == direction ? modem : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,38 +5,47 @@
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.monitor;
|
package dan200.computercraft.shared.peripheral.monitor;
|
||||||
|
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
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;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Mirror;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.block.Rotation;
|
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||||
|
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.minecraft.world.level.block.state.StateDefinition;
|
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.BlockStateProperties;
|
||||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class MonitorBlock extends GenericBlock {
|
public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBlock {
|
||||||
public static final DirectionProperty ORIENTATION = DirectionProperty.create("orientation",
|
public static final DirectionProperty ORIENTATION = DirectionProperty.create("orientation",
|
||||||
Direction.UP, Direction.DOWN, Direction.NORTH);
|
Direction.UP, Direction.DOWN, Direction.NORTH);
|
||||||
|
|
||||||
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||||
|
|
||||||
public static final EnumProperty<MonitorEdgeState> STATE = EnumProperty.create("state", MonitorEdgeState.class);
|
public static final EnumProperty<MonitorEdgeState> STATE = EnumProperty.create("state", MonitorEdgeState.class);
|
||||||
|
|
||||||
|
private final RegistryEntry<? extends BlockEntityType<? extends MonitorBlockEntity>> type;
|
||||||
|
|
||||||
public MonitorBlock(Properties settings, RegistryEntry<? extends BlockEntityType<? extends MonitorBlockEntity>> type) {
|
public MonitorBlock(Properties settings, RegistryEntry<? extends BlockEntityType<? extends MonitorBlockEntity>> type) {
|
||||||
super(settings, type);
|
super(settings);
|
||||||
|
this.type = type;
|
||||||
|
|
||||||
// TODO: Test underwater - do we need isSolid at all?
|
// TODO: Test underwater - do we need isSolid at all?
|
||||||
registerDefaultState(getStateDefinition().any()
|
registerDefaultState(getStateDefinition().any()
|
||||||
.setValue(ORIENTATION, Direction.NORTH)
|
.setValue(ORIENTATION, Direction.NORTH)
|
||||||
|
@ -49,18 +58,6 @@ protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockSt
|
||||||
builder.add(ORIENTATION, FACING, STATE);
|
builder.add(ORIENTATION, FACING, STATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
|
||||||
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState rotate(BlockState state, Rotation rot) {
|
|
||||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||||
|
@ -81,6 +78,41 @@ public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||||
.setValue(ORIENTATION, orientation);
|
.setValue(ORIENTATION, orientation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final void onRemove(BlockState block, Level world, BlockPos pos, BlockState replace, boolean bool) {
|
||||||
|
if (block.getBlock() == replace.getBlock()) return;
|
||||||
|
|
||||||
|
var tile = world.getBlockEntity(pos);
|
||||||
|
super.onRemove(block, world, pos, replace, bool);
|
||||||
|
if (tile instanceof MonitorBlockEntity generic) generic.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
|
||||||
|
var te = world.getBlockEntity(pos);
|
||||||
|
if (te instanceof MonitorBlockEntity monitor) monitor.blockTick();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
if (player.isCrouching() || !(level.getBlockEntity(pos) instanceof MonitorBlockEntity monitor) || monitor.getFront() != hit.getDirection()) {
|
||||||
|
return InteractionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!level.isClientSide) {
|
||||||
|
monitor.monitorTouched(
|
||||||
|
(float) (hit.getLocation().x - hit.getBlockPos().getX()),
|
||||||
|
(float) (hit.getLocation().y - hit.getBlockPos().getY()),
|
||||||
|
(float) (hit.getLocation().z - hit.getBlockPos().getZ())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return InteractionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlacedBy(Level world, BlockPos pos, BlockState blockState, @Nullable LivingEntity livingEntity, ItemStack itemStack) {
|
public void setPlacedBy(Level world, BlockPos pos, BlockState blockState, @Nullable LivingEntity livingEntity, ItemStack itemStack) {
|
||||||
super.setPlacedBy(world, pos, blockState, livingEntity, itemStack);
|
super.setPlacedBy(world, pos, blockState, livingEntity, itemStack);
|
||||||
|
@ -96,4 +128,10 @@ public void setPlacedBy(Level world, BlockPos pos, BlockState blockState, @Nulla
|
||||||
monitor.expand();
|
monitor.expand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
|
||||||
|
return type.get().create(blockPos, blockState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,21 +10,18 @@
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||||
import dan200.computercraft.shared.config.Config;
|
import dan200.computercraft.shared.config.Config;
|
||||||
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
import dan200.computercraft.shared.util.TickScheduler;
|
import dan200.computercraft.shared.util.TickScheduler;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
import net.minecraft.world.InteractionHand;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.InteractionResult;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
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.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -33,7 +30,7 @@
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class MonitorBlockEntity extends GenericTile {
|
public class MonitorBlockEntity extends BlockEntity {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(MonitorBlockEntity.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MonitorBlockEntity.class);
|
||||||
|
|
||||||
public static final double RENDER_BORDER = 2.0 / 16.0;
|
public static final double RENDER_BORDER = 2.0 / 16.0;
|
||||||
|
@ -79,17 +76,14 @@ public MonitorBlockEntity(BlockEntityType<? extends MonitorBlockEntity> type, Bl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearRemoved() { // TODO: Switch back to onLood
|
public void clearRemoved() {
|
||||||
super.clearRemoved();
|
super.clearRemoved();
|
||||||
needsValidating = true; // Same, tbh
|
needsValidating = true; // Same, tbh
|
||||||
TickScheduler.schedule(tickToken);
|
TickScheduler.schedule(tickToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void destroy() {
|
||||||
public void destroy() {
|
|
||||||
// TODO: Call this before using the block
|
// TODO: Call this before using the block
|
||||||
if (destroyed) return;
|
|
||||||
destroyed = true;
|
|
||||||
if (!getLevel().isClientSide) contractNeighbours();
|
if (!getLevel().isClientSide) contractNeighbours();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,22 +93,6 @@ public void setRemoved() {
|
||||||
if (clientMonitor != null && xIndex == 0 && yIndex == 0) clientMonitor.destroy();
|
if (clientMonitor != null && xIndex == 0 && yIndex == 0) clientMonitor.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
|
||||||
if (!player.isCrouching() && getFront() == hit.getDirection()) {
|
|
||||||
if (!getLevel().isClientSide) {
|
|
||||||
monitorTouched(
|
|
||||||
(float) (hit.getLocation().x - hit.getBlockPos().getX()),
|
|
||||||
(float) (hit.getLocation().y - hit.getBlockPos().getY()),
|
|
||||||
(float) (hit.getLocation().z - hit.getBlockPos().getZ())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return InteractionResult.SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return InteractionResult.PASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveAdditional(CompoundTag tag) {
|
public void saveAdditional(CompoundTag tag) {
|
||||||
tag.putInt(NBT_X, xIndex);
|
tag.putInt(NBT_X, xIndex);
|
||||||
|
@ -128,14 +106,18 @@ public void saveAdditional(CompoundTag tag) {
|
||||||
public void load(CompoundTag nbt) {
|
public void load(CompoundTag nbt) {
|
||||||
super.load(nbt);
|
super.load(nbt);
|
||||||
|
|
||||||
|
var oldXIndex = xIndex;
|
||||||
|
var oldYIndex = yIndex;
|
||||||
|
|
||||||
xIndex = nbt.getInt(NBT_X);
|
xIndex = nbt.getInt(NBT_X);
|
||||||
yIndex = nbt.getInt(NBT_Y);
|
yIndex = nbt.getInt(NBT_Y);
|
||||||
width = nbt.getInt(NBT_WIDTH);
|
width = nbt.getInt(NBT_WIDTH);
|
||||||
height = nbt.getInt(NBT_HEIGHT);
|
height = nbt.getInt(NBT_HEIGHT);
|
||||||
|
|
||||||
|
if (level != null && level.isClientSide) onClientLoad(oldXIndex, oldYIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void blockTick() {
|
||||||
public void blockTick() {
|
|
||||||
if (needsValidating) {
|
if (needsValidating) {
|
||||||
needsValidating = false;
|
needsValidating = false;
|
||||||
validate();
|
validate();
|
||||||
|
@ -223,18 +205,7 @@ public final CompoundTag getUpdateTag() {
|
||||||
return nbt;
|
return nbt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private void onClientLoad(int oldXIndex, int oldYIndex) {
|
||||||
public final void handleUpdateTag(CompoundTag nbt) {
|
|
||||||
super.handleUpdateTag(nbt);
|
|
||||||
|
|
||||||
var oldXIndex = xIndex;
|
|
||||||
var oldYIndex = yIndex;
|
|
||||||
|
|
||||||
xIndex = nbt.getInt(NBT_X);
|
|
||||||
yIndex = nbt.getInt(NBT_Y);
|
|
||||||
width = nbt.getInt(NBT_WIDTH);
|
|
||||||
height = nbt.getInt(NBT_HEIGHT);
|
|
||||||
|
|
||||||
if (oldXIndex != xIndex || oldYIndex != yIndex) {
|
if (oldXIndex != xIndex || oldYIndex != yIndex) {
|
||||||
// If our index has changed then it's possible the origin monitor has changed. Thus
|
// If our index has changed then it's possible the origin monitor has changed. Thus
|
||||||
// we'll clear our cache. If we're the origin then we'll need to remove the glList as well.
|
// we'll clear our cache. If we're the origin then we'll need to remove the glList as well.
|
||||||
|
@ -401,7 +372,7 @@ void resize(int width, int height) {
|
||||||
monitor.serverMonitor = serverMonitor;
|
monitor.serverMonitor = serverMonitor;
|
||||||
monitor.needsUpdate = monitor.needsValidating = false;
|
monitor.needsUpdate = monitor.needsValidating = false;
|
||||||
monitor.updateBlockState();
|
monitor.updateBlockState();
|
||||||
monitor.updateBlock();
|
BlockEntityHelpers.updateBlock(monitor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -476,7 +447,7 @@ private void validate() {
|
||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
private void monitorTouched(float xPos, float yPos, float zPos) {
|
void monitorTouched(float xPos, float yPos, float zPos) {
|
||||||
if (!advanced) return;
|
if (!advanced) return;
|
||||||
|
|
||||||
var pair = XYPair
|
var pair = XYPair
|
||||||
|
|
|
@ -34,11 +34,11 @@ synchronized void rebuild() {
|
||||||
|
|
||||||
var textScale = this.textScale * 0.5;
|
var textScale = this.textScale * 0.5;
|
||||||
var termWidth = (int) Math.max(
|
var termWidth = (int) Math.max(
|
||||||
Math.round((origin.getWidth() - 2.0 * (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN)) / (textScale * 6.0 * MonitorBlockEntity.RENDER_PIXEL_SCALE)),
|
(double) Math.round((origin.getWidth() - 2.0 * (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN)) / (textScale * 6.0 * MonitorBlockEntity.RENDER_PIXEL_SCALE)),
|
||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
var termHeight = (int) Math.max(
|
var termHeight = (int) Math.max(
|
||||||
Math.round((origin.getHeight() - 2.0 * (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN)) / (textScale * 9.0 * MonitorBlockEntity.RENDER_PIXEL_SCALE)),
|
(double) Math.round((origin.getHeight() - 2.0 * (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN)) / (textScale * 9.0 * MonitorBlockEntity.RENDER_PIXEL_SCALE)),
|
||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -6,35 +6,23 @@
|
||||||
package dan200.computercraft.shared.peripheral.printer;
|
package dan200.computercraft.shared.peripheral.printer;
|
||||||
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
import dan200.computercraft.shared.common.HorizontalContainerBlock;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.stats.Stats;
|
|
||||||
import net.minecraft.world.Nameable;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Mirror;
|
|
||||||
import net.minecraft.world.level.block.Rotation;
|
|
||||||
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.StateDefinition;
|
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.BooleanProperty;
|
||||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class PrinterBlock extends GenericBlock {
|
public class PrinterBlock extends HorizontalContainerBlock {
|
||||||
private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
|
||||||
public static final BooleanProperty TOP = BooleanProperty.create("top");
|
public static final BooleanProperty TOP = BooleanProperty.create("top");
|
||||||
public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom");
|
public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom");
|
||||||
|
|
||||||
public PrinterBlock(Properties settings) {
|
public PrinterBlock(Properties settings) {
|
||||||
super(settings, ModRegistry.BlockEntities.PRINTER);
|
super(settings);
|
||||||
registerDefaultState(getStateDefinition().any()
|
registerDefaultState(getStateDefinition().any()
|
||||||
.setValue(FACING, Direction.NORTH)
|
.setValue(FACING, Direction.NORTH)
|
||||||
.setValue(TOP, false)
|
.setValue(TOP, false)
|
||||||
|
@ -46,42 +34,9 @@ protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockSt
|
||||||
properties.add(FACING, TOP, BOTTOM);
|
properties.add(FACING, TOP, BOTTOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
|
||||||
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState rotate(BlockState state, Rotation rot) {
|
|
||||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite());
|
return ModRegistry.BlockEntities.PRINTER.get().create(pos, state);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void playerDestroy(Level world, Player player, BlockPos pos, BlockState state, @Nullable BlockEntity te, ItemStack stack) {
|
|
||||||
if (te instanceof Nameable nameable && nameable.hasCustomName()) {
|
|
||||||
player.awardStat(Stats.BLOCK_MINED.get(this));
|
|
||||||
player.causeFoodExhaustion(0.005F);
|
|
||||||
|
|
||||||
var result = new ItemStack(this);
|
|
||||||
result.setHoverName(nameable.getCustomName());
|
|
||||||
popResource(world, pos, result);
|
|
||||||
} else {
|
|
||||||
super.playerDestroy(world, player, pos, state, te, stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
|
|
||||||
if (stack.hasCustomHoverName() && world.getBlockEntity(pos) instanceof PrinterBlockEntity printer) {
|
|
||||||
printer.customName = stack.getHoverName();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,34 +6,26 @@
|
||||||
package dan200.computercraft.shared.peripheral.printer;
|
package dan200.computercraft.shared.peripheral.printer;
|
||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.shared.common.AbstractContainerBlockEntity;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||||
|
import dan200.computercraft.shared.container.BasicWorldlyContainer;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||||
import dan200.computercraft.shared.util.ColourUtils;
|
import dan200.computercraft.shared.util.ColourUtils;
|
||||||
import dan200.computercraft.shared.util.DefaultSidedInventory;
|
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.world.ContainerHelper;
|
||||||
import net.minecraft.world.*;
|
|
||||||
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.inventory.AbstractContainerMenu;
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
|
||||||
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.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public final class PrinterBlockEntity extends GenericTile implements DefaultSidedInventory, Nameable, MenuProvider {
|
public final class PrinterBlockEntity extends AbstractContainerBlockEntity implements BasicWorldlyContainer {
|
||||||
private static final String NBT_NAME = "CustomName";
|
|
||||||
private static final String NBT_PRINTING = "Printing";
|
private static final String NBT_PRINTING = "Printing";
|
||||||
private static final String NBT_PAGE_TITLE = "PageTitle";
|
private static final String NBT_PAGE_TITLE = "PageTitle";
|
||||||
|
|
||||||
|
@ -43,12 +35,8 @@ public final class PrinterBlockEntity extends GenericTile implements DefaultSide
|
||||||
private static final int[] TOP_SLOTS = new int[]{ 1, 2, 3, 4, 5, 6 };
|
private static final int[] TOP_SLOTS = new int[]{ 1, 2, 3, 4, 5, 6 };
|
||||||
private static final int[] SIDE_SLOTS = new int[]{ 0 };
|
private static final int[] SIDE_SLOTS = new int[]{ 0 };
|
||||||
|
|
||||||
@Nullable
|
private final PrinterPeripheral peripheral = new PrinterPeripheral(this);
|
||||||
Component customName;
|
|
||||||
private LockCode lockCode = LockCode.NO_LOCK;
|
|
||||||
|
|
||||||
private final NonNullList<ItemStack> inventory = NonNullList.withSize(SLOTS, ItemStack.EMPTY);
|
private final NonNullList<ItemStack> inventory = NonNullList.withSize(SLOTS, ItemStack.EMPTY);
|
||||||
private @Nullable IPeripheral peripheral;
|
|
||||||
|
|
||||||
private final NetworkedTerminal page = new NetworkedTerminal(PrintoutItem.LINE_MAX_LENGTH, PrintoutItem.LINES_PER_PAGE, true);
|
private final NetworkedTerminal page = new NetworkedTerminal(PrintoutItem.LINE_MAX_LENGTH, PrintoutItem.LINES_PER_PAGE, true);
|
||||||
private String pageTitle = "";
|
private String pageTitle = "";
|
||||||
|
@ -58,30 +46,14 @@ public PrinterBlockEntity(BlockEntityType<PrinterBlockEntity> type, BlockPos pos
|
||||||
super(type, pos, state);
|
super(type, pos, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public IPeripheral peripheral() {
|
||||||
public void destroy() {
|
return peripheral;
|
||||||
ejectContents();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isUsable(Player player) {
|
|
||||||
return super.isUsable(player) && BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
|
||||||
if (player.isCrouching()) return InteractionResult.PASS;
|
|
||||||
|
|
||||||
if (!getLevel().isClientSide && isUsable(player)) player.openMenu(this);
|
|
||||||
return InteractionResult.SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(CompoundTag nbt) {
|
public void load(CompoundTag nbt) {
|
||||||
super.load(nbt);
|
super.load(nbt);
|
||||||
|
|
||||||
customName = nbt.contains(NBT_NAME) ? Component.Serializer.fromJson(nbt.getString(NBT_NAME)) : null;
|
|
||||||
|
|
||||||
// Read page
|
// Read page
|
||||||
synchronized (page) {
|
synchronized (page) {
|
||||||
printing = nbt.getBoolean(NBT_PRINTING);
|
printing = nbt.getBoolean(NBT_PRINTING);
|
||||||
|
@ -91,91 +63,35 @@ public void load(CompoundTag nbt) {
|
||||||
|
|
||||||
// Read inventory
|
// Read inventory
|
||||||
ContainerHelper.loadAllItems(nbt, inventory);
|
ContainerHelper.loadAllItems(nbt, inventory);
|
||||||
|
|
||||||
lockCode = LockCode.fromTag(nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void saveAdditional(CompoundTag nbt) {
|
public void saveAdditional(CompoundTag tag) {
|
||||||
if (customName != null) nbt.putString(NBT_NAME, Component.Serializer.toJson(customName));
|
|
||||||
|
|
||||||
// Write page
|
// Write page
|
||||||
synchronized (page) {
|
synchronized (page) {
|
||||||
nbt.putBoolean(NBT_PRINTING, printing);
|
tag.putBoolean(NBT_PRINTING, printing);
|
||||||
nbt.putString(NBT_PAGE_TITLE, pageTitle);
|
tag.putString(NBT_PAGE_TITLE, pageTitle);
|
||||||
page.writeToNBT(nbt);
|
page.writeToNBT(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write inventory
|
// Write inventory
|
||||||
ContainerHelper.saveAllItems(nbt, inventory);
|
ContainerHelper.saveAllItems(tag, inventory);
|
||||||
|
|
||||||
lockCode.addToTag(nbt);
|
super.saveAdditional(tag);
|
||||||
|
|
||||||
super.saveAdditional(nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isPrinting() {
|
boolean isPrinting() {
|
||||||
return printing;
|
return printing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// IInventory implementation
|
|
||||||
@Override
|
@Override
|
||||||
public int getContainerSize() {
|
public NonNullList<ItemStack> getContents() {
|
||||||
return inventory.size();
|
return inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isEmpty() {
|
public void setChanged() {
|
||||||
for (var stack : inventory) {
|
super.setChanged();
|
||||||
if (!stack.isEmpty()) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack getItem(int slot) {
|
|
||||||
return inventory.get(slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack removeItemNoUpdate(int slot) {
|
|
||||||
var result = inventory.get(slot);
|
|
||||||
inventory.set(slot, ItemStack.EMPTY);
|
|
||||||
setChanged();
|
|
||||||
updateBlockState();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack removeItem(int slot, int count) {
|
|
||||||
var stack = inventory.get(slot);
|
|
||||||
if (stack.isEmpty()) return ItemStack.EMPTY;
|
|
||||||
|
|
||||||
if (stack.getCount() <= count) {
|
|
||||||
setItem(slot, ItemStack.EMPTY);
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
var part = stack.split(count);
|
|
||||||
if (inventory.get(slot).isEmpty()) {
|
|
||||||
inventory.set(slot, ItemStack.EMPTY);
|
|
||||||
updateBlockState();
|
|
||||||
}
|
|
||||||
setChanged();
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(int slot, ItemStack stack) {
|
|
||||||
inventory.set(slot, stack);
|
|
||||||
setChanged();
|
|
||||||
updateBlockState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearContent() {
|
|
||||||
for (var i = 0; i < inventory.size(); i++) inventory.set(i, ItemStack.EMPTY);
|
|
||||||
setChanged();
|
|
||||||
updateBlockState();
|
updateBlockState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,24 +106,17 @@ public boolean canPlaceItem(int slot, ItemStack stack) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean stillValid(Player playerEntity) {
|
|
||||||
return isUsable(playerEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ISidedInventory implementation
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[] getSlotsForFace(Direction side) {
|
public int[] getSlotsForFace(Direction side) {
|
||||||
return switch (side) {
|
return switch (side) {
|
||||||
case DOWN -> BOTTOM_SLOTS; // Out tray
|
case DOWN -> BOTTOM_SLOTS; // Bottom (Out tray)
|
||||||
case UP -> TOP_SLOTS; // In tray
|
case UP -> TOP_SLOTS; // Top (In tray)
|
||||||
default -> SIDE_SLOTS; // Ink
|
default -> SIDE_SLOTS; // Sides (Ink)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
Terminal getCurrentPage() {
|
NetworkedTerminal getCurrentPage() {
|
||||||
synchronized (page) {
|
synchronized (page) {
|
||||||
return printing ? page : null;
|
return printing ? page : null;
|
||||||
}
|
}
|
||||||
|
@ -325,19 +234,6 @@ private boolean outputPage() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ejectContents() {
|
|
||||||
for (var i = 0; i < 13; i++) {
|
|
||||||
var stack = inventory.get(i);
|
|
||||||
if (!stack.isEmpty()) {
|
|
||||||
// Remove the stack from the inventory
|
|
||||||
setItem(i, ItemStack.EMPTY);
|
|
||||||
|
|
||||||
// Spawn the item in the world
|
|
||||||
WorldUtil.dropItemStack(stack, getLevel(), Vec3.atLowerCornerOf(getBlockPos()).add(0.5, 0.75, 0.5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBlockState() {
|
private void updateBlockState() {
|
||||||
boolean top = false, bottom = false;
|
boolean top = false, bottom = false;
|
||||||
for (var i = 1; i < 7; i++) {
|
for (var i = 1; i < 7; i++) {
|
||||||
|
@ -367,34 +263,8 @@ private void updateBlockState(boolean top, boolean bottom) {
|
||||||
getLevel().setBlockAndUpdate(getBlockPos(), state.setValue(PrinterBlock.TOP, top).setValue(PrinterBlock.BOTTOM, bottom));
|
getLevel().setBlockAndUpdate(getBlockPos(), state.setValue(PrinterBlock.TOP, top).setValue(PrinterBlock.BOTTOM, bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPeripheral peripheral() {
|
|
||||||
if (peripheral == null) peripheral = new PrinterPeripheral(this);
|
|
||||||
return peripheral;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasCustomName() {
|
protected AbstractContainerMenu createMenu(int id, Inventory inventory) {
|
||||||
return customName != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public Component getCustomName() {
|
|
||||||
return customName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getName() {
|
|
||||||
return customName != null ? customName : Component.translatable(getBlockState().getBlock().getDescriptionId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getDisplayName() {
|
|
||||||
return Nameable.super.getDisplayName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AbstractContainerMenu createMenu(int id, Inventory inventory, Player player) {
|
|
||||||
return new PrinterMenu(id, inventory, this);
|
return new PrinterMenu(id, inventory, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
package dan200.computercraft.shared.peripheral.printer;
|
package dan200.computercraft.shared.peripheral.printer;
|
||||||
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.util.SingleIntArray;
|
import dan200.computercraft.shared.container.SingleContainerData;
|
||||||
import dan200.computercraft.shared.util.ValidatingSlot;
|
import dan200.computercraft.shared.container.ValidatingSlot;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.SimpleContainer;
|
import net.minecraft.world.SimpleContainer;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
@ -58,7 +58,7 @@ public PrinterMenu(int id, Inventory player) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public PrinterMenu(int id, Inventory player, PrinterBlockEntity printer) {
|
public PrinterMenu(int id, Inventory player, PrinterBlockEntity printer) {
|
||||||
this(id, player, printer, (SingleIntArray) () -> printer.isPrinting() ? 1 : 0);
|
this(id, player, printer, (SingleContainerData) () -> printer.isPrinting() ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPrinting() {
|
public boolean isPrinting() {
|
||||||
|
|
|
@ -6,31 +6,27 @@
|
||||||
package dan200.computercraft.shared.peripheral.speaker;
|
package dan200.computercraft.shared.peripheral.speaker;
|
||||||
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.GenericBlock;
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
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;
|
||||||
import net.minecraft.world.level.block.BaseEntityBlock;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.Mirror;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
import net.minecraft.world.level.block.Rotation;
|
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
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.minecraft.world.level.block.state.StateDefinition;
|
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 javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class SpeakerBlock extends GenericBlock {
|
public class SpeakerBlock extends HorizontalDirectionalBlock implements EntityBlock {
|
||||||
private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
|
||||||
|
|
||||||
private static final BlockEntityTicker<SpeakerBlockEntity> serverTicker = (level, pos, state, drive) -> drive.serverTick();
|
private static final BlockEntityTicker<SpeakerBlockEntity> serverTicker = (level, pos, state, drive) -> drive.serverTick();
|
||||||
|
|
||||||
public SpeakerBlock(Properties settings) {
|
public SpeakerBlock(Properties settings) {
|
||||||
super(settings, ModRegistry.BlockEntities.SPEAKER);
|
super(settings);
|
||||||
registerDefaultState(getStateDefinition().any()
|
registerDefaultState(getStateDefinition().any()
|
||||||
.setValue(FACING, Direction.NORTH));
|
.setValue(FACING, Direction.NORTH));
|
||||||
}
|
}
|
||||||
|
@ -40,18 +36,6 @@ protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockSt
|
||||||
properties.add(FACING);
|
properties.add(FACING);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
|
||||||
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState rotate(BlockState state, Rotation rot) {
|
|
||||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
||||||
|
@ -61,6 +45,12 @@ public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
return level.isClientSide ? null : BaseEntityBlock.createTickerHelper(type, ModRegistry.BlockEntities.SPEAKER.get(), serverTicker);
|
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.SPEAKER.get(), serverTicker);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||||
|
return ModRegistry.BlockEntities.SPEAKER.get().create(pos, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,17 +7,17 @@
|
||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.util.Nullability;
|
import dan200.computercraft.core.util.Nullability;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
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.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class SpeakerBlockEntity extends GenericTile {
|
public class SpeakerBlockEntity extends BlockEntity {
|
||||||
private final SpeakerPeripheral peripheral;
|
private final SpeakerPeripheral peripheral;
|
||||||
|
|
||||||
public SpeakerBlockEntity(BlockEntityType<SpeakerBlockEntity> type, BlockPos pos, BlockState state) {
|
public SpeakerBlockEntity(BlockEntityType<SpeakerBlockEntity> type, BlockPos pos, BlockState state) {
|
||||||
|
|
|
@ -15,9 +15,11 @@
|
||||||
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
||||||
import dan200.computercraft.shared.turtle.items.ITurtleItem;
|
import dan200.computercraft.shared.turtle.items.ITurtleItem;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
|
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
|
||||||
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.Containers;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
||||||
|
@ -27,7 +29,9 @@
|
||||||
import net.minecraft.world.level.Explosion;
|
import net.minecraft.world.level.Explosion;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.block.*;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
import net.minecraft.world.level.block.RenderShape;
|
||||||
|
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
@ -69,18 +73,6 @@ protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockSt
|
||||||
builder.add(FACING, WATERLOGGED);
|
builder.add(FACING, WATERLOGGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
|
||||||
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Deprecated
|
|
||||||
public BlockState rotate(BlockState state, Rotation rot) {
|
|
||||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public RenderShape getRenderShape(BlockState state) {
|
public RenderShape getRenderShape(BlockState state) {
|
||||||
|
@ -116,6 +108,19 @@ public BlockState updateShape(BlockState state, Direction side, BlockState other
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public final void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||||
|
if (state.is(newState.getBlock())) return;
|
||||||
|
|
||||||
|
if (level.getBlockEntity(pos) instanceof TurtleBlockEntity turtle) {
|
||||||
|
if (!level.isClientSide) Containers.dropContents(level, pos, turtle);
|
||||||
|
level.updateNeighbourForOutputSignal(pos, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onRemove(state, level, pos, newState, isMoving);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
||||||
super.setPlacedBy(world, pos, state, entity, stack);
|
super.setPlacedBy(world, pos, state, entity, stack);
|
||||||
|
@ -161,6 +166,6 @@ protected ItemStack getItem(AbstractComputerBlockEntity tile) {
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||||
return level.isClientSide ? BaseEntityBlock.createTickerHelper(type, this.type.get(), clientTicker) : super.getTicker(level, state, type);
|
return level.isClientSide ? BlockEntityHelpers.createTickerHelper(type, this.type.get(), clientTicker) : super.getTicker(level, state, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,16 @@
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.core.computer.ComputerSide;
|
import dan200.computercraft.core.computer.ComputerSide;
|
||||||
import dan200.computercraft.shared.common.GenericTile;
|
|
||||||
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlockEntity;
|
import dan200.computercraft.shared.computer.blocks.AbstractComputerBlockEntity;
|
||||||
import dan200.computercraft.shared.computer.blocks.ComputerPeripheral;
|
import dan200.computercraft.shared.computer.blocks.ComputerPeripheral;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
import dan200.computercraft.shared.config.Config;
|
import dan200.computercraft.shared.config.Config;
|
||||||
|
import dan200.computercraft.shared.container.BasicContainer;
|
||||||
import dan200.computercraft.shared.turtle.apis.TurtleAPI;
|
import dan200.computercraft.shared.turtle.apis.TurtleAPI;
|
||||||
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
||||||
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
||||||
import dan200.computercraft.shared.util.DefaultInventory;
|
|
||||||
import dan200.computercraft.shared.util.DirectionUtil;
|
|
||||||
import dan200.computercraft.shared.util.RedstoneUtil;
|
|
||||||
import dan200.computercraft.shared.util.WorldUtil;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.NonNullList;
|
import net.minecraft.core.NonNullList;
|
||||||
|
@ -43,13 +39,12 @@
|
||||||
import net.minecraft.world.item.Items;
|
import net.minecraft.world.item.Items;
|
||||||
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.minecraft.world.phys.BlockHitResult;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public class TurtleBlockEntity extends AbstractComputerBlockEntity implements ITurtleBlockEntity, DefaultInventory {
|
public class TurtleBlockEntity extends AbstractComputerBlockEntity implements BasicContainer, ITurtleBlockEntity {
|
||||||
public static final int INVENTORY_SIZE = 16;
|
public static final int INVENTORY_SIZE = 16;
|
||||||
public static final int INVENTORY_WIDTH = 4;
|
public static final int INVENTORY_WIDTH = 4;
|
||||||
public static final int INVENTORY_HEIGHT = 4;
|
public static final int INVENTORY_HEIGHT = 4;
|
||||||
|
@ -68,7 +63,7 @@ enum MoveState {
|
||||||
private @Nullable IPeripheral peripheral;
|
private @Nullable IPeripheral peripheral;
|
||||||
private @Nullable Runnable onMoved;
|
private @Nullable Runnable onMoved;
|
||||||
|
|
||||||
public TurtleBlockEntity(BlockEntityType<? extends GenericTile> type, BlockPos pos, BlockState state, ComputerFamily family) {
|
public TurtleBlockEntity(BlockEntityType<? extends TurtleBlockEntity> type, BlockPos pos, BlockState state, ComputerFamily family) {
|
||||||
super(type, pos, state, family);
|
super(type, pos, state, family);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,39 +83,13 @@ protected ServerComputer createComputer(int id) {
|
||||||
return computer;
|
return computer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
if (!hasMoved()) {
|
|
||||||
// Stop computer
|
|
||||||
super.destroy();
|
|
||||||
|
|
||||||
// Drop contents
|
|
||||||
if (!getLevel().isClientSide) {
|
|
||||||
var size = getContainerSize();
|
|
||||||
for (var i = 0; i < size; i++) {
|
|
||||||
var stack = getItem(i);
|
|
||||||
if (!stack.isEmpty()) {
|
|
||||||
WorldUtil.dropItemStack(stack, getLevel(), getBlockPos());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Just turn off any redstone we had on
|
|
||||||
for (var dir : DirectionUtil.FACINGS) {
|
|
||||||
RedstoneUtil.propagateRedstoneOutput(getLevel(), getBlockPos(), dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void unload() {
|
protected void unload() {
|
||||||
if (!hasMoved()) {
|
if (!hasMoved()) super.unload();
|
||||||
super.unload();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
public InteractionResult use(Player player, InteractionHand hand) {
|
||||||
// Apply dye
|
// Apply dye
|
||||||
var currentItem = player.getItemInHand(hand);
|
var currentItem = player.getItemInHand(hand);
|
||||||
if (!currentItem.isEmpty()) {
|
if (!currentItem.isEmpty()) {
|
||||||
|
@ -152,7 +121,7 @@ public InteractionResult onActivate(Player player, InteractionHand hand, BlockHi
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open GUI or whatever
|
// Open GUI or whatever
|
||||||
return super.onActivate(player, hand, hit);
|
return super.use(player, hand);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -161,7 +130,7 @@ protected boolean canNameWithTag(Player player) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected double getInteractRange(Player player) {
|
protected double getInteractRange() {
|
||||||
return 12.0;
|
return 12.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,13 +158,8 @@ protected void updateBlockState(ComputerState newState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNeighbourChange(BlockPos neighbour) {
|
public void neighborChanged(BlockPos neighbour) {
|
||||||
if (moveState == MoveState.NOT_MOVED) super.onNeighbourChange(neighbour);
|
if (moveState == MoveState.NOT_MOVED) super.neighborChanged(neighbour);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
|
||||||
if (moveState == MoveState.NOT_MOVED) super.onNeighbourTileEntityChange(neighbour);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyMoveStart() {
|
public void notifyMoveStart() {
|
||||||
|
@ -208,8 +172,8 @@ public void notifyMoveEnd() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(CompoundTag nbt) {
|
public void loadServer(CompoundTag nbt) {
|
||||||
super.load(nbt);
|
super.loadServer(nbt);
|
||||||
|
|
||||||
// Read inventory
|
// Read inventory
|
||||||
var nbttaglist = nbt.getList("Items", Tag.TAG_COMPOUND);
|
var nbttaglist = nbt.getList("Items", Tag.TAG_COMPOUND);
|
||||||
|
@ -315,66 +279,8 @@ void setOwningPlayer(GameProfile player) {
|
||||||
// IInventory
|
// IInventory
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getContainerSize() {
|
public NonNullList<ItemStack> getContents() {
|
||||||
return INVENTORY_SIZE;
|
return inventory;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
for (var stack : inventory) {
|
|
||||||
if (!stack.isEmpty()) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack getItem(int slot) {
|
|
||||||
return slot >= 0 && slot < INVENTORY_SIZE ? inventory.get(slot) : ItemStack.EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack removeItemNoUpdate(int slot) {
|
|
||||||
var result = getItem(slot);
|
|
||||||
setItem(slot, ItemStack.EMPTY);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemStack removeItem(int slot, int count) {
|
|
||||||
if (count == 0) return ItemStack.EMPTY;
|
|
||||||
|
|
||||||
var stack = getItem(slot);
|
|
||||||
if (stack.isEmpty()) return ItemStack.EMPTY;
|
|
||||||
|
|
||||||
if (stack.getCount() <= count) {
|
|
||||||
setItem(slot, ItemStack.EMPTY);
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
var part = stack.split(count);
|
|
||||||
onInventoryDefinitelyChanged();
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(int i, ItemStack stack) {
|
|
||||||
if (i >= 0 && i < INVENTORY_SIZE && !ItemStack.matches(stack, inventory.get(i))) {
|
|
||||||
inventory.set(i, stack);
|
|
||||||
onInventoryDefinitelyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clearContent() {
|
|
||||||
var changed = false;
|
|
||||||
for (var i = 0; i < INVENTORY_SIZE; i++) {
|
|
||||||
if (!inventory.get(i).isEmpty()) {
|
|
||||||
inventory.set(i, ItemStack.EMPTY);
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changed) onInventoryDefinitelyChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -395,11 +301,6 @@ public boolean stillValid(Player player) {
|
||||||
return isUsable(player);
|
return isUsable(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onInventoryDefinitelyChanged() {
|
|
||||||
super.setChanged();
|
|
||||||
inventoryChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onTileEntityChange() {
|
public void onTileEntityChange() {
|
||||||
super.setChanged();
|
super.setChanged();
|
||||||
}
|
}
|
||||||
|
@ -414,8 +315,8 @@ public CompoundTag getUpdateTag() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleUpdateTag(CompoundTag nbt) {
|
public void loadClient(CompoundTag nbt) {
|
||||||
super.handleUpdateTag(nbt);
|
super.loadClient(nbt);
|
||||||
brain.readDescription(nbt);
|
brain.readDescription(nbt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,12 @@
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
import dan200.computercraft.shared.config.Config;
|
import dan200.computercraft.shared.config.Config;
|
||||||
|
import dan200.computercraft.shared.container.InventoryDelegate;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||||
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
import dan200.computercraft.shared.util.Holiday;
|
import dan200.computercraft.shared.util.Holiday;
|
||||||
import dan200.computercraft.shared.util.HolidayUtil;
|
import dan200.computercraft.shared.util.HolidayUtil;
|
||||||
import dan200.computercraft.shared.util.InventoryDelegate;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.particles.ParticleTypes;
|
import net.minecraft.core.particles.ParticleTypes;
|
||||||
|
@ -345,6 +346,8 @@ public float getVisualYaw(float f) {
|
||||||
yaw += 360.0f;
|
yaw += 360.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
default -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return yaw;
|
return yaw;
|
||||||
}
|
}
|
||||||
|
@ -454,7 +457,7 @@ public void playAnimation(TurtleAnimation animation) {
|
||||||
animationProgress = 0;
|
animationProgress = 0;
|
||||||
lastAnimationProgress = 0;
|
lastAnimationProgress = 0;
|
||||||
}
|
}
|
||||||
owner.updateBlock();
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable ResourceLocation getOverlay() {
|
public @Nullable ResourceLocation getOverlay() {
|
||||||
|
@ -464,7 +467,7 @@ public void playAnimation(TurtleAnimation animation) {
|
||||||
public void setOverlay(ResourceLocation overlay) {
|
public void setOverlay(ResourceLocation overlay) {
|
||||||
if (!Objects.equal(this.overlay, overlay)) {
|
if (!Objects.equal(this.overlay, overlay)) {
|
||||||
this.overlay = overlay;
|
this.overlay = overlay;
|
||||||
owner.updateBlock();
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +484,7 @@ public void setDyeColour(@Nullable DyeColor dyeColour) {
|
||||||
}
|
}
|
||||||
if (colourHex != newColour) {
|
if (colourHex != newColour) {
|
||||||
colourHex = newColour;
|
colourHex = newColour;
|
||||||
owner.updateBlock();
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,11 +493,11 @@ public void setColour(int colour) {
|
||||||
if (colour >= 0 && colour <= 0xFFFFFF) {
|
if (colour >= 0 && colour <= 0xFFFFFF) {
|
||||||
if (colourHex != colour) {
|
if (colourHex != colour) {
|
||||||
colourHex = colour;
|
colourHex = colour;
|
||||||
owner.updateBlock();
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
}
|
}
|
||||||
} else if (colourHex != -1) {
|
} else if (colourHex != -1) {
|
||||||
colourHex = -1;
|
colourHex = -1;
|
||||||
owner.updateBlock();
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +528,7 @@ public void setUpgrade(TurtleSide side, @Nullable ITurtleUpgrade upgrade) {
|
||||||
// This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as
|
// This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as
|
||||||
// either the block is newly placed (and so won't have changed) or is being updated with /data, which calls
|
// either the block is newly placed (and so won't have changed) or is being updated with /data, which calls
|
||||||
// updateBlock for us.
|
// updateBlock for us.
|
||||||
owner.updateBlock();
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
|
|
||||||
// Recompute peripherals in case an upgrade being removed has exposed a new peripheral.
|
// Recompute peripherals in case an upgrade being removed has exposed a new peripheral.
|
||||||
// TODO: Only update peripherals, or even only two sides?
|
// TODO: Only update peripherals, or even only two sides?
|
||||||
|
@ -568,7 +571,7 @@ public CompoundTag getUpgradeNBTData(TurtleSide side) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateUpgradeNBTData(TurtleSide side) {
|
public void updateUpgradeNBTData(TurtleSide side) {
|
||||||
owner.updateBlock();
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vec3 getRenderOffset(float f) {
|
public Vec3 getRenderOffset(float f) {
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||||
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
||||||
import dan200.computercraft.shared.util.SingleIntArray;
|
import dan200.computercraft.shared.container.SingleContainerData;
|
||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.SimpleContainer;
|
import net.minecraft.world.SimpleContainer;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
@ -65,7 +65,7 @@ public static TurtleMenu ofBrain(int id, Inventory player, TurtleBrain turtle) {
|
||||||
return new TurtleMenu(
|
return new TurtleMenu(
|
||||||
// Laziness in turtle.getOwner() is important here!
|
// Laziness in turtle.getOwner() is important here!
|
||||||
id, p -> turtle.getOwner().stillValid(p), turtle.getFamily(), turtle.getOwner().createServerComputer(), null,
|
id, p -> turtle.getOwner().stillValid(p), turtle.getFamily(), turtle.getOwner().createServerComputer(), null,
|
||||||
player, turtle.getInventory(), (SingleIntArray) turtle::getSelectedSlot
|
player, turtle.getInventory(), (SingleContainerData) turtle::getSelectedSlot
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ public List<ItemStack> doCrafting(Level world, int maxCount) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return Collections.unmodifiableList(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.util;
|
||||||
|
|
||||||
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.block.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.phys.Vec3;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
public final class BlockEntityHelpers {
|
||||||
|
/**
|
||||||
|
* The maximum limit a player can be away from a block to still have its UI open.
|
||||||
|
*
|
||||||
|
* @see #isUsable(BlockEntity, Player, double)
|
||||||
|
*/
|
||||||
|
public static final double DEFAULT_INTERACT_RANGE = 8.0;
|
||||||
|
|
||||||
|
private BlockEntityHelpers() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <E extends BlockEntity, A extends BlockEntity> BlockEntityTicker<A> createTickerHelper(
|
||||||
|
BlockEntityType<A> actualType, BlockEntityType<E> expectedType, BlockEntityTicker<? super E> ticker
|
||||||
|
) {
|
||||||
|
return actualType == expectedType ? (BlockEntityTicker<A>) ticker : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a block entity is "usable" by a player.
|
||||||
|
*
|
||||||
|
* @param blockEntity The current block entity.
|
||||||
|
* @param player The player who is trying to interact with the block.
|
||||||
|
* @param range The default distance the player can be away. This typically defaults to {@link #DEFAULT_INTERACT_RANGE},
|
||||||
|
* but a custom value may be used. If {@link PlatformHelper#getReachDistance(Player)} is larger,
|
||||||
|
* that will be used instead.
|
||||||
|
* @return Whether this block entity is usable.
|
||||||
|
*/
|
||||||
|
public static boolean isUsable(BlockEntity blockEntity, Player player, double range) {
|
||||||
|
var level = blockEntity.getLevel();
|
||||||
|
var pos = blockEntity.getBlockPos();
|
||||||
|
|
||||||
|
range = Math.max(range, PlatformHelper.get().getReachDistance(player));
|
||||||
|
|
||||||
|
return player.isAlive() && player.getCommandSenderWorld() == level &&
|
||||||
|
!blockEntity.isRemoved() && level.getBlockEntity(pos) == blockEntity &&
|
||||||
|
player.distanceToSqr(Vec3.atCenterOf(pos)) <= range * range;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a block entity, marking it as changed and propagating changes to the client.
|
||||||
|
*
|
||||||
|
* @param blockEntity The block entity which has updated.
|
||||||
|
*/
|
||||||
|
public static void updateBlock(BlockEntity blockEntity) {
|
||||||
|
blockEntity.setChanged();
|
||||||
|
|
||||||
|
var state = blockEntity.getBlockState();
|
||||||
|
blockEntity.getLevel().sendBlockUpdated(blockEntity.getBlockPos(), state, state, Block.UPDATE_ALL);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
||||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
|
||||||
*/
|
|
||||||
package dan200.computercraft.shared.util;
|
|
||||||
|
|
||||||
import net.minecraft.world.Container;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
|
|
||||||
|
|
||||||
public interface DefaultInventory extends Container {
|
|
||||||
@Override
|
|
||||||
default int getMaxStackSize() {
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
default void startOpen(Player player) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
default void stopOpen(Player player) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
default boolean canPlaceItem(int slot, ItemStack stack) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -63,14 +63,16 @@ public static ShapedTemplate getTemplate(JsonObject json) {
|
||||||
Set<Character> missingKeys = Sets.newHashSet(ingMap.keySet());
|
Set<Character> missingKeys = Sets.newHashSet(ingMap.keySet());
|
||||||
missingKeys.remove(' ');
|
missingKeys.remove(' ');
|
||||||
|
|
||||||
var i = 0;
|
var ingredientIdx = 0;
|
||||||
for (var line : pattern) {
|
for (var line : pattern) {
|
||||||
for (var chr : line.toCharArray()) {
|
for (var i = 0; i < line.length(); i++) {
|
||||||
|
var chr = line.charAt(i);
|
||||||
|
|
||||||
var ing = ingMap.get(chr);
|
var ing = ingMap.get(chr);
|
||||||
if (ing == null) {
|
if (ing == null) {
|
||||||
throw new JsonSyntaxException("Pattern references symbol '" + chr + "' but it's not defined in the key");
|
throw new JsonSyntaxException("Pattern references symbol '" + chr + "' but it's not defined in the key");
|
||||||
}
|
}
|
||||||
ingredients.set(i++, ing);
|
ingredients.set(ingredientIdx++, ing);
|
||||||
missingKeys.remove(chr);
|
missingKeys.remove(chr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public final class WorldUtil {
|
public final class WorldUtil {
|
||||||
|
@SuppressWarnings("UnnecessaryLambda")
|
||||||
private static final Predicate<Entity> CAN_COLLIDE = x -> x != null && x.isAlive() && x.isPickable();
|
private static final Predicate<Entity> CAN_COLLIDE = x -> x != null && x.isAlive() && x.isPickable();
|
||||||
|
|
||||||
public static boolean isLiquidBlock(Level world, BlockPos pos) {
|
public static boolean isLiquidBlock(Level world, BlockPos pos) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ protected boolean matchesSafely(ItemStack item) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void describeTo(Description description) {
|
public void describeTo(Description description) {
|
||||||
description.appendValue(stack);
|
description.appendValue(stack).appendValue(stack.getTag());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Matcher<ItemStack> isStack(ItemStack stack) {
|
public static Matcher<ItemStack> isStack(ItemStack stack) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ public void tickAndContinue(long ticks) {
|
||||||
// Mimic the original behaviour.
|
// Mimic the original behaviour.
|
||||||
} catch (AssertionError e) {
|
} catch (AssertionError e) {
|
||||||
parent.fail(e);
|
parent.fail(e);
|
||||||
} catch (Exception e) {
|
} catch (Exception | LinkageError | VirtualMachineError e) {
|
||||||
// Fail the test, rather than crashing the server.
|
// Fail the test, rather than crashing the server.
|
||||||
TestHooks.LOG.error("{} threw unexpected exception", parent.getTestName(), e);
|
TestHooks.LOG.error("{} threw unexpected exception", parent.getTestName(), e);
|
||||||
parent.fail(e);
|
parent.fail(e);
|
||||||
|
|
|
@ -6,15 +6,19 @@
|
||||||
package dan200.computercraft.gametest
|
package dan200.computercraft.gametest
|
||||||
|
|
||||||
import dan200.computercraft.core.apis.FSAPI
|
import dan200.computercraft.core.apis.FSAPI
|
||||||
import dan200.computercraft.gametest.api.GameTestHolder
|
import dan200.computercraft.gametest.api.*
|
||||||
import dan200.computercraft.gametest.api.sequence
|
import dan200.computercraft.shared.ModRegistry
|
||||||
import dan200.computercraft.gametest.api.thenOnComputer
|
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlock
|
||||||
|
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveState
|
||||||
import dan200.computercraft.test.core.assertArrayEquals
|
import dan200.computercraft.test.core.assertArrayEquals
|
||||||
import dan200.computercraft.test.core.computer.getApi
|
import dan200.computercraft.test.core.computer.getApi
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.gametest.framework.GameTest
|
import net.minecraft.gametest.framework.GameTest
|
||||||
import net.minecraft.gametest.framework.GameTestHelper
|
import net.minecraft.gametest.framework.GameTestHelper
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
|
import net.minecraft.world.level.block.RedStoneWireBlock
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
|
||||||
@GameTestHolder
|
@GameTestHolder
|
||||||
|
@ -52,4 +56,70 @@ fun Adds_removes_mount(helper: GameTestHelper) = helper.sequence {
|
||||||
thenIdle(2)
|
thenIdle(2)
|
||||||
thenOnComputer { assertEquals(null, getApi<FSAPI>().getDrive("disk")) }
|
thenOnComputer { assertEquals(null, getApi<FSAPI>().getDrive("disk")) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check comparators can read the contents of the disk drive
|
||||||
|
*/
|
||||||
|
@GameTest
|
||||||
|
fun Comparator(helper: GameTestHelper) = helper.sequence {
|
||||||
|
val drivePos = BlockPos(2, 2, 2)
|
||||||
|
val dustPos = BlockPos(2, 2, 4)
|
||||||
|
|
||||||
|
// Adding items should provide power
|
||||||
|
thenExecute {
|
||||||
|
val drive = helper.getBlockEntity(drivePos, ModRegistry.BlockEntities.DISK_DRIVE.get())
|
||||||
|
drive.setItem(0, ItemStack(ModRegistry.Items.TREASURE_DISK.get()))
|
||||||
|
drive.setChanged()
|
||||||
|
}
|
||||||
|
thenIdle(2)
|
||||||
|
thenExecute { helper.assertBlockHas(dustPos, RedStoneWireBlock.POWER, 15) }
|
||||||
|
|
||||||
|
// And removing them should reset power.
|
||||||
|
thenExecute {
|
||||||
|
val drive = helper.getBlockEntity(drivePos, ModRegistry.BlockEntities.DISK_DRIVE.get())
|
||||||
|
drive.setItem(0, ItemStack.EMPTY)
|
||||||
|
drive.setChanged()
|
||||||
|
}
|
||||||
|
thenIdle(2)
|
||||||
|
thenExecute { helper.assertBlockHas(dustPos, RedStoneWireBlock.POWER, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changing the inventory contents updates the block state
|
||||||
|
*/
|
||||||
|
@GameTest
|
||||||
|
fun Contents_updates_state(helper: GameTestHelper) = helper.sequence {
|
||||||
|
val pos = BlockPos(2, 2, 2)
|
||||||
|
|
||||||
|
thenExecute {
|
||||||
|
val drive = helper.getBlockEntity(pos, ModRegistry.BlockEntities.DISK_DRIVE.get())
|
||||||
|
|
||||||
|
drive.setItem(0, ItemStack(Items.DIRT))
|
||||||
|
drive.setChanged()
|
||||||
|
helper.assertBlockHas(pos, DiskDriveBlock.STATE, DiskDriveState.INVALID)
|
||||||
|
|
||||||
|
drive.setItem(0, ItemStack(ModRegistry.Items.TREASURE_DISK.get()))
|
||||||
|
drive.setChanged()
|
||||||
|
helper.assertBlockHas(pos, DiskDriveBlock.STATE, DiskDriveState.FULL)
|
||||||
|
|
||||||
|
drive.setItem(0, ItemStack.EMPTY)
|
||||||
|
drive.setChanged()
|
||||||
|
helper.assertBlockHas(pos, DiskDriveBlock.STATE, DiskDriveState.EMPTY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the block is broken, we drop the contents and an optionally named stack.
|
||||||
|
*/
|
||||||
|
@GameTest
|
||||||
|
fun Drops_contents(helper: GameTestHelper) = helper.sequence {
|
||||||
|
thenExecute {
|
||||||
|
helper.level.destroyBlock(helper.absolutePos(BlockPos(2, 2, 2)), true)
|
||||||
|
helper.assertExactlyItems(
|
||||||
|
ItemStack(ModRegistry.Items.DISK_DRIVE.get()).setHoverName(Component.literal("My Disk Drive")),
|
||||||
|
ItemStack(ModRegistry.Items.TREASURE_DISK.get()),
|
||||||
|
message = "Breaking a disk drive should drop the contents",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,10 @@
|
||||||
*/
|
*/
|
||||||
package dan200.computercraft.gametest
|
package dan200.computercraft.gametest
|
||||||
|
|
||||||
import dan200.computercraft.gametest.api.GameTestHolder
|
import dan200.computercraft.gametest.api.*
|
||||||
import dan200.computercraft.gametest.api.getBlockEntity
|
|
||||||
import dan200.computercraft.gametest.api.sequence
|
|
||||||
import dan200.computercraft.gametest.api.setBlock
|
|
||||||
import dan200.computercraft.shared.ModRegistry
|
import dan200.computercraft.shared.ModRegistry
|
||||||
|
import dan200.computercraft.shared.peripheral.monitor.MonitorBlock
|
||||||
|
import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState
|
||||||
import net.minecraft.commands.arguments.blocks.BlockInput
|
import net.minecraft.commands.arguments.blocks.BlockInput
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.gametest.framework.GameTest
|
import net.minecraft.gametest.framework.GameTest
|
||||||
|
@ -47,4 +46,16 @@ fun Ensures_valid_on_place(context: GameTestHelper) = context.sequence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a monitor is destroyed, assert its neighbors correctly contract.
|
||||||
|
*/
|
||||||
|
@GameTest
|
||||||
|
fun Contract_on_destroy(helper: GameTestHelper) = helper.sequence {
|
||||||
|
thenExecute {
|
||||||
|
helper.setBlock(BlockPos(2, 2, 2), Blocks.AIR.defaultBlockState())
|
||||||
|
helper.assertBlockHas(BlockPos(1, 2, 2), MonitorBlock.STATE, MonitorEdgeState.NONE)
|
||||||
|
helper.assertBlockHas(BlockPos(3, 2, 2), MonitorBlock.STATE, MonitorEdgeState.NONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
package dan200.computercraft.gametest
|
||||||
|
|
||||||
|
import dan200.computercraft.gametest.api.*
|
||||||
|
import dan200.computercraft.shared.ModRegistry
|
||||||
|
import dan200.computercraft.shared.peripheral.printer.PrinterBlock
|
||||||
|
import net.minecraft.core.BlockPos
|
||||||
|
import net.minecraft.gametest.framework.GameTest
|
||||||
|
import net.minecraft.gametest.framework.GameTestHelper
|
||||||
|
import net.minecraft.network.chat.Component
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
import net.minecraft.world.item.Items
|
||||||
|
import net.minecraft.world.level.block.RedStoneWireBlock
|
||||||
|
|
||||||
|
@GameTestHolder
|
||||||
|
class Printer_Test {
|
||||||
|
/**
|
||||||
|
* Check comparators can read the contents of the disk drive
|
||||||
|
*/
|
||||||
|
@GameTest
|
||||||
|
fun Comparator(helper: GameTestHelper) = helper.sequence {
|
||||||
|
val printerPos = BlockPos(2, 2, 2)
|
||||||
|
val dustPos = BlockPos(2, 2, 4)
|
||||||
|
|
||||||
|
// Adding items should provide power
|
||||||
|
thenExecute {
|
||||||
|
val drive = helper.getBlockEntity(printerPos, ModRegistry.BlockEntities.PRINTER.get())
|
||||||
|
drive.setItem(0, ItemStack(Items.BLACK_DYE))
|
||||||
|
drive.setItem(1, ItemStack(Items.PAPER))
|
||||||
|
drive.setChanged()
|
||||||
|
}
|
||||||
|
thenIdle(2)
|
||||||
|
thenExecute { helper.assertBlockHas(dustPos, RedStoneWireBlock.POWER, 1) }
|
||||||
|
|
||||||
|
// And removing them should reset power.
|
||||||
|
thenExecute {
|
||||||
|
val drive = helper.getBlockEntity(printerPos, ModRegistry.BlockEntities.PRINTER.get())
|
||||||
|
drive.clearContent()
|
||||||
|
drive.setChanged()
|
||||||
|
}
|
||||||
|
thenIdle(2)
|
||||||
|
thenExecute { helper.assertBlockHas(dustPos, RedStoneWireBlock.POWER, 0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changing the inventory contents updates the block state
|
||||||
|
*/
|
||||||
|
@GameTest
|
||||||
|
fun Contents_updates_state(helper: GameTestHelper) = helper.sequence {
|
||||||
|
val pos = BlockPos(2, 2, 2)
|
||||||
|
|
||||||
|
thenExecute {
|
||||||
|
val drive = helper.getBlockEntity(pos, ModRegistry.BlockEntities.PRINTER.get())
|
||||||
|
|
||||||
|
drive.setItem(1, ItemStack(Items.PAPER))
|
||||||
|
drive.setChanged()
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.TOP, true, message = "One item in the top row")
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.BOTTOM, false, message = "One item in the top row")
|
||||||
|
|
||||||
|
drive.setItem(7, ItemStack(Items.PAPER))
|
||||||
|
drive.setChanged()
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.TOP, true, message = "One item in each row")
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.BOTTOM, true, message = "One item in each row")
|
||||||
|
|
||||||
|
drive.setItem(1, ItemStack.EMPTY)
|
||||||
|
drive.setChanged()
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.TOP, false, message = "One item in the bottom")
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.BOTTOM, true, message = "One item in the bottom row")
|
||||||
|
|
||||||
|
drive.setItem(7, ItemStack.EMPTY)
|
||||||
|
drive.setChanged()
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.TOP, false, message = "Empty")
|
||||||
|
helper.assertBlockHas(pos, PrinterBlock.BOTTOM, false, message = "Empty")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the block is broken, we drop the contents and an optionally named stack.
|
||||||
|
*/
|
||||||
|
@GameTest
|
||||||
|
fun Drops_contents(helper: GameTestHelper) = helper.sequence {
|
||||||
|
thenExecute {
|
||||||
|
helper.level.destroyBlock(helper.absolutePos(BlockPos(2, 2, 2)), true)
|
||||||
|
helper.assertExactlyItems(
|
||||||
|
ItemStack(ModRegistry.Items.PRINTER.get()).setHoverName(Component.literal("My Printer")),
|
||||||
|
ItemStack(Items.PAPER),
|
||||||
|
ItemStack(Items.BLACK_DYE),
|
||||||
|
message = "Breaking a printer should drop the contents",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,6 +36,7 @@
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.Assertions.assertNotEquals
|
import org.junit.jupiter.api.Assertions.assertNotEquals
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
@GameTestHolder
|
@GameTestHolder
|
||||||
class Turtle_Test {
|
class Turtle_Test {
|
||||||
|
@ -402,7 +403,9 @@ fun Peripheral_change(helper: GameTestHelper) = helper.sequence {
|
||||||
val testInfo = (helper as GameTestHelperAccessor).testInfo as GameTestInfoAccessor
|
val testInfo = (helper as GameTestHelperAccessor).testInfo as GameTestInfoAccessor
|
||||||
|
|
||||||
val events = mutableListOf<Pair<String, String>>()
|
val events = mutableListOf<Pair<String, String>>()
|
||||||
|
var running = false
|
||||||
thenStartComputer("listen") {
|
thenStartComputer("listen") {
|
||||||
|
running = true
|
||||||
while (true) {
|
while (true) {
|
||||||
val event = pullEvent()
|
val event = pullEvent()
|
||||||
TestHooks.LOG.info("[{}] Got event {} at tick {}", testInfo, event[0], testInfo.`computercraft$getTick`())
|
TestHooks.LOG.info("[{}] Got event {} at tick {}", testInfo, event[0], testInfo.`computercraft$getTick`())
|
||||||
|
@ -411,8 +414,9 @@ fun Peripheral_change(helper: GameTestHelper) = helper.sequence {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thenIdle(2)
|
|
||||||
thenOnComputer("turtle") {
|
thenOnComputer("turtle") {
|
||||||
|
while (!running) sleep(10.milliseconds)
|
||||||
|
|
||||||
turtle.forward().await().assertArrayEquals(true, message = "Moved turtle forward")
|
turtle.forward().await().assertArrayEquals(true, message = "Moved turtle forward")
|
||||||
turtle.back().await().assertArrayEquals(true, message = "Moved turtle forward")
|
turtle.back().await().assertArrayEquals(true, message = "Moved turtle forward")
|
||||||
TestHooks.LOG.info("[{}] Finished turtle at {}", testInfo, testInfo.`computercraft$getTick`())
|
TestHooks.LOG.info("[{}] Finished turtle at {}", testInfo, testInfo.`computercraft$getTick`())
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper
|
import dan200.computercraft.shared.platform.PlatformHelper
|
||||||
import dan200.computercraft.shared.platform.Registries
|
import dan200.computercraft.shared.platform.Registries
|
||||||
import dan200.computercraft.test.core.computer.LuaTaskContext
|
import dan200.computercraft.test.core.computer.LuaTaskContext
|
||||||
|
import dan200.computercraft.test.shared.ItemStackMatcher.isStack
|
||||||
import net.minecraft.commands.arguments.blocks.BlockInput
|
import net.minecraft.commands.arguments.blocks.BlockInput
|
||||||
import net.minecraft.core.BlockPos
|
import net.minecraft.core.BlockPos
|
||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
|
@ -24,6 +25,8 @@
|
||||||
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.minecraft.world.level.block.state.properties.Property
|
import net.minecraft.world.level.block.state.properties.Property
|
||||||
|
import org.hamcrest.Matchers
|
||||||
|
import org.hamcrest.StringDescription
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Globally usable structures.
|
* Globally usable structures.
|
||||||
|
@ -202,6 +205,16 @@ Items do not match (first mismatch at slot $slot).
|
||||||
if (peripheral != null) fail("Expected no peripheral, got a ${peripheral.type}", pos)
|
if (peripheral != null) fail("Expected no peripheral, got a ${peripheral.type}", pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun GameTestHelper.assertExactlyItems(vararg expected: ItemStack, message: String? = null) {
|
||||||
|
val actual = getEntities(EntityType.ITEM).map { it.item }
|
||||||
|
val matcher = Matchers.containsInAnyOrder(expected.map { isStack(it) })
|
||||||
|
if (!matcher.matches(actual)) {
|
||||||
|
val description = StringDescription()
|
||||||
|
matcher.describeMismatch(actual, description)
|
||||||
|
fail(if (message.isNullOrEmpty()) description.toString() else "$message: $description")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getName(type: BlockEntityType<*>): ResourceLocation = Registries.BLOCK_ENTITY_TYPES.getKey(type)!!
|
private fun getName(type: BlockEntityType<*>): ResourceLocation = Registries.BLOCK_ENTITY_TYPES.getKey(type)!!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
139
projects/common/src/testMod/resources/data/cctest/structures/disk_drive_test.comparator.snbt
generated
Normal file
139
projects/common/src/testMod/resources/data/cctest/structures/disk_drive_test.comparator.snbt
generated
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
{
|
||||||
|
DataVersion: 3120,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:disk_drive{facing:north,state:empty}", nbt: {id: "computercraft:disk_drive"}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:comparator{facing:north,mode:compare,powered:false}", nbt: {OutputSignal: 0, id: "minecraft:comparator"}},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}",
|
||||||
|
"computercraft:disk_drive{facing:north,state:empty}",
|
||||||
|
"minecraft:comparator{facing:north,mode:compare,powered:false}"
|
||||||
|
]
|
||||||
|
}
|
137
projects/common/src/testMod/resources/data/cctest/structures/disk_drive_test.contents_updates_state.snbt
generated
Normal file
137
projects/common/src/testMod/resources/data/cctest/structures/disk_drive_test.contents_updates_state.snbt
generated
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
{
|
||||||
|
DataVersion: 3120,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:disk_drive{facing:north,state:empty}", nbt: {ForgeCaps: {}, id: "computercraft:disk_drive"}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"computercraft:disk_drive{facing:north,state:empty}"
|
||||||
|
]
|
||||||
|
}
|
137
projects/common/src/testMod/resources/data/cctest/structures/disk_drive_test.drops_contents.snbt
generated
Normal file
137
projects/common/src/testMod/resources/data/cctest/structures/disk_drive_test.drops_contents.snbt
generated
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
{
|
||||||
|
DataVersion: 3120,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:disk_drive{facing:north,state:full}", nbt: {CustomName: '{"text":"My Disk Drive"}', ForgeCaps: {}, Item: {Count: 1b, id: "computercraft:treasure_disk"}, id: "computercraft:disk_drive"}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"computercraft:disk_drive{facing:north,state:full}"
|
||||||
|
]
|
||||||
|
}
|
139
projects/common/src/testMod/resources/data/cctest/structures/monitor_test.contract_on_destroy.snbt
generated
Normal file
139
projects/common/src/testMod/resources/data/cctest/structures/monitor_test.contract_on_destroy.snbt
generated
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
{
|
||||||
|
DataVersion: 3120,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:l}", nbt: {ForgeCaps: {}, Height: 1, Width: 3, XIndex: 2, YIndex: 0, id: "computercraft:monitor_advanced"}},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:lr}", nbt: {ForgeCaps: {}, Height: 1, Width: 3, XIndex: 1, YIndex: 0, id: "computercraft:monitor_advanced"}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "computercraft:monitor_advanced{facing:north,orientation:north,state:r}", nbt: {ForgeCaps: {}, Height: 1, Width: 3, XIndex: 0, YIndex: 0, id: "computercraft:monitor_advanced"}},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"computercraft:monitor_advanced{facing:north,orientation:north,state:l}",
|
||||||
|
"computercraft:monitor_advanced{facing:north,orientation:north,state:lr}",
|
||||||
|
"computercraft:monitor_advanced{facing:north,orientation:north,state:r}"
|
||||||
|
]
|
||||||
|
}
|
139
projects/common/src/testMod/resources/data/cctest/structures/printer_test.comparator.snbt
generated
Normal file
139
projects/common/src/testMod/resources/data/cctest/structures/printer_test.comparator.snbt
generated
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
{
|
||||||
|
DataVersion: 3120,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:printer{bottom:false,facing:north,top:false}", nbt: {ForgeCaps: {}, Items: [], PageTitle: "", Printing: 0b, id: "computercraft:printer", term_bgColour: 15, term_cursorBlink: 0b, term_cursorX: 0, term_cursorY: 0, term_palette: [I; 1118481, 13388876, 5744206, 8349260, 3368652, 11691749, 5020082, 10066329, 5000268, 15905484, 8375321, 14605932, 10072818, 15040472, 15905331, 15790320], term_textBgColour_0: "fffffffffffffffffffffffff", term_textBgColour_1: "fffffffffffffffffffffffff", term_textBgColour_10: "fffffffffffffffffffffffff", term_textBgColour_11: "fffffffffffffffffffffffff", term_textBgColour_12: "fffffffffffffffffffffffff", term_textBgColour_13: "fffffffffffffffffffffffff", term_textBgColour_14: "fffffffffffffffffffffffff", term_textBgColour_15: "fffffffffffffffffffffffff", term_textBgColour_16: "fffffffffffffffffffffffff", term_textBgColour_17: "fffffffffffffffffffffffff", term_textBgColour_18: "fffffffffffffffffffffffff", term_textBgColour_19: "fffffffffffffffffffffffff", term_textBgColour_2: "fffffffffffffffffffffffff", term_textBgColour_20: "fffffffffffffffffffffffff", term_textBgColour_3: "fffffffffffffffffffffffff", term_textBgColour_4: "fffffffffffffffffffffffff", term_textBgColour_5: "fffffffffffffffffffffffff", term_textBgColour_6: "fffffffffffffffffffffffff", term_textBgColour_7: "fffffffffffffffffffffffff", term_textBgColour_8: "fffffffffffffffffffffffff", term_textBgColour_9: "fffffffffffffffffffffffff", term_textColour: 0, term_textColour_0: "0000000000000000000000000", term_textColour_1: "0000000000000000000000000", term_textColour_10: "0000000000000000000000000", term_textColour_11: "0000000000000000000000000", term_textColour_12: "0000000000000000000000000", term_textColour_13: "0000000000000000000000000", term_textColour_14: "0000000000000000000000000", term_textColour_15: "0000000000000000000000000", term_textColour_16: "0000000000000000000000000", term_textColour_17: "0000000000000000000000000", term_textColour_18: "0000000000000000000000000", term_textColour_19: "0000000000000000000000000", term_textColour_2: "0000000000000000000000000", term_textColour_20: "0000000000000000000000000", term_textColour_3: "0000000000000000000000000", term_textColour_4: "0000000000000000000000000", term_textColour_5: "0000000000000000000000000", term_textColour_6: "0000000000000000000000000", term_textColour_7: "0000000000000000000000000", term_textColour_8: "0000000000000000000000000", term_textColour_9: "0000000000000000000000000", term_text_0: " ", term_text_1: " ", term_text_10: " ", term_text_11: " ", term_text_12: " ", term_text_13: " ", term_text_14: " ", term_text_15: " ", term_text_16: " ", term_text_17: " ", term_text_18: " ", term_text_19: " ", term_text_2: " ", term_text_20: " ", term_text_3: " ", term_text_4: " ", term_text_5: " ", term_text_6: " ", term_text_7: " ", term_text_8: " ", term_text_9: " "}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:comparator{facing:north,mode:compare,powered:false}", nbt: {OutputSignal: 0, id: "minecraft:comparator"}},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"minecraft:redstone_wire{east:none,north:side,power:0,south:side,west:none}",
|
||||||
|
"computercraft:printer{bottom:false,facing:north,top:false}",
|
||||||
|
"minecraft:comparator{facing:north,mode:compare,powered:false}"
|
||||||
|
]
|
||||||
|
}
|
137
projects/common/src/testMod/resources/data/cctest/structures/printer_test.contents_updates_state.snbt
generated
Normal file
137
projects/common/src/testMod/resources/data/cctest/structures/printer_test.contents_updates_state.snbt
generated
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
{
|
||||||
|
DataVersion: 3120,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:printer{bottom:false,facing:north,top:false}", nbt: {ForgeCaps: {}, Items: [], PageTitle: "", Printing: 0b, id: "computercraft:printer", term_bgColour: 15, term_cursorBlink: 0b, term_cursorX: 0, term_cursorY: 0, term_palette: [I; 1118481, 13388876, 5744206, 8349260, 3368652, 11691749, 5020082, 10066329, 5000268, 15905484, 8375321, 14605932, 10072818, 15040472, 15905331, 15790320], term_textBgColour_0: "fffffffffffffffffffffffff", term_textBgColour_1: "fffffffffffffffffffffffff", term_textBgColour_10: "fffffffffffffffffffffffff", term_textBgColour_11: "fffffffffffffffffffffffff", term_textBgColour_12: "fffffffffffffffffffffffff", term_textBgColour_13: "fffffffffffffffffffffffff", term_textBgColour_14: "fffffffffffffffffffffffff", term_textBgColour_15: "fffffffffffffffffffffffff", term_textBgColour_16: "fffffffffffffffffffffffff", term_textBgColour_17: "fffffffffffffffffffffffff", term_textBgColour_18: "fffffffffffffffffffffffff", term_textBgColour_19: "fffffffffffffffffffffffff", term_textBgColour_2: "fffffffffffffffffffffffff", term_textBgColour_20: "fffffffffffffffffffffffff", term_textBgColour_3: "fffffffffffffffffffffffff", term_textBgColour_4: "fffffffffffffffffffffffff", term_textBgColour_5: "fffffffffffffffffffffffff", term_textBgColour_6: "fffffffffffffffffffffffff", term_textBgColour_7: "fffffffffffffffffffffffff", term_textBgColour_8: "fffffffffffffffffffffffff", term_textBgColour_9: "fffffffffffffffffffffffff", term_textColour: 0, term_textColour_0: "0000000000000000000000000", term_textColour_1: "0000000000000000000000000", term_textColour_10: "0000000000000000000000000", term_textColour_11: "0000000000000000000000000", term_textColour_12: "0000000000000000000000000", term_textColour_13: "0000000000000000000000000", term_textColour_14: "0000000000000000000000000", term_textColour_15: "0000000000000000000000000", term_textColour_16: "0000000000000000000000000", term_textColour_17: "0000000000000000000000000", term_textColour_18: "0000000000000000000000000", term_textColour_19: "0000000000000000000000000", term_textColour_2: "0000000000000000000000000", term_textColour_20: "0000000000000000000000000", term_textColour_3: "0000000000000000000000000", term_textColour_4: "0000000000000000000000000", term_textColour_5: "0000000000000000000000000", term_textColour_6: "0000000000000000000000000", term_textColour_7: "0000000000000000000000000", term_textColour_8: "0000000000000000000000000", term_textColour_9: "0000000000000000000000000", term_text_0: " ", term_text_1: " ", term_text_10: " ", term_text_11: " ", term_text_12: " ", term_text_13: " ", term_text_14: " ", term_text_15: " ", term_text_16: " ", term_text_17: " ", term_text_18: " ", term_text_19: " ", term_text_2: " ", term_text_20: " ", term_text_3: " ", term_text_4: " ", term_text_5: " ", term_text_6: " ", term_text_7: " ", term_text_8: " ", term_text_9: " "}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"computercraft:printer{bottom:false,facing:north,top:false}"
|
||||||
|
]
|
||||||
|
}
|
137
projects/common/src/testMod/resources/data/cctest/structures/printer_test.drops_contents.snbt
generated
Normal file
137
projects/common/src/testMod/resources/data/cctest/structures/printer_test.drops_contents.snbt
generated
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
{
|
||||||
|
DataVersion: 3120,
|
||||||
|
size: [5, 5, 5],
|
||||||
|
data: [
|
||||||
|
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
||||||
|
{pos: [0, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 2], state: "computercraft:printer{bottom:false,facing:north,top:true}", nbt: {CustomName: '{"text":"My Printer"}', ForgeCaps: {}, Items: [{Count: 1b, Slot: 0b, id: "minecraft:black_dye"}, {Count: 1b, Slot: 1b, id: "minecraft:paper"}], PageTitle: "", Printing: 0b, id: "computercraft:printer", term_bgColour: 15, term_cursorBlink: 0b, term_cursorX: 0, term_cursorY: 0, term_palette: [I; 1118481, 13388876, 5744206, 8349260, 3368652, 11691749, 5020082, 10066329, 5000268, 15905484, 8375321, 14605932, 10072818, 15040472, 15905331, 15790320], term_textBgColour_0: "fffffffffffffffffffffffff", term_textBgColour_1: "fffffffffffffffffffffffff", term_textBgColour_10: "fffffffffffffffffffffffff", term_textBgColour_11: "fffffffffffffffffffffffff", term_textBgColour_12: "fffffffffffffffffffffffff", term_textBgColour_13: "fffffffffffffffffffffffff", term_textBgColour_14: "fffffffffffffffffffffffff", term_textBgColour_15: "fffffffffffffffffffffffff", term_textBgColour_16: "fffffffffffffffffffffffff", term_textBgColour_17: "fffffffffffffffffffffffff", term_textBgColour_18: "fffffffffffffffffffffffff", term_textBgColour_19: "fffffffffffffffffffffffff", term_textBgColour_2: "fffffffffffffffffffffffff", term_textBgColour_20: "fffffffffffffffffffffffff", term_textBgColour_3: "fffffffffffffffffffffffff", term_textBgColour_4: "fffffffffffffffffffffffff", term_textBgColour_5: "fffffffffffffffffffffffff", term_textBgColour_6: "fffffffffffffffffffffffff", term_textBgColour_7: "fffffffffffffffffffffffff", term_textBgColour_8: "fffffffffffffffffffffffff", term_textBgColour_9: "fffffffffffffffffffffffff", term_textColour: 0, term_textColour_0: "0000000000000000000000000", term_textColour_1: "0000000000000000000000000", term_textColour_10: "0000000000000000000000000", term_textColour_11: "0000000000000000000000000", term_textColour_12: "0000000000000000000000000", term_textColour_13: "0000000000000000000000000", term_textColour_14: "0000000000000000000000000", term_textColour_15: "0000000000000000000000000", term_textColour_16: "0000000000000000000000000", term_textColour_17: "0000000000000000000000000", term_textColour_18: "0000000000000000000000000", term_textColour_19: "0000000000000000000000000", term_textColour_2: "0000000000000000000000000", term_textColour_20: "0000000000000000000000000", term_textColour_3: "0000000000000000000000000", term_textColour_4: "0000000000000000000000000", term_textColour_5: "0000000000000000000000000", term_textColour_6: "0000000000000000000000000", term_textColour_7: "0000000000000000000000000", term_textColour_8: "0000000000000000000000000", term_textColour_9: "0000000000000000000000000", term_text_0: " ", term_text_1: " ", term_text_10: " ", term_text_11: " ", term_text_12: " ", term_text_13: " ", term_text_14: " ", term_text_15: " ", term_text_16: " ", term_text_17: " ", term_text_18: " ", term_text_19: " ", term_text_2: " ", term_text_20: " ", term_text_3: " ", term_text_4: " ", term_text_5: " ", term_text_6: " ", term_text_7: " ", term_text_8: " ", term_text_9: " "}},
|
||||||
|
{pos: [2, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 1, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 2, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 3, 4], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [0, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [1, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [2, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [3, 4, 4], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 0], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 1], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 2], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 3], state: "minecraft:air"},
|
||||||
|
{pos: [4, 4, 4], state: "minecraft:air"}
|
||||||
|
],
|
||||||
|
entities: [],
|
||||||
|
palette: [
|
||||||
|
"minecraft:polished_andesite",
|
||||||
|
"minecraft:air",
|
||||||
|
"computercraft:printer{bottom:false,facing:north,top:true}"
|
||||||
|
]
|
||||||
|
}
|
|
@ -99,8 +99,6 @@ minecraft {
|
||||||
mods.register("cctest") {
|
mods.register("cctest") {
|
||||||
source(sourceSets["testMod"])
|
source(sourceSets["testMod"])
|
||||||
source(sourceSets["testFixtures"])
|
source(sourceSets["testFixtures"])
|
||||||
// FIXME: We need this for running in-dev but not from Gradle:
|
|
||||||
// source(project(":core").sourceSets.testFixtures.get())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +157,7 @@ dependencies {
|
||||||
testRuntimeOnly(libs.bundles.testRuntime)
|
testRuntimeOnly(libs.bundles.testRuntime)
|
||||||
|
|
||||||
testModImplementation(testFixtures(project(":core")))
|
testModImplementation(testFixtures(project(":core")))
|
||||||
|
testModImplementation(testFixtures(project(":forge")))
|
||||||
|
|
||||||
"cctJavadoc"(libs.cctJavadoc)
|
"cctJavadoc"(libs.cctJavadoc)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
import net.minecraft.client.resources.model.ModelManager;
|
import net.minecraft.client.resources.model.ModelManager;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
@AutoService(ClientPlatformHelper.class)
|
@AutoService(dan200.computercraft.impl.client.ClientPlatformHelper.class)
|
||||||
public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||||
@Override
|
@Override
|
||||||
public BakedModel getModel(ModelManager manager, ResourceLocation location) {
|
public BakedModel getModel(ModelManager manager, ResourceLocation location) {
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraftforge.common.capabilities.Capability;
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
@ -14,6 +16,7 @@
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ICapabilityProvider} which provides a different single capability, with different instances for each
|
* A {@link ICapabilityProvider} which provides a different single capability, with different instances for each
|
||||||
|
@ -28,15 +31,21 @@
|
||||||
public final class SidedCapabilityProvider<T> implements ICapabilityProvider {
|
public final class SidedCapabilityProvider<T> implements ICapabilityProvider {
|
||||||
private final Capability<T> cap;
|
private final Capability<T> cap;
|
||||||
private final Provider<T> supplier;
|
private final Provider<T> supplier;
|
||||||
|
private final BooleanSupplier isRemoved;
|
||||||
private @Nullable LazyOptional<T>[] instances;
|
private @Nullable LazyOptional<T>[] instances;
|
||||||
|
|
||||||
private SidedCapabilityProvider(Capability<T> cap, Provider<T> supplier) {
|
private SidedCapabilityProvider(Capability<T> cap, Provider<T> supplier, BooleanSupplier isRemoved) {
|
||||||
this.cap = Objects.requireNonNull(cap, "Capability cannot be null");
|
this.cap = Objects.requireNonNull(cap, "Capability cannot be null");
|
||||||
this.supplier = supplier;
|
this.supplier = supplier;
|
||||||
|
this.isRemoved = isRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> SidedCapabilityProvider<T> attach(AttachCapabilitiesEvent<?> event, ResourceLocation id, Capability<T> cap, Provider<T> supplier) {
|
public static <T> SidedCapabilityProvider<T> attach(AttachCapabilitiesEvent<?> event, ResourceLocation id, Capability<T> cap, Provider<T> supplier) {
|
||||||
var provider = new SidedCapabilityProvider<>(cap, supplier);
|
BooleanSupplier isRemoved
|
||||||
|
= event.getObject() instanceof BlockEntity be ? be::isRemoved
|
||||||
|
: event.getObject() instanceof Entity entity ? entity::isRemoved
|
||||||
|
: () -> true;
|
||||||
|
var provider = new SidedCapabilityProvider<>(cap, supplier, isRemoved);
|
||||||
event.addCapability(id, provider);
|
event.addCapability(id, provider);
|
||||||
event.addListener(provider::invalidate);
|
event.addListener(provider::invalidate);
|
||||||
return provider;
|
return provider;
|
||||||
|
@ -49,7 +58,7 @@ public void invalidate() {
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
public <U> LazyOptional<U> getCapability(Capability<U> cap, @Nullable Direction side) {
|
public <U> LazyOptional<U> getCapability(Capability<U> cap, @Nullable Direction side) {
|
||||||
if (cap != this.cap) return LazyOptional.empty();
|
if (cap != this.cap || isRemoved.getAsBoolean()) return LazyOptional.empty();
|
||||||
|
|
||||||
var instances = this.instances;
|
var instances = this.instances;
|
||||||
if (instances == null) instances = this.instances = new LazyOptional[6];
|
if (instances == null) instances = this.instances = new LazyOptional[6];
|
||||||
|
|
Loading…
Reference in New Issue
Block a user