mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-04-10 04:36:40 +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 @@ internal class IdeaRunConfigurations(project: Project) {
|
||||
|
||||
if (newClasses.any { it.startsWith("cctest%%") }) {
|
||||
appendUnique(forgeModEntry("cctest", "core", "testFixtures"))
|
||||
appendUnique(forgeModEntry("cctest", "common", "testFixtures"))
|
||||
appendUnique(forgeModEntry("cctest", "common", "testMod"))
|
||||
}
|
||||
|
||||
|
@ -32,5 +32,6 @@ dependencies {
|
||||
testRuntimeOnly(libs.bundles.testRuntime)
|
||||
|
||||
testModImplementation(testFixtures(project(":core")))
|
||||
testModImplementation(testFixtures(project(":common")))
|
||||
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_HEIGHT = 217;
|
||||
|
||||
private final ComputerFamily family;
|
||||
|
||||
public TurtleScreen(TurtleMenu container, Inventory player, Component title) {
|
||||
super(container, player, title, BORDER);
|
||||
family = container.getFamily();
|
||||
|
||||
imageWidth = TEX_WIDTH + AbstractComputerMenu.SIDEBAR_WIDTH;
|
||||
imageHeight = TEX_HEIGHT;
|
||||
|
@ -107,7 +107,7 @@ public final class PrintoutRenderer {
|
||||
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 + 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 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
|
||||
RenderSystem.setInverseViewRotationMatrix(oldInverseRotation);
|
||||
}
|
||||
case BEST -> throw new IllegalStateException("Impossible: Should never use BEST renderer");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,7 @@ public final class WiredNode implements IWiredNode {
|
||||
return "WiredNode{@" + element.getPosition() + " (" + element.getClass().getSimpleName() + ")}";
|
||||
}
|
||||
|
||||
@SuppressWarnings("LockNotBeforeTry")
|
||||
private void acquireReadLock() {
|
||||
var currentNetwork = network;
|
||||
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 class CommandAPI implements ILuaAPI {
|
||||
for (CommandNode<?> child : node.getChildren()) {
|
||||
if (child instanceof LiteralCommandNode<?>) result.add(child.getName());
|
||||
}
|
||||
return result;
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,34 +5,42 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.computer.blocks;
|
||||
|
||||
import dan200.computercraft.annotations.ForgeOverride;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.common.GenericBlock;
|
||||
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
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.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
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.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.storage.loot.LootContext;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
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 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();
|
||||
|
||||
protected AbstractComputerBlock(Properties settings, ComputerFamily family, RegistryEntry<BlockEntityType<T>> type) {
|
||||
super(settings, type);
|
||||
super(settings);
|
||||
this.family = family;
|
||||
this.type = type;
|
||||
}
|
||||
@ -160,9 +168,41 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
@Nullable
|
||||
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.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
import dan200.computercraft.impl.BundledRedstone;
|
||||
import dan200.computercraft.shared.common.GenericTile;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
@ -18,6 +17,7 @@ import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.platform.ComponentAccess;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import dan200.computercraft.shared.util.IDAssigner;
|
||||
import dan200.computercraft.shared.util.RedstoneUtil;
|
||||
@ -32,14 +32,14 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
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;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
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_LABEL = "Label";
|
||||
private static final String NBT_ON = "On";
|
||||
@ -58,7 +58,7 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
|
||||
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);
|
||||
this.family = family;
|
||||
}
|
||||
@ -71,31 +71,26 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
instanceID = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
unload();
|
||||
for (var dir : DirectionUtil.FACINGS) {
|
||||
RedstoneUtil.propagateRedstoneOutput(getLevel(), getBlockPos(), dir);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
unload();
|
||||
super.setRemoved();
|
||||
unload();
|
||||
}
|
||||
|
||||
protected boolean canNameWithTag(Player player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsable(Player player) {
|
||||
return super.isUsable(player) && BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName());
|
||||
protected double getInteractRange() {
|
||||
return BlockEntityHelpers.DEFAULT_INTERACT_RANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
public boolean isUsable(Player player) {
|
||||
return BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName())
|
||||
&& BlockEntityHelpers.isUsable(this, player, getInteractRange());
|
||||
}
|
||||
|
||||
public InteractionResult use(Player player, InteractionHand hand) {
|
||||
var currentItem = player.getItemInHand(hand);
|
||||
if (!currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag(player) && currentItem.hasCustomHoverName()) {
|
||||
// Label to rename computer
|
||||
@ -120,13 +115,7 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourChange(BlockPos neighbour) {
|
||||
updateInputAt(neighbour);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
||||
public void neighborChanged(BlockPos neighbour) {
|
||||
updateInputAt(neighbour);
|
||||
}
|
||||
|
||||
@ -179,9 +168,16 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
public final void load(CompoundTag 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
|
||||
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
||||
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
||||
@ -268,7 +264,7 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
* Update the block's state and propagate redstone output.
|
||||
*/
|
||||
public void updateOutput() {
|
||||
updateBlock();
|
||||
BlockEntityHelpers.updateBlock(this);
|
||||
for (var dir : DirectionUtil.FACINGS) {
|
||||
RedstoneUtil.propagateRedstoneOutput(getLevel(), getBlockPos(), dir);
|
||||
}
|
||||
@ -319,7 +315,7 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
if (computer == null) {
|
||||
if (computerID < 0) {
|
||||
computerID = ComputerCraftAPI.createUniqueNumberedSaveDir(level, IDAssigner.COMPUTER);
|
||||
updateBlock();
|
||||
BlockEntityHelpers.updateBlock(this);
|
||||
}
|
||||
|
||||
computer = createComputer(computerID);
|
||||
@ -353,8 +349,7 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleUpdateTag(CompoundTag nbt) {
|
||||
protected void loadClient(CompoundTag nbt) {
|
||||
label = nbt.contains(NBT_LABEL) ? nbt.getString(NBT_LABEL) : null;
|
||||
computerID = nbt.contains(NBT_ID) ? nbt.getInt(NBT_ID) : -1;
|
||||
}
|
||||
@ -368,7 +363,7 @@ public abstract class AbstractComputerBlockEntity extends GenericTile implements
|
||||
on = copy.on;
|
||||
startOn = copy.startOn;
|
||||
lockCode = copy.lockCode;
|
||||
updateBlock();
|
||||
BlockEntityHelpers.updateBlock(this);
|
||||
}
|
||||
copy.instanceID = -1;
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
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.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
@ -47,18 +45,6 @@ public class ComputerBlock<T extends ComputerBlockEntity> extends AbstractComput
|
||||
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
|
||||
protected ItemStack getItem(AbstractComputerBlockEntity tile) {
|
||||
return tile instanceof ComputerBlockEntity ? ComputerItemFactory.create((ComputerBlockEntity) tile) : ItemStack.EMPTY;
|
||||
|
@ -14,7 +14,7 @@ import dan200.computercraft.shared.computer.menu.ServerInputState;
|
||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
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.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
@ -46,7 +46,7 @@ public abstract class AbstractComputerMenu extends AbstractContainerMenu impleme
|
||||
super(type, id);
|
||||
this.canUse = canUse;
|
||||
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);
|
||||
|
||||
this.computer = computer;
|
||||
|
@ -8,7 +8,7 @@ package dan200.computercraft.shared.computer.inventory;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
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.Player;
|
||||
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.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
package dan200.computercraft.shared.container;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.WorldlyContainer;
|
||||
@ -11,7 +11,10 @@ import net.minecraft.world.item.ItemStack;
|
||||
|
||||
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
|
||||
default boolean canPlaceItemThroughFace(int slot, ItemStack stack, @Nullable Direction side) {
|
||||
return canPlaceItem(slot, stack);
|
@ -3,7 +3,7 @@
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* 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.entity.player.Player;
|
||||
@ -12,6 +12,7 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Provides a delegate over inventories.
|
||||
@ -97,4 +98,9 @@ public interface InventoryDelegate extends Container {
|
||||
default boolean hasAnyOf(Set<Item> 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.
|
||||
* 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.entity.player.Player;
|
@ -3,12 +3,15 @@
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
package dan200.computercraft.shared.container;
|
||||
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
|
||||
/**
|
||||
* A basic {@link ContainerData} implementation which provides a single value.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SingleIntArray extends ContainerData {
|
||||
public interface SingleContainerData extends ContainerData {
|
||||
int get();
|
||||
|
||||
@Override
|
@ -3,7 +3,7 @@
|
||||
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
|
||||
* 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.inventory.Slot;
|
@ -5,40 +5,34 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.diskdrive;
|
||||
|
||||
import dan200.computercraft.impl.MediaProviders;
|
||||
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.Direction;
|
||||
import net.minecraft.stats.Stats;
|
||||
import net.minecraft.world.Nameable;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
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.BaseEntityBlock;
|
||||
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.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DiskDriveBlock extends GenericBlock {
|
||||
static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||
public class DiskDriveBlock extends HorizontalContainerBlock {
|
||||
public static final EnumProperty<DiskDriveState> STATE = EnumProperty.create("state", DiskDriveState.class);
|
||||
|
||||
private static final BlockEntityTicker<DiskDriveBlockEntity> serverTicker = (level, pos, state, drive) -> drive.serverTick();
|
||||
|
||||
public DiskDriveBlock(Properties settings) {
|
||||
super(settings, ModRegistry.BlockEntities.DISK_DRIVE);
|
||||
super(settings);
|
||||
registerDefaultState(getStateDefinition().any()
|
||||
.setValue(FACING, Direction.NORTH)
|
||||
.setValue(STATE, DiskDriveState.EMPTY));
|
||||
@ -52,41 +46,25 @@ public class DiskDriveBlock extends GenericBlock {
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public BlockState mirror(BlockState state, Mirror mirrorIn) {
|
||||
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
|
||||
}
|
||||
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
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;
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public BlockState rotate(BlockState state, Rotation rot) {
|
||||
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
|
||||
if (!level.isClientSide && drive.getDiskStack().isEmpty() && MediaProviders.get(disk) != null) {
|
||||
drive.setDiskStack(disk.split(1));
|
||||
}
|
||||
return InteractionResult.sidedSuccess(level.isClientSide);
|
||||
}
|
||||
|
||||
return super.use(state, level, pos, player, hand, hit);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
||||
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite());
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||
return ModRegistry.BlockEntities.DISK_DRIVE.get().create(pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,42 +5,34 @@
|
||||
*/
|
||||
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.media.IMedia;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.impl.MediaProviders;
|
||||
import dan200.computercraft.shared.common.GenericTile;
|
||||
import dan200.computercraft.shared.common.AbstractContainerBlockEntity;
|
||||
import dan200.computercraft.shared.network.client.PlayRecordClientMessage;
|
||||
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.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
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.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
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.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
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 GenericTile implements DefaultInventory, Nameable, MenuProvider {
|
||||
private static final String NBT_NAME = "CustomName";
|
||||
public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity {
|
||||
private static final String NBT_ITEM = "Item";
|
||||
|
||||
private static class MountInfo {
|
||||
@ -48,54 +40,37 @@ public final class DiskDriveBlockEntity extends GenericTile implements DefaultIn
|
||||
String mountPath;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Component customName;
|
||||
private LockCode lockCode = LockCode.NO_LOCK;
|
||||
private final DiskDrivePeripheral peripheral = new DiskDrivePeripheral(this);
|
||||
|
||||
private final Map<IComputerAccess, MountInfo> computers = new HashMap<>();
|
||||
private final @GuardedBy("this") Map<IComputerAccess, MountInfo> computers = new HashMap<>();
|
||||
|
||||
private ItemStack diskStack = ItemStack.EMPTY;
|
||||
private @Nullable IPeripheral peripheral;
|
||||
private @Nullable IMount diskMount = null;
|
||||
private final NonNullList<ItemStack> inventory = NonNullList.withSize(1, ItemStack.EMPTY);
|
||||
|
||||
private boolean recordQueued = false;
|
||||
private MediaStack media = MediaStack.EMPTY;
|
||||
private boolean recordPlaying = false;
|
||||
private boolean restartRecord = false;
|
||||
private boolean ejectQueued;
|
||||
// In order to avoid main-thread calls in the peripheral, we set flags to mark which operation should be performed,
|
||||
// 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) {
|
||||
super(type, pos, state);
|
||||
}
|
||||
|
||||
public IPeripheral peripheral() {
|
||||
return peripheral;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
ejectContents(true);
|
||||
public void clearRemoved() {
|
||||
updateItem();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
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() {
|
||||
return getBlockState().getValue(DiskDriveBlock.FACING);
|
||||
}
|
||||
@ -103,52 +78,32 @@ public final class DiskDriveBlockEntity extends GenericTile implements DefaultIn
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
customName = nbt.contains(NBT_NAME) ? Component.Serializer.fromJson(nbt.getString(NBT_NAME)) : null;
|
||||
if (nbt.contains(NBT_ITEM)) {
|
||||
var item = nbt.getCompound(NBT_ITEM);
|
||||
diskStack = ItemStack.of(item);
|
||||
diskMount = null;
|
||||
}
|
||||
|
||||
lockCode = LockCode.fromTag(nbt);
|
||||
setDiskStack(nbt.contains(NBT_ITEM) ? ItemStack.of(nbt.getCompound(NBT_ITEM)) : ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAdditional(CompoundTag nbt) {
|
||||
if (customName != null) nbt.putString(NBT_NAME, Component.Serializer.toJson(customName));
|
||||
public void saveAdditional(CompoundTag tag) {
|
||||
super.saveAdditional(tag);
|
||||
|
||||
if (!diskStack.isEmpty()) {
|
||||
var item = new CompoundTag();
|
||||
diskStack.save(item);
|
||||
nbt.put(NBT_ITEM, item);
|
||||
}
|
||||
|
||||
lockCode.addToTag(nbt);
|
||||
|
||||
super.saveAdditional(nbt);
|
||||
var stack = getDiskStack();
|
||||
if (!stack.isEmpty()) tag.put(NBT_ITEM, stack.save(new CompoundTag()));
|
||||
}
|
||||
|
||||
void serverTick() {
|
||||
// Ejection
|
||||
if (ejectQueued) {
|
||||
ejectContents(false);
|
||||
ejectQueued = false;
|
||||
}
|
||||
if (ejectQueued.getAndSet(false)) ejectContents();
|
||||
|
||||
// Music
|
||||
synchronized (this) {
|
||||
if (recordPlaying != recordQueued || restartRecord) {
|
||||
restartRecord = false;
|
||||
if (recordQueued) {
|
||||
var contents = getDiskMedia();
|
||||
var record = contents != null ? contents.getAudio(diskStack) : null;
|
||||
var recordQueued = this.recordQueued.getAndSet(null);
|
||||
if (recordQueued != null) {
|
||||
switch (recordQueued) {
|
||||
case PLAY -> {
|
||||
var record = media.getAudio();
|
||||
if (record != null) {
|
||||
recordPlaying = true;
|
||||
playRecord();
|
||||
} else {
|
||||
recordQueued = false;
|
||||
var title = media.getAudioTitle();
|
||||
sendMessage(new PlayRecordClientMessage(getBlockPos(), record, title));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
case STOP -> {
|
||||
stopRecord();
|
||||
recordPlaying = false;
|
||||
}
|
||||
@ -156,115 +111,61 @@ public final class DiskDriveBlockEntity extends GenericTile implements DefaultIn
|
||||
}
|
||||
}
|
||||
|
||||
// IInventory implementation
|
||||
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
return 1;
|
||||
public NonNullList<ItemStack> getContents() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return diskStack.isEmpty();
|
||||
public void setChanged() {
|
||||
if (level != null && !level.isClientSide) updateItem();
|
||||
super.setChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItem(int slot) {
|
||||
return diskStack;
|
||||
}
|
||||
private void updateItem() {
|
||||
var newDisk = getDiskStack();
|
||||
if (ItemStack.isSame(newDisk, media.stack)) return;
|
||||
|
||||
@Override
|
||||
public ItemStack removeItemNoUpdate(int slot) {
|
||||
var result = diskStack;
|
||||
diskStack = ItemStack.EMPTY;
|
||||
diskMount = null;
|
||||
var media = new MediaStack(newDisk.copy());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
if (newDisk.isEmpty()) {
|
||||
updateBlockState(DiskDriveState.EMPTY);
|
||||
} else {
|
||||
updateBlockState(media.media != null ? DiskDriveState.FULL : DiskDriveState.INVALID);
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (ItemStack.isSameItemSameTags(stack, diskStack)) {
|
||||
diskStack = stack;
|
||||
return;
|
||||
}
|
||||
|
||||
// Unmount old disk
|
||||
if (!diskStack.isEmpty()) {
|
||||
// TODO: Is this iteration thread safe?
|
||||
var computers = this.computers.keySet();
|
||||
for (var computer : computers) unmountDisk(computer);
|
||||
if (!this.media.stack.isEmpty()) {
|
||||
for (var computer : computers.entrySet()) unmountDisk(computer.getKey(), computer.getValue());
|
||||
}
|
||||
|
||||
// Stop music
|
||||
if (recordPlaying) {
|
||||
stopRecord();
|
||||
recordPlaying = false;
|
||||
recordQueued = false;
|
||||
}
|
||||
|
||||
// Swap disk over
|
||||
diskStack = stack;
|
||||
diskMount = null;
|
||||
setChanged();
|
||||
this.media = media;
|
||||
|
||||
// Mount new disk
|
||||
if (!diskStack.isEmpty()) {
|
||||
var computers = this.computers.keySet();
|
||||
for (var computer : computers) mountDisk(computer);
|
||||
if (!this.media.stack.isEmpty()) {
|
||||
for (var computer : computers.entrySet()) mountDisk(computer.getKey(), computer.getValue(), this.media);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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() {
|
||||
return getItem(0);
|
||||
}
|
||||
|
||||
void setDiskStack(ItemStack stack) {
|
||||
setItem(0, stack);
|
||||
MediaStack getMedia() {
|
||||
return media;
|
||||
}
|
||||
|
||||
private @Nullable IMedia getDiskMedia() {
|
||||
return MediaProviders.get(getDiskStack());
|
||||
void setDiskStack(ItemStack stack) {
|
||||
setItem(0, stack);
|
||||
setChanged();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -277,95 +178,62 @@ public final class DiskDriveBlockEntity extends GenericTile implements DefaultIn
|
||||
|
||||
void mount(IComputerAccess computer) {
|
||||
synchronized (this) {
|
||||
computers.put(computer, new MountInfo());
|
||||
mountDisk(computer);
|
||||
var info = new MountInfo();
|
||||
computers.put(computer, info);
|
||||
mountDisk(computer, info, media);
|
||||
}
|
||||
}
|
||||
|
||||
void unmount(IComputerAccess computer) {
|
||||
synchronized (this) {
|
||||
unmountDisk(computer);
|
||||
computers.remove(computer);
|
||||
unmountDisk(computer, computers.remove(computer));
|
||||
}
|
||||
}
|
||||
|
||||
void playDiskAudio() {
|
||||
synchronized (this) {
|
||||
var media = getDiskMedia();
|
||||
if (media != null && media.getAudioTitle(diskStack) != null) {
|
||||
recordQueued = true;
|
||||
restartRecord = recordPlaying;
|
||||
}
|
||||
}
|
||||
recordQueued.set(RecordCommand.PLAY);
|
||||
}
|
||||
|
||||
void stopDiskAudio() {
|
||||
synchronized (this) {
|
||||
recordQueued = false;
|
||||
restartRecord = false;
|
||||
}
|
||||
recordQueued.set(RecordCommand.STOP);
|
||||
}
|
||||
|
||||
void ejectDisk() {
|
||||
synchronized (this) {
|
||||
ejectQueued = true;
|
||||
}
|
||||
ejectQueued.set(true);
|
||||
}
|
||||
|
||||
// private methods
|
||||
|
||||
private synchronized void mountDisk(IComputerAccess computer) {
|
||||
if (!diskStack.isEmpty()) {
|
||||
var info = assertNonNull(computers.get(computer));
|
||||
var contents = getDiskMedia();
|
||||
if (contents != null) {
|
||||
if (diskMount == null) {
|
||||
diskMount = contents.createDataMount(diskStack, getLevel());
|
||||
private void mountDisk(IComputerAccess computer, MountInfo info, MediaStack disk) {
|
||||
var mount = disk.getMount((ServerLevel) getLevel());
|
||||
if (mount != null) {
|
||||
if (mount instanceof IWritableMount writable) {
|
||||
// Try mounting at the lowest numbered "disk" name we can
|
||||
var n = 1;
|
||||
while (info.mountPath == null) {
|
||||
info.mountPath = computer.mountWritable(n == 1 ? "disk" : "disk" + n, writable);
|
||||
n++;
|
||||
}
|
||||
if (diskMount != null) {
|
||||
if (diskMount instanceof IWritableMount) {
|
||||
// Try mounting at the lowest numbered "disk" name we can
|
||||
var n = 1;
|
||||
while (info.mountPath == null) {
|
||||
info.mountPath = computer.mountWritable(n == 1 ? "disk" : "disk" + n, (IWritableMount) diskMount);
|
||||
n++;
|
||||
}
|
||||
} else {
|
||||
// Try mounting at the lowest numbered "disk" name we can
|
||||
var n = 1;
|
||||
while (info.mountPath == null) {
|
||||
info.mountPath = computer.mount(n == 1 ? "disk" : "disk" + n, diskMount);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info.mountPath = null;
|
||||
} else {
|
||||
// Try mounting at the lowest numbered "disk" name we can
|
||||
var n = 1;
|
||||
while (info.mountPath == null) {
|
||||
info.mountPath = computer.mount(n == 1 ? "disk" : "disk" + n, mount);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
computer.queueEvent("disk", computer.getAttachmentName());
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void unmountDisk(IComputerAccess computer) {
|
||||
if (!diskStack.isEmpty()) {
|
||||
var info = Objects.requireNonNull(computers.get(computer), "No mount info");
|
||||
if (info.mountPath != null) {
|
||||
computer.unmount(info.mountPath);
|
||||
info.mountPath = null;
|
||||
}
|
||||
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);
|
||||
info.mountPath = null;
|
||||
}
|
||||
|
||||
computer.queueEvent("disk", computer.getAttachmentName());
|
||||
}
|
||||
|
||||
private static void unmountDisk(IComputerAccess computer, MountInfo info) {
|
||||
if (info.mountPath != null) {
|
||||
computer.unmount(info.mountPath);
|
||||
info.mountPath = null;
|
||||
}
|
||||
|
||||
computer.queueEvent("disk_eject", computer.getAttachmentName());
|
||||
}
|
||||
|
||||
private void updateBlockState(DiskDriveState state) {
|
||||
@ -375,81 +243,32 @@ public final class DiskDriveBlockEntity extends GenericTile implements DefaultIn
|
||||
getLevel().setBlockAndUpdate(getBlockPos(), blockState.setValue(DiskDriveBlock.STATE, state));
|
||||
}
|
||||
|
||||
private synchronized void ejectContents(boolean destroyed) {
|
||||
if (getLevel().isClientSide || diskStack.isEmpty()) return;
|
||||
private void ejectContents() {
|
||||
if (getLevel().isClientSide) return;
|
||||
|
||||
// Remove the disks from the inventory
|
||||
var disks = diskStack;
|
||||
var stack = getDiskStack();
|
||||
if (stack.isEmpty()) return;
|
||||
setDiskStack(ItemStack.EMPTY);
|
||||
|
||||
// Spawn the item in the world
|
||||
var xOff = 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();
|
||||
}
|
||||
WorldUtil.dropItemStack(stack, getLevel(), getBlockPos(), getDirection());
|
||||
getLevel().levelEvent(LevelEvent.SOUND_DISPENSER_DISPENSE, getBlockPos(), 0);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomName() {
|
||||
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) {
|
||||
protected AbstractContainerMenu createMenu(int id, Inventory inventory) {
|
||||
return new DiskDriveMenu(id, inventory, this);
|
||||
}
|
||||
|
||||
public IPeripheral peripheral() {
|
||||
if (peripheral != null) return peripheral;
|
||||
return peripheral = new DiskDrivePeripheral(this);
|
||||
private enum RecordCommand {
|
||||
PLAY,
|
||||
STOP,
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.util.StringUtil;
|
||||
import dan200.computercraft.impl.MediaProviders;
|
||||
import dan200.computercraft.shared.media.items.DiskItem;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -53,20 +52,20 @@ public class DiskDrivePeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction
|
||||
public final boolean isDiskPresent() {
|
||||
return !diskDrive.getDiskStack().isEmpty();
|
||||
return !diskDrive.getMedia().stack.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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
|
||||
public final @Nullable Object[] getDiskLabel() {
|
||||
var stack = diskDrive.getDiskStack();
|
||||
var media = MediaProviders.get(stack);
|
||||
return media == null ? null : new Object[]{ media.getLabel(stack) };
|
||||
public final Object[] getDiskLabel() {
|
||||
var media = diskDrive.getMedia();
|
||||
return media.media == null ? null : new Object[]{ media.media.getLabel(media.stack) };
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,11 +81,11 @@ public class DiskDrivePeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction(mainThread = true)
|
||||
public final void setDiskLabel(Optional<String> label) throws LuaException {
|
||||
var stack = diskDrive.getDiskStack();
|
||||
var media = MediaProviders.get(stack);
|
||||
if (media == null) return;
|
||||
var media = diskDrive.getMedia();
|
||||
if (media.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");
|
||||
}
|
||||
diskDrive.setDiskStack(stack);
|
||||
@ -122,9 +121,7 @@ public class DiskDrivePeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction
|
||||
public final boolean hasAudio() {
|
||||
var stack = diskDrive.getDiskStack();
|
||||
var media = MediaProviders.get(stack);
|
||||
return media != null && media.getAudio(stack) != null;
|
||||
return diskDrive.getMedia().getAudio() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -136,9 +133,7 @@ public class DiskDrivePeripheral implements IPeripheral {
|
||||
@LuaFunction
|
||||
@Nullable
|
||||
public final Object getAudioTitle() {
|
||||
var stack = diskDrive.getDiskStack();
|
||||
var media = MediaProviders.get(stack);
|
||||
return media != null ? media.getAudioTitle(stack) : false;
|
||||
return diskDrive.getMedia().getAudioTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,12 +166,13 @@ public class DiskDrivePeripheral implements IPeripheral {
|
||||
* 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.
|
||||
* @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
|
||||
*/
|
||||
@Nullable
|
||||
@LuaFunction
|
||||
public final @Nullable Object[] getDiskID() {
|
||||
var disk = diskDrive.getDiskStack();
|
||||
public final Object[] getDiskID() {
|
||||
var disk = diskDrive.getMedia().stack;
|
||||
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 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa
|
||||
if (this.network != null) this.network.addReceiver(this);
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
public void removed() {
|
||||
setNetwork(null);
|
||||
}
|
||||
|
||||
|
@ -8,24 +8,30 @@ package dan200.computercraft.shared.peripheral.modem.wired;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import dan200.computercraft.annotations.ForgeOverride;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.common.GenericBlock;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
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.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||
import net.minecraft.world.level.*;
|
||||
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.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
@ -36,7 +42,7 @@ import java.util.EnumMap;
|
||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
||||
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 BooleanProperty CABLE = BooleanProperty.create("cable");
|
||||
|
||||
@ -55,7 +61,7 @@ public class CableBlock extends GenericBlock implements SimpleWaterloggedBlock {
|
||||
.build());
|
||||
|
||||
public CableBlock(Properties settings) {
|
||||
super(settings, ModRegistry.BlockEntities.CABLE);
|
||||
super(settings);
|
||||
|
||||
registerDefaultState(getStateDefinition().any()
|
||||
.setValue(MODEM, CableModemVariant.None)
|
||||
@ -218,4 +224,33 @@ public class CableBlock extends GenericBlock implements SimpleWaterloggedBlock {
|
||||
.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.network.wired.IWiredNode;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.command.text.ChatHelpers;
|
||||
import dan200.computercraft.shared.common.GenericTile;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||
import dan200.computercraft.shared.platform.ComponentAccess;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
@ -22,21 +21,20 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
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 java.util.Collections;
|
||||
|
||||
public class CableBlockEntity extends GenericTile {
|
||||
public class CableBlockEntity extends BlockEntity {
|
||||
private static final String NBT_PERIPHERAL_ENABLED = "PeirpheralAccess";
|
||||
|
||||
private class CableElement extends WiredModemElement {
|
||||
@ -66,8 +64,6 @@ public class CableBlockEntity extends GenericTile {
|
||||
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral(this::queueRefreshPeripheral);
|
||||
private @Nullable Runnable modemChanged;
|
||||
|
||||
private boolean destroyed = false;
|
||||
|
||||
private boolean connectionsFormed = false;
|
||||
|
||||
private final WiredModemElement cable = new CableElement();
|
||||
@ -106,24 +102,16 @@ public class CableBlockEntity extends GenericTile {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (!destroyed) {
|
||||
destroyed = true;
|
||||
modem.destroy();
|
||||
onRemove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
modem.removed();
|
||||
onRemove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRemoved() {
|
||||
super.clearRemoved(); // TODO: Replace with onLoad
|
||||
super.clearRemoved();
|
||||
TickScheduler.schedule(tickToken);
|
||||
}
|
||||
|
||||
@ -147,8 +135,7 @@ public class CableBlockEntity extends GenericTile {
|
||||
return direction == null ? Direction.NORTH : direction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourChange(BlockPos neighbour) {
|
||||
void neighborChanged(BlockPos neighbour) {
|
||||
var dir = getDirection();
|
||||
if (neighbour.equals(getBlockPos().relative(dir)) && hasModem() && !getBlockState().canSurvive(getLevel(), getBlockPos())) {
|
||||
if (hasCable()) {
|
||||
@ -167,12 +154,6 @@ public class CableBlockEntity extends GenericTile {
|
||||
return;
|
||||
}
|
||||
|
||||
onNeighbourTileEntityChange(neighbour);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
||||
super.onNeighbourTileEntityChange(neighbour);
|
||||
if (!level.isClientSide && peripheralAccessAllowed) {
|
||||
var facing = getDirection();
|
||||
if (getBlockPos().relative(facing).equals(neighbour)) queueRefreshPeripheral();
|
||||
@ -192,8 +173,7 @@ public class CableBlockEntity extends GenericTile {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
InteractionResult use(Player player) {
|
||||
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
||||
if (!canAttachPeripheral()) return InteractionResult.FAIL;
|
||||
|
||||
@ -241,8 +221,7 @@ public class CableBlockEntity extends GenericTile {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockTick() {
|
||||
void blockTick() {
|
||||
if (getLevel().isClientSide) return;
|
||||
|
||||
if (invalidPeripheral) refreshPeripheral();
|
||||
@ -331,13 +310,11 @@ public class CableBlockEntity extends GenericTile {
|
||||
|
||||
@Nullable
|
||||
public IWiredElement getWiredElement(@Nullable Direction direction) {
|
||||
if (destroyed) return null;
|
||||
return direction == null || CableBlock.canConnectIn(getBlockState(), direction) ? cable : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
||||
if (destroyed) return null;
|
||||
return direction == null || getMaybeDirection() == direction ? modem : null;
|
||||
}
|
||||
|
||||
|
@ -5,19 +5,32 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.modem.wired;
|
||||
|
||||
import dan200.computercraft.annotations.ForgeOverride;
|
||||
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.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.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 PERIPHERAL_ON = BooleanProperty.create("peripheral");
|
||||
|
||||
public WiredModemFullBlock(Properties settings) {
|
||||
super(settings, ModRegistry.BlockEntities.WIRED_MODEM_FULL);
|
||||
super(settings);
|
||||
registerDefaultState(getStateDefinition().any()
|
||||
.setValue(MODEM_ON, false)
|
||||
.setValue(PERIPHERAL_ON, false)
|
||||
@ -28,4 +41,33 @@ public class WiredModemFullBlock extends GenericBlock {
|
||||
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
|
||||
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.IWiredElement;
|
||||
import dan200.computercraft.api.network.wired.IWiredNode;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.command.text.ChatHelpers;
|
||||
import dan200.computercraft.shared.common.GenericTile;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||
import dan200.computercraft.shared.platform.ComponentAccess;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
@ -21,13 +20,12 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
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.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 net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -36,7 +34,7 @@ import java.util.*;
|
||||
import static dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlock.MODEM_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 class FullElement extends WiredModemElement {
|
||||
@ -78,7 +76,6 @@ public class WiredModemFullBlockEntity extends GenericTile {
|
||||
private boolean peripheralAccessAllowed = false;
|
||||
private final WiredModemLocalPeripheral[] peripherals = new WiredModemLocalPeripheral[6];
|
||||
|
||||
private boolean destroyed = false;
|
||||
private boolean connectionsFormed = false;
|
||||
|
||||
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
||||
@ -98,35 +95,16 @@ public class WiredModemFullBlockEntity extends GenericTile {
|
||||
}
|
||||
}
|
||||
|
||||
private void doRemove() {
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
if (level == null || !level.isClientSide) {
|
||||
node.remove();
|
||||
connectionsFormed = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
void neighborChanged(BlockPos neighbour) {
|
||||
if (!level.isClientSide && peripheralAccessAllowed) {
|
||||
for (var facing : DirectionUtil.FACINGS) {
|
||||
if (getBlockPos().relative(facing).equals(neighbour)) queueRefreshPeripheral(facing);
|
||||
@ -147,8 +125,7 @@ public class WiredModemFullBlockEntity extends GenericTile {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
public InteractionResult use(Player player) {
|
||||
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
||||
if (getLevel().isClientSide) return InteractionResult.SUCCESS;
|
||||
|
||||
@ -204,12 +181,11 @@ public class WiredModemFullBlockEntity extends GenericTile {
|
||||
|
||||
@Override
|
||||
public void clearRemoved() {
|
||||
super.clearRemoved(); // TODO: Replace with onLoad
|
||||
super.clearRemoved();
|
||||
TickScheduler.schedule(tickToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockTick() {
|
||||
void blockTick() {
|
||||
if (getLevel().isClientSide) return;
|
||||
|
||||
if (invalidSides != 0) {
|
||||
@ -288,7 +264,7 @@ public class WiredModemFullBlockEntity extends GenericTile {
|
||||
|
||||
Map<String, IPeripheral> peripherals = new HashMap<>(6);
|
||||
for (var peripheral : this.peripherals) peripheral.extendMap(peripherals);
|
||||
return peripherals;
|
||||
return Collections.unmodifiableMap(peripherals);
|
||||
}
|
||||
|
||||
private void updateConnectedPeripherals() {
|
||||
|
@ -219,6 +219,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
|
||||
public void attach(IComputerAccess computer) {
|
||||
super.attach(computer);
|
||||
|
||||
@ -236,6 +237,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("UnsynchronizedOverridesSynchronized")
|
||||
public void detach(IComputerAccess computer) {
|
||||
Map<String, RemotePeripheralWrapper> wrappers;
|
||||
synchronized (peripheralWrappers) {
|
||||
|
@ -5,26 +5,23 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.modem.wireless;
|
||||
|
||||
import dan200.computercraft.shared.common.GenericBlock;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemShapes;
|
||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
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.level.BlockGetter;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
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.SimpleWaterloggedBlock;
|
||||
import net.minecraft.world.level.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.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
@ -34,12 +31,15 @@ import javax.annotation.Nullable;
|
||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
|
||||
import static dan200.computercraft.shared.util.WaterloggableHelpers.getFluidStateForPlacement;
|
||||
|
||||
public class WirelessModemBlock extends GenericBlock implements SimpleWaterloggedBlock {
|
||||
public static final DirectionProperty FACING = BlockStateProperties.FACING;
|
||||
public class WirelessModemBlock extends DirectionalBlock implements SimpleWaterloggedBlock, EntityBlock {
|
||||
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) {
|
||||
super(settings, type);
|
||||
super(settings);
|
||||
this.type = type;
|
||||
|
||||
registerDefaultState(getStateDefinition().any()
|
||||
.setValue(FACING, Direction.NORTH)
|
||||
.setValue(ON, false)
|
||||
@ -98,4 +98,17 @@ public class WirelessModemBlock extends GenericBlock implements SimpleWaterlogge
|
||||
public BlockState rotate(BlockState state, Rotation rot) {
|
||||
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;
|
||||
|
||||
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.ModemState;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class WirelessModemBlockEntity extends GenericTile {
|
||||
public class WirelessModemBlockEntity extends BlockEntity {
|
||||
private static class Peripheral extends WirelessModemPeripheral {
|
||||
private final WirelessModemBlockEntity entity;
|
||||
|
||||
@ -52,7 +52,6 @@ public class WirelessModemBlockEntity extends GenericTile {
|
||||
private final boolean advanced;
|
||||
|
||||
private final ModemPeripheral modem;
|
||||
private boolean destroyed = false;
|
||||
private @Nullable Runnable modemChanged;
|
||||
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
||||
|
||||
@ -63,17 +62,15 @@ public class WirelessModemBlockEntity extends GenericTile {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRemoved() {
|
||||
super.clearRemoved(); // TODO: Replace with onLoad
|
||||
TickScheduler.schedule(tickToken);
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
modem.removed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (!destroyed) {
|
||||
modem.destroy();
|
||||
destroyed = true;
|
||||
}
|
||||
public void clearRemoved() {
|
||||
super.clearRemoved();
|
||||
TickScheduler.schedule(tickToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -84,8 +81,7 @@ public class WirelessModemBlockEntity extends GenericTile {
|
||||
if (getDirection() != direction && modemChanged != null) modemChanged.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockTick() {
|
||||
void blockTick() {
|
||||
if (modem.getModemState().pollChanged()) updateBlockState();
|
||||
}
|
||||
|
||||
@ -103,7 +99,6 @@ public class WirelessModemBlockEntity extends GenericTile {
|
||||
|
||||
@Nullable
|
||||
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
||||
if (destroyed) return null;
|
||||
return direction == null || getDirection() == direction ? modem : null;
|
||||
}
|
||||
|
||||
|
@ -5,38 +5,47 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.monitor;
|
||||
|
||||
import dan200.computercraft.shared.common.GenericBlock;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
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.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.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
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.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class MonitorBlock extends GenericBlock {
|
||||
public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBlock {
|
||||
public static final DirectionProperty ORIENTATION = DirectionProperty.create("orientation",
|
||||
Direction.UP, Direction.DOWN, Direction.NORTH);
|
||||
|
||||
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||
|
||||
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) {
|
||||
super(settings, type);
|
||||
super(settings);
|
||||
this.type = type;
|
||||
|
||||
// TODO: Test underwater - do we need isSolid at all?
|
||||
registerDefaultState(getStateDefinition().any()
|
||||
.setValue(ORIENTATION, Direction.NORTH)
|
||||
@ -49,18 +58,6 @@ public class MonitorBlock extends GenericBlock {
|
||||
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
|
||||
@Nullable
|
||||
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
||||
@ -81,6 +78,41 @@ public class MonitorBlock extends GenericBlock {
|
||||
.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
|
||||
public void setPlacedBy(Level world, BlockPos pos, BlockState blockState, @Nullable LivingEntity livingEntity, ItemStack itemStack) {
|
||||
super.setPlacedBy(world, pos, blockState, livingEntity, itemStack);
|
||||
@ -96,4 +128,10 @@ public class MonitorBlock extends GenericBlock {
|
||||
monitor.expand();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity newBlockEntity(BlockPos blockPos, BlockState blockState) {
|
||||
return type.get().create(blockPos, blockState);
|
||||
}
|
||||
}
|
||||
|
@ -10,21 +10,18 @@ import dan200.computercraft.annotations.ForgeOverride;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.common.GenericTile;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
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.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -33,7 +30,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class MonitorBlockEntity extends GenericTile {
|
||||
public class MonitorBlockEntity extends BlockEntity {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MonitorBlockEntity.class);
|
||||
|
||||
public static final double RENDER_BORDER = 2.0 / 16.0;
|
||||
@ -79,17 +76,14 @@ public class MonitorBlockEntity extends GenericTile {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRemoved() { // TODO: Switch back to onLood
|
||||
public void clearRemoved() {
|
||||
super.clearRemoved();
|
||||
needsValidating = true; // Same, tbh
|
||||
TickScheduler.schedule(tickToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
void destroy() {
|
||||
// TODO: Call this before using the block
|
||||
if (destroyed) return;
|
||||
destroyed = true;
|
||||
if (!getLevel().isClientSide) contractNeighbours();
|
||||
}
|
||||
|
||||
@ -99,22 +93,6 @@ public class MonitorBlockEntity extends GenericTile {
|
||||
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
|
||||
public void saveAdditional(CompoundTag tag) {
|
||||
tag.putInt(NBT_X, xIndex);
|
||||
@ -128,14 +106,18 @@ public class MonitorBlockEntity extends GenericTile {
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(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 (level != null && level.isClientSide) onClientLoad(oldXIndex, oldYIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockTick() {
|
||||
void blockTick() {
|
||||
if (needsValidating) {
|
||||
needsValidating = false;
|
||||
validate();
|
||||
@ -223,18 +205,7 @@ public class MonitorBlockEntity extends GenericTile {
|
||||
return nbt;
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
|
||||
private void onClientLoad(int oldXIndex, int oldYIndex) {
|
||||
if (oldXIndex != xIndex || oldYIndex != yIndex) {
|
||||
// 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.
|
||||
@ -401,7 +372,7 @@ public class MonitorBlockEntity extends GenericTile {
|
||||
monitor.serverMonitor = serverMonitor;
|
||||
monitor.needsUpdate = monitor.needsValidating = false;
|
||||
monitor.updateBlockState();
|
||||
monitor.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(monitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -476,7 +447,7 @@ public class MonitorBlockEntity extends GenericTile {
|
||||
}
|
||||
// endregion
|
||||
|
||||
private void monitorTouched(float xPos, float yPos, float zPos) {
|
||||
void monitorTouched(float xPos, float yPos, float zPos) {
|
||||
if (!advanced) return;
|
||||
|
||||
var pair = XYPair
|
||||
|
@ -34,11 +34,11 @@ public class ServerMonitor {
|
||||
|
||||
var textScale = this.textScale * 0.5;
|
||||
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
|
||||
);
|
||||
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
|
||||
);
|
||||
|
||||
|
@ -6,35 +6,23 @@
|
||||
package dan200.computercraft.shared.peripheral.printer;
|
||||
|
||||
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.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.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PrinterBlock extends GenericBlock {
|
||||
private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||
public class PrinterBlock extends HorizontalContainerBlock {
|
||||
public static final BooleanProperty TOP = BooleanProperty.create("top");
|
||||
public static final BooleanProperty BOTTOM = BooleanProperty.create("bottom");
|
||||
|
||||
public PrinterBlock(Properties settings) {
|
||||
super(settings, ModRegistry.BlockEntities.PRINTER);
|
||||
super(settings);
|
||||
registerDefaultState(getStateDefinition().any()
|
||||
.setValue(FACING, Direction.NORTH)
|
||||
.setValue(TOP, false)
|
||||
@ -46,42 +34,9 @@ public class PrinterBlock extends GenericBlock {
|
||||
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
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
||||
return defaultBlockState().setValue(FACING, placement.getHorizontalDirection().getOpposite());
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
|
||||
return ModRegistry.BlockEntities.PRINTER.get().create(pos, state);
|
||||
}
|
||||
}
|
||||
|
@ -6,34 +6,26 @@
|
||||
package dan200.computercraft.shared.peripheral.printer;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.common.GenericTile;
|
||||
import dan200.computercraft.shared.common.AbstractContainerBlockEntity;
|
||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||
import dan200.computercraft.shared.container.BasicWorldlyContainer;
|
||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
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.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.*;
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
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.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class PrinterBlockEntity extends GenericTile implements DefaultSidedInventory, Nameable, MenuProvider {
|
||||
private static final String NBT_NAME = "CustomName";
|
||||
public final class PrinterBlockEntity extends AbstractContainerBlockEntity implements BasicWorldlyContainer {
|
||||
private static final String NBT_PRINTING = "Printing";
|
||||
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[] SIDE_SLOTS = new int[]{ 0 };
|
||||
|
||||
@Nullable
|
||||
Component customName;
|
||||
private LockCode lockCode = LockCode.NO_LOCK;
|
||||
|
||||
private final PrinterPeripheral peripheral = new PrinterPeripheral(this);
|
||||
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 String pageTitle = "";
|
||||
@ -58,30 +46,14 @@ public final class PrinterBlockEntity extends GenericTile implements DefaultSide
|
||||
super(type, pos, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
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;
|
||||
public IPeripheral peripheral() {
|
||||
return peripheral;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
|
||||
customName = nbt.contains(NBT_NAME) ? Component.Serializer.fromJson(nbt.getString(NBT_NAME)) : null;
|
||||
|
||||
// Read page
|
||||
synchronized (page) {
|
||||
printing = nbt.getBoolean(NBT_PRINTING);
|
||||
@ -91,91 +63,35 @@ public final class PrinterBlockEntity extends GenericTile implements DefaultSide
|
||||
|
||||
// Read inventory
|
||||
ContainerHelper.loadAllItems(nbt, inventory);
|
||||
|
||||
lockCode = LockCode.fromTag(nbt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveAdditional(CompoundTag nbt) {
|
||||
if (customName != null) nbt.putString(NBT_NAME, Component.Serializer.toJson(customName));
|
||||
|
||||
public void saveAdditional(CompoundTag tag) {
|
||||
// Write page
|
||||
synchronized (page) {
|
||||
nbt.putBoolean(NBT_PRINTING, printing);
|
||||
nbt.putString(NBT_PAGE_TITLE, pageTitle);
|
||||
page.writeToNBT(nbt);
|
||||
tag.putBoolean(NBT_PRINTING, printing);
|
||||
tag.putString(NBT_PAGE_TITLE, pageTitle);
|
||||
page.writeToNBT(tag);
|
||||
}
|
||||
|
||||
// Write inventory
|
||||
ContainerHelper.saveAllItems(nbt, inventory);
|
||||
ContainerHelper.saveAllItems(tag, inventory);
|
||||
|
||||
lockCode.addToTag(nbt);
|
||||
|
||||
super.saveAdditional(nbt);
|
||||
super.saveAdditional(tag);
|
||||
}
|
||||
|
||||
boolean isPrinting() {
|
||||
return printing;
|
||||
}
|
||||
|
||||
// IInventory implementation
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
return inventory.size();
|
||||
public NonNullList<ItemStack> getContents() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
for (var stack : inventory) {
|
||||
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();
|
||||
public void setChanged() {
|
||||
super.setChanged();
|
||||
updateBlockState();
|
||||
}
|
||||
|
||||
@ -190,24 +106,17 @@ public final class PrinterBlockEntity extends GenericTile implements DefaultSide
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player playerEntity) {
|
||||
return isUsable(playerEntity);
|
||||
}
|
||||
|
||||
// ISidedInventory implementation
|
||||
|
||||
@Override
|
||||
public int[] getSlotsForFace(Direction side) {
|
||||
return switch (side) {
|
||||
case DOWN -> BOTTOM_SLOTS; // Out tray
|
||||
case UP -> TOP_SLOTS; // In tray
|
||||
default -> SIDE_SLOTS; // Ink
|
||||
case DOWN -> BOTTOM_SLOTS; // Bottom (Out tray)
|
||||
case UP -> TOP_SLOTS; // Top (In tray)
|
||||
default -> SIDE_SLOTS; // Sides (Ink)
|
||||
};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Terminal getCurrentPage() {
|
||||
NetworkedTerminal getCurrentPage() {
|
||||
synchronized (page) {
|
||||
return printing ? page : null;
|
||||
}
|
||||
@ -325,19 +234,6 @@ public final class PrinterBlockEntity extends GenericTile implements DefaultSide
|
||||
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() {
|
||||
boolean top = false, bottom = false;
|
||||
for (var i = 1; i < 7; i++) {
|
||||
@ -367,34 +263,8 @@ public final class PrinterBlockEntity extends GenericTile implements DefaultSide
|
||||
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
|
||||
public boolean hasCustomName() {
|
||||
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) {
|
||||
protected AbstractContainerMenu createMenu(int id, Inventory inventory) {
|
||||
return new PrinterMenu(id, inventory, this);
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
package dan200.computercraft.shared.peripheral.printer;
|
||||
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.util.SingleIntArray;
|
||||
import dan200.computercraft.shared.util.ValidatingSlot;
|
||||
import dan200.computercraft.shared.container.SingleContainerData;
|
||||
import dan200.computercraft.shared.container.ValidatingSlot;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
@ -58,7 +58,7 @@ public class PrinterMenu extends AbstractContainerMenu {
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -6,31 +6,27 @@
|
||||
package dan200.computercraft.shared.peripheral.speaker;
|
||||
|
||||
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.world.item.context.BlockPlaceContext;
|
||||
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.Mirror;
|
||||
import net.minecraft.world.level.block.Rotation;
|
||||
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.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SpeakerBlock extends GenericBlock {
|
||||
private static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
|
||||
|
||||
public class SpeakerBlock extends HorizontalDirectionalBlock implements EntityBlock {
|
||||
private static final BlockEntityTicker<SpeakerBlockEntity> serverTicker = (level, pos, state, drive) -> drive.serverTick();
|
||||
|
||||
public SpeakerBlock(Properties settings) {
|
||||
super(settings, ModRegistry.BlockEntities.SPEAKER);
|
||||
super(settings);
|
||||
registerDefaultState(getStateDefinition().any()
|
||||
.setValue(FACING, Direction.NORTH));
|
||||
}
|
||||
@ -40,18 +36,6 @@ public class SpeakerBlock extends GenericBlock {
|
||||
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
|
||||
@Override
|
||||
public BlockState getStateForPlacement(BlockPlaceContext placement) {
|
||||
@ -61,6 +45,12 @@ public class SpeakerBlock extends GenericBlock {
|
||||
@Override
|
||||
@Nullable
|
||||
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 @@ package dan200.computercraft.shared.peripheral.speaker;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.common.GenericTile;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
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.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class SpeakerBlockEntity extends GenericTile {
|
||||
public class SpeakerBlockEntity extends BlockEntity {
|
||||
private final SpeakerPeripheral peripheral;
|
||||
|
||||
public SpeakerBlockEntity(BlockEntityType<SpeakerBlockEntity> type, BlockPos pos, BlockState state) {
|
||||
|
@ -15,9 +15,11 @@ import dan200.computercraft.shared.platform.RegistryEntry;
|
||||
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
||||
import dan200.computercraft.shared.turtle.items.ITurtleItem;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItemFactory;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import dan200.computercraft.shared.util.WaterloggableHelpers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.Containers;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
||||
@ -27,7 +29,9 @@ import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Explosion;
|
||||
import net.minecraft.world.level.Level;
|
||||
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.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
@ -69,18 +73,6 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
||||
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
|
||||
@Deprecated
|
||||
public RenderShape getRenderShape(BlockState state) {
|
||||
@ -116,6 +108,19 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
||||
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
|
||||
public void setPlacedBy(Level world, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
||||
super.setPlacedBy(world, pos, state, entity, stack);
|
||||
@ -161,6 +166,6 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
||||
@Override
|
||||
@Nullable
|
||||
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.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
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.ComputerPeripheral;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.container.BasicContainer;
|
||||
import dan200.computercraft.shared.turtle.apis.TurtleAPI;
|
||||
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
||||
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.Direction;
|
||||
import net.minecraft.core.NonNullList;
|
||||
@ -43,13 +39,12 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
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 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_WIDTH = 4;
|
||||
public static final int INVENTORY_HEIGHT = 4;
|
||||
@ -68,7 +63,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
private @Nullable IPeripheral peripheral;
|
||||
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);
|
||||
}
|
||||
|
||||
@ -88,39 +83,13 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
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
|
||||
protected void unload() {
|
||||
if (!hasMoved()) {
|
||||
super.unload();
|
||||
}
|
||||
if (!hasMoved()) super.unload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
public InteractionResult use(Player player, InteractionHand hand) {
|
||||
// Apply dye
|
||||
var currentItem = player.getItemInHand(hand);
|
||||
if (!currentItem.isEmpty()) {
|
||||
@ -152,7 +121,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
}
|
||||
|
||||
// Open GUI or whatever
|
||||
return super.onActivate(player, hand, hit);
|
||||
return super.use(player, hand);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -161,7 +130,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double getInteractRange(Player player) {
|
||||
protected double getInteractRange() {
|
||||
return 12.0;
|
||||
}
|
||||
|
||||
@ -189,13 +158,8 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourChange(BlockPos neighbour) {
|
||||
if (moveState == MoveState.NOT_MOVED) super.onNeighbourChange(neighbour);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourTileEntityChange(BlockPos neighbour) {
|
||||
if (moveState == MoveState.NOT_MOVED) super.onNeighbourTileEntityChange(neighbour);
|
||||
public void neighborChanged(BlockPos neighbour) {
|
||||
if (moveState == MoveState.NOT_MOVED) super.neighborChanged(neighbour);
|
||||
}
|
||||
|
||||
public void notifyMoveStart() {
|
||||
@ -208,8 +172,8 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(CompoundTag nbt) {
|
||||
super.load(nbt);
|
||||
public void loadServer(CompoundTag nbt) {
|
||||
super.loadServer(nbt);
|
||||
|
||||
// Read inventory
|
||||
var nbttaglist = nbt.getList("Items", Tag.TAG_COMPOUND);
|
||||
@ -315,66 +279,8 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
// IInventory
|
||||
|
||||
@Override
|
||||
public int getContainerSize() {
|
||||
return INVENTORY_SIZE;
|
||||
}
|
||||
|
||||
@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();
|
||||
public NonNullList<ItemStack> getContents() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -395,11 +301,6 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
return isUsable(player);
|
||||
}
|
||||
|
||||
private void onInventoryDefinitelyChanged() {
|
||||
super.setChanged();
|
||||
inventoryChanged = true;
|
||||
}
|
||||
|
||||
public void onTileEntityChange() {
|
||||
super.setChanged();
|
||||
}
|
||||
@ -414,8 +315,8 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements IT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleUpdateTag(CompoundTag nbt) {
|
||||
super.handleUpdateTag(nbt);
|
||||
public void loadClient(CompoundTag nbt) {
|
||||
super.loadClient(nbt);
|
||||
brain.readDescription(nbt);
|
||||
}
|
||||
|
||||
|
@ -17,11 +17,12 @@ import dan200.computercraft.impl.TurtleUpgrades;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.container.InventoryDelegate;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import dan200.computercraft.shared.util.Holiday;
|
||||
import dan200.computercraft.shared.util.HolidayUtil;
|
||||
import dan200.computercraft.shared.util.InventoryDelegate;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
@ -345,6 +346,8 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
yaw += 360.0f;
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
return yaw;
|
||||
}
|
||||
@ -454,7 +457,7 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
animationProgress = 0;
|
||||
lastAnimationProgress = 0;
|
||||
}
|
||||
owner.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getOverlay() {
|
||||
@ -464,7 +467,7 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
public void setOverlay(ResourceLocation overlay) {
|
||||
if (!Objects.equal(this.overlay, overlay)) {
|
||||
this.overlay = overlay;
|
||||
owner.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,7 +484,7 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
}
|
||||
if (colourHex != newColour) {
|
||||
colourHex = newColour;
|
||||
owner.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,11 +493,11 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
if (colour >= 0 && colour <= 0xFFFFFF) {
|
||||
if (colourHex != colour) {
|
||||
colourHex = colour;
|
||||
owner.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
}
|
||||
} else if (colourHex != -1) {
|
||||
colourHex = -1;
|
||||
owner.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,7 +528,7 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
// 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
|
||||
// updateBlock for us.
|
||||
owner.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
|
||||
// Recompute peripherals in case an upgrade being removed has exposed a new peripheral.
|
||||
// TODO: Only update peripherals, or even only two sides?
|
||||
@ -568,7 +571,7 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
|
||||
@Override
|
||||
public void updateUpgradeNBTData(TurtleSide side) {
|
||||
owner.updateBlock();
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
}
|
||||
|
||||
public Vec3 getRenderOffset(float f) {
|
||||
|
@ -12,7 +12,7 @@ import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
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.SimpleContainer;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
@ -65,7 +65,7 @@ public final class TurtleMenu extends AbstractComputerMenu {
|
||||
return new TurtleMenu(
|
||||
// Laziness in turtle.getOwner() is important here!
|
||||
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 class TurtleInventoryCrafting extends CraftingContainer {
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
return Collections.unmodifiableList(results);
|
||||
}
|
||||
|
||||
@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 final class RecipeUtil {
|
||||
Set<Character> missingKeys = Sets.newHashSet(ingMap.keySet());
|
||||
missingKeys.remove(' ');
|
||||
|
||||
var i = 0;
|
||||
var ingredientIdx = 0;
|
||||
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);
|
||||
if (ing == null) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import javax.annotation.Nullable;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class WorldUtil {
|
||||
@SuppressWarnings("UnnecessaryLambda")
|
||||
private static final Predicate<Entity> CAN_COLLIDE = x -> x != null && x.isAlive() && x.isPickable();
|
||||
|
||||
public static boolean isLiquidBlock(Level world, BlockPos pos) {
|
||||
|
@ -24,7 +24,7 @@ public class ItemStackMatcher extends TypeSafeMatcher<ItemStack> {
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendValue(stack);
|
||||
description.appendValue(stack).appendValue(stack.getTag());
|
||||
}
|
||||
|
||||
public static Matcher<ItemStack> isStack(ItemStack stack) {
|
||||
|
@ -35,7 +35,7 @@ class GameTestSequenceMixin {
|
||||
// Mimic the original behaviour.
|
||||
} catch (AssertionError e) {
|
||||
parent.fail(e);
|
||||
} catch (Exception e) {
|
||||
} catch (Exception | LinkageError | VirtualMachineError e) {
|
||||
// Fail the test, rather than crashing the server.
|
||||
TestHooks.LOG.error("{} threw unexpected exception", parent.getTestName(), e);
|
||||
parent.fail(e);
|
||||
|
@ -6,15 +6,19 @@
|
||||
package dan200.computercraft.gametest
|
||||
|
||||
import dan200.computercraft.core.apis.FSAPI
|
||||
import dan200.computercraft.gametest.api.GameTestHolder
|
||||
import dan200.computercraft.gametest.api.sequence
|
||||
import dan200.computercraft.gametest.api.thenOnComputer
|
||||
import dan200.computercraft.gametest.api.*
|
||||
import dan200.computercraft.shared.ModRegistry
|
||||
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.computer.getApi
|
||||
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
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
||||
@GameTestHolder
|
||||
@ -52,4 +56,70 @@ class Disk_Drive_Test {
|
||||
thenIdle(2)
|
||||
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
|
||||
|
||||
import dan200.computercraft.gametest.api.GameTestHolder
|
||||
import dan200.computercraft.gametest.api.getBlockEntity
|
||||
import dan200.computercraft.gametest.api.sequence
|
||||
import dan200.computercraft.gametest.api.setBlock
|
||||
import dan200.computercraft.gametest.api.*
|
||||
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.core.BlockPos
|
||||
import net.minecraft.gametest.framework.GameTest
|
||||
@ -47,4 +46,16 @@ class Monitor_Test {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.hamcrest.Matchers.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotEquals
|
||||
import java.util.*
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@GameTestHolder
|
||||
class Turtle_Test {
|
||||
@ -402,7 +403,9 @@ class Turtle_Test {
|
||||
val testInfo = (helper as GameTestHelperAccessor).testInfo as GameTestInfoAccessor
|
||||
|
||||
val events = mutableListOf<Pair<String, String>>()
|
||||
var running = false
|
||||
thenStartComputer("listen") {
|
||||
running = true
|
||||
while (true) {
|
||||
val event = pullEvent()
|
||||
TestHooks.LOG.info("[{}] Got event {} at tick {}", testInfo, event[0], testInfo.`computercraft$getTick`())
|
||||
@ -411,8 +414,9 @@ class Turtle_Test {
|
||||
}
|
||||
}
|
||||
}
|
||||
thenIdle(2)
|
||||
thenOnComputer("turtle") {
|
||||
while (!running) sleep(10.milliseconds)
|
||||
|
||||
turtle.forward().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`())
|
||||
|
@ -11,6 +11,7 @@ import dan200.computercraft.mixin.gametest.GameTestSequenceAccessor
|
||||
import dan200.computercraft.shared.platform.PlatformHelper
|
||||
import dan200.computercraft.shared.platform.Registries
|
||||
import dan200.computercraft.test.core.computer.LuaTaskContext
|
||||
import dan200.computercraft.test.shared.ItemStackMatcher.isStack
|
||||
import net.minecraft.commands.arguments.blocks.BlockInput
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
@ -24,6 +25,8 @@ 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.level.block.state.properties.Property
|
||||
import org.hamcrest.Matchers
|
||||
import org.hamcrest.StringDescription
|
||||
|
||||
/**
|
||||
* Globally usable structures.
|
||||
@ -202,6 +205,16 @@ fun GameTestHelper.assertNoPeripheral(pos: BlockPos, direction: Direction = Dire
|
||||
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)!!
|
||||
|
||||
/**
|
||||
|
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") {
|
||||
source(sourceSets["testMod"])
|
||||
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)
|
||||
|
||||
testModImplementation(testFixtures(project(":core")))
|
||||
testModImplementation(testFixtures(project(":forge")))
|
||||
|
||||
"cctJavadoc"(libs.cctJavadoc)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
@AutoService(ClientPlatformHelper.class)
|
||||
@AutoService(dan200.computercraft.impl.client.ClientPlatformHelper.class)
|
||||
public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
@Override
|
||||
public BakedModel getModel(ModelManager manager, ResourceLocation location) {
|
||||
|
@ -7,6 +7,8 @@ package dan200.computercraft.shared.util;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
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.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
@ -14,6 +16,7 @@ import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
/**
|
||||
* A {@link ICapabilityProvider} which provides a different single capability, with different instances for each
|
||||
@ -28,15 +31,21 @@ import java.util.Objects;
|
||||
public final class SidedCapabilityProvider<T> implements ICapabilityProvider {
|
||||
private final Capability<T> cap;
|
||||
private final Provider<T> supplier;
|
||||
private final BooleanSupplier isRemoved;
|
||||
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.supplier = supplier;
|
||||
this.isRemoved = isRemoved;
|
||||
}
|
||||
|
||||
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.addListener(provider::invalidate);
|
||||
return provider;
|
||||
@ -49,7 +58,7 @@ public final class SidedCapabilityProvider<T> implements ICapabilityProvider {
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
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;
|
||||
if (instances == null) instances = this.instances = new LazyOptional[6];
|
||||
|
Loading…
x
Reference in New Issue
Block a user