mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-14 20:20:30 +00:00
Attach capabilities to our BlockEntities externally
Previously we overrode getCapability on our BlockEntity implementations. While this is the Proper way to do things, it's obviously impossible to do in a multi-loader environment. We now subscribe to the AttachCapabilitiesEvent and add our caps that way. This does require[^1] some nasty invalidation of caps in a couple of places, which I'm not wild about. [^1]: I'm not actually sure it does: we invalidate peripherals and wired elements when neighbours change, so the explicit invalidation probably isn't useful.
This commit is contained in:
parent
53abe5e56e
commit
e8f9cdd221
@ -113,6 +113,7 @@ 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())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,7 +64,7 @@ public class TileEntityTurtleRenderer implements BlockEntityRenderer<TileTurtle>
|
||||
@Override
|
||||
public void render(@Nonnull TileTurtle turtle, float partialTicks, @Nonnull PoseStack transform, @Nonnull MultiBufferSource buffers, int lightmapCoord, int overlayLight) {
|
||||
// Render the label
|
||||
var label = turtle.createProxy().getLabel();
|
||||
var label = turtle.getLabel();
|
||||
var hit = renderer.cameraHitResult;
|
||||
if (label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())) {
|
||||
var mc = Minecraft.getInstance();
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.TileCable;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.TileWiredModemFull;
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.TileWirelessModem;
|
||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
|
||||
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
|
||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||
import dan200.computercraft.shared.util.CapabilityProvider;
|
||||
import dan200.computercraft.shared.util.SidedCapabilityProvider;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
import static net.minecraftforge.common.capabilities.ForgeCapabilities.ITEM_HANDLER;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = ComputerCraftAPI.MOD_ID)
|
||||
public class ForgeCommonHooks {
|
||||
private static final ResourceLocation PERIPHERAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "peripheral");
|
||||
private static final ResourceLocation WIRED_ELEMENT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "wired_node");
|
||||
private static final ResourceLocation INVENTORY = new ResourceLocation(ComputerCraftAPI.MOD_ID, "inventory");
|
||||
|
||||
/**
|
||||
* Attach capabilities to our block entities.
|
||||
*
|
||||
* @param event The {@link AttachCapabilitiesEvent} event.
|
||||
*/
|
||||
@SubscribeEvent
|
||||
public static void onCapability(AttachCapabilitiesEvent<BlockEntity> event) {
|
||||
var blockEntity = event.getObject();
|
||||
if (blockEntity instanceof TileComputer computer) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, computer::peripheral);
|
||||
} else if (blockEntity instanceof TileTurtle turtle) {
|
||||
CapabilityProvider.attach(event, INVENTORY, ITEM_HANDLER, () -> new InvWrapper(turtle));
|
||||
|
||||
var peripheral = CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, turtle::peripheral);
|
||||
turtle.onMoved(peripheral::invalidate);
|
||||
} else if (blockEntity instanceof TileDiskDrive diskDrive) {
|
||||
CapabilityProvider.attach(event, INVENTORY, ITEM_HANDLER, () -> new InvWrapper(diskDrive));
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, diskDrive::peripheral);
|
||||
} else if (blockEntity instanceof TileCable cable) {
|
||||
var peripheralHandler = SidedCapabilityProvider.attach(event, PERIPHERAL, Capabilities.CAPABILITY_PERIPHERAL, cable::getPeripheral);
|
||||
var elementHandler = SidedCapabilityProvider.attach(event, WIRED_ELEMENT, Capabilities.CAPABILITY_WIRED_ELEMENT, cable::getWiredElement);
|
||||
cable.onModemChanged(() -> {
|
||||
peripheralHandler.invalidate();
|
||||
elementHandler.invalidate();
|
||||
});
|
||||
} else if (blockEntity instanceof TileWiredModemFull modem) {
|
||||
SidedCapabilityProvider.attach(event, PERIPHERAL, Capabilities.CAPABILITY_PERIPHERAL, modem::getPeripheral);
|
||||
CapabilityProvider.attach(event, WIRED_ELEMENT, Capabilities.CAPABILITY_WIRED_ELEMENT, modem::getElement);
|
||||
} else if (blockEntity instanceof TileWirelessModem modem) {
|
||||
var peripheral = SidedCapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, modem::getPeripheral);
|
||||
modem.onModemChanged(peripheral::invalidate);
|
||||
} else if (blockEntity instanceof TileMonitor monitor) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, monitor::peripheral);
|
||||
} else if (blockEntity instanceof TileSpeaker speaker) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, speaker::peripheral);
|
||||
} else if (blockEntity instanceof TilePrinter printer) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, Capabilities.CAPABILITY_PERIPHERAL, printer::peripheral);
|
||||
// We don't need to invalidate here as the block's can't be rotated on the X axis!
|
||||
SidedCapabilityProvider.attach(
|
||||
event, INVENTORY, ITEM_HANDLER,
|
||||
s -> s == null ? new InvWrapper(printer) : new SidedInvWrapper(printer, s)
|
||||
);
|
||||
} else if (ComputerCraft.enableCommandBlock && blockEntity instanceof CommandBlockEntity commandBlock) {
|
||||
CapabilityProvider.attach(event, PERIPHERAL, CAPABILITY_PERIPHERAL, () -> new CommandBlockPeripheral(commandBlock));
|
||||
}
|
||||
}
|
||||
}
|
@ -22,11 +22,11 @@ import javax.annotation.Nullable;
|
||||
*/
|
||||
public class ComputerPeripheral implements IPeripheral {
|
||||
private final String type;
|
||||
private final ComputerProxy computer;
|
||||
private final TileComputerBase owner;
|
||||
|
||||
public ComputerPeripheral(String type, ComputerProxy computer) {
|
||||
public ComputerPeripheral(String type, TileComputerBase owner) {
|
||||
this.type = type;
|
||||
this.computer = computer;
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@ -40,7 +40,12 @@ public class ComputerPeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction
|
||||
public final void turnOn() {
|
||||
computer.turnOn();
|
||||
var computer = owner.getServerComputer();
|
||||
if (computer == null) {
|
||||
owner.startOn = true;
|
||||
} else {
|
||||
computer.turnOn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -48,7 +53,12 @@ public class ComputerPeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction
|
||||
public final void shutdown() {
|
||||
computer.shutdown();
|
||||
var computer = owner.getServerComputer();
|
||||
if (computer == null) {
|
||||
owner.startOn = false;
|
||||
} else {
|
||||
computer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -56,7 +66,12 @@ public class ComputerPeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction
|
||||
public final void reboot() {
|
||||
computer.reboot();
|
||||
var computer = owner.getServerComputer();
|
||||
if (computer == null) {
|
||||
owner.startOn = true;
|
||||
} else {
|
||||
computer.reboot();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,7 +82,8 @@ public class ComputerPeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction
|
||||
public final int getID() {
|
||||
return computer.getID();
|
||||
var computer = owner.getServerComputer();
|
||||
return computer == null ? owner.getComputerID() : computer.getID();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -77,7 +93,8 @@ public class ComputerPeripheral implements IPeripheral {
|
||||
*/
|
||||
@LuaFunction
|
||||
public final boolean isOn() {
|
||||
return computer.isOn();
|
||||
var computer = owner.getServerComputer();
|
||||
return computer != null && computer.isOn();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,17 +106,18 @@ public class ComputerPeripheral implements IPeripheral {
|
||||
@Nullable
|
||||
@LuaFunction
|
||||
public final String getLabel() {
|
||||
return computer.getLabel();
|
||||
var computer = owner.getServerComputer();
|
||||
return computer == null ? owner.getLabel() : computer.getLabel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(IPeripheral other) {
|
||||
return other instanceof ComputerPeripheral && computer == ((ComputerPeripheral) other).computer;
|
||||
return other instanceof ComputerPeripheral computerPeripheral && owner == computerPeripheral.owner;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Object getTarget() {
|
||||
return computer.getTile();
|
||||
return owner;
|
||||
}
|
||||
}
|
||||
|
@ -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.computer.blocks;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A proxy object for computer objects, delegating to {@link ServerComputer} or {@link TileComputer} where appropriate.
|
||||
*/
|
||||
public final class ComputerProxy {
|
||||
private final Supplier<TileComputerBase> get;
|
||||
|
||||
public ComputerProxy(Supplier<TileComputerBase> get) {
|
||||
this.get = get;
|
||||
}
|
||||
|
||||
TileComputerBase getTile() {
|
||||
return get.get();
|
||||
}
|
||||
|
||||
public void turnOn() {
|
||||
var tile = getTile();
|
||||
var computer = tile.getServerComputer();
|
||||
if (computer == null) {
|
||||
tile.startOn = true;
|
||||
} else {
|
||||
computer.turnOn();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
var tile = getTile();
|
||||
var computer = tile.getServerComputer();
|
||||
if (computer == null) {
|
||||
tile.startOn = false;
|
||||
} else {
|
||||
computer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void reboot() {
|
||||
var tile = getTile();
|
||||
var computer = tile.getServerComputer();
|
||||
if (computer == null) {
|
||||
tile.startOn = true;
|
||||
} else {
|
||||
computer.reboot();
|
||||
}
|
||||
}
|
||||
|
||||
public int getID() {
|
||||
var tile = getTile();
|
||||
var computer = tile.getServerComputer();
|
||||
return computer == null ? tile.getComputerID() : computer.getID();
|
||||
}
|
||||
|
||||
public boolean isOn() {
|
||||
var computer = getTile().getServerComputer();
|
||||
return computer != null && computer.isOn();
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
var tile = getTile();
|
||||
var computer = tile.getServerComputer();
|
||||
return computer == null ? tile.getLabel() : computer.getLabel();
|
||||
}
|
||||
}
|
@ -13,7 +13,6 @@ 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.computer.inventory.ComputerMenuWithoutInventory;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@ -22,17 +21,12 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
public class TileComputer extends TileComputerBase {
|
||||
private ComputerProxy proxy;
|
||||
private LazyOptional<IPeripheral> peripheral;
|
||||
private IPeripheral peripheral;
|
||||
|
||||
public TileComputer(BlockEntityType<? extends TileComputer> type, BlockPos pos, BlockState state, ComputerFamily family) {
|
||||
super(type, pos, state, family);
|
||||
@ -81,25 +75,8 @@ public class TileComputer extends TileComputerBase {
|
||||
return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == CAPABILITY_PERIPHERAL) {
|
||||
if (peripheral == null) {
|
||||
peripheral = LazyOptional.of(() -> {
|
||||
if (proxy == null) proxy = new ComputerProxy(() -> this);
|
||||
return new ComputerPeripheral("computer", proxy);
|
||||
});
|
||||
}
|
||||
return peripheral.cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
peripheral = CapabilityUtil.invalidate(peripheral);
|
||||
public IPeripheral peripheral() {
|
||||
if (peripheral != null) return peripheral;
|
||||
return peripheral = new ComputerPeripheral("computer", this);
|
||||
}
|
||||
}
|
||||
|
@ -5,26 +5,12 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.commandblock;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.computer.apis.CommandAPI;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.CommandBlockEntity;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
/**
|
||||
* This peripheral allows you to interact with command blocks.
|
||||
@ -36,12 +22,8 @@ import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
*
|
||||
* @cc.module command
|
||||
*/
|
||||
@Mod.EventBusSubscriber
|
||||
public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider {
|
||||
private static final ResourceLocation CAP_ID = new ResourceLocation(ComputerCraft.MOD_ID, "command_block");
|
||||
|
||||
public class CommandBlockPeripheral implements IPeripheral {
|
||||
private final CommandBlockEntity commandBlock;
|
||||
private LazyOptional<IPeripheral> self;
|
||||
|
||||
public CommandBlockPeripheral(CommandBlockEntity commandBlock) {
|
||||
this.commandBlock = commandBlock;
|
||||
@ -98,28 +80,4 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider
|
||||
public Object getTarget() {
|
||||
return commandBlock;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == CAPABILITY_PERIPHERAL) {
|
||||
if (self == null) self = LazyOptional.of(() -> this);
|
||||
return self.cast();
|
||||
}
|
||||
return LazyOptional.empty();
|
||||
}
|
||||
|
||||
private void invalidate() {
|
||||
self = CapabilityUtil.invalidate(self);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onCapability(AttachCapabilitiesEvent<BlockEntity> event) {
|
||||
var tile = event.getObject();
|
||||
if (ComputerCraft.enableCommandBlock && tile instanceof CommandBlockEntity commandBlock) {
|
||||
var peripheral = new CommandBlockPeripheral(commandBlock);
|
||||
event.addCapability(CAP_ID, peripheral);
|
||||
event.addListener(peripheral::invalidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.MediaProviders;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import dan200.computercraft.shared.util.DefaultInventory;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import dan200.computercraft.shared.util.RecordUtil;
|
||||
@ -30,19 +29,12 @@ 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.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
public final class TileDiskDrive extends TileGeneric implements DefaultInventory, Nameable, MenuProvider {
|
||||
private static final String NBT_NAME = "CustomName";
|
||||
private static final String NBT_ITEM = "Item";
|
||||
@ -58,8 +50,7 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
|
||||
|
||||
@Nonnull
|
||||
private ItemStack diskStack = ItemStack.EMPTY;
|
||||
private LazyOptional<IItemHandlerModifiable> itemHandlerCap;
|
||||
private LazyOptional<IPeripheral> peripheralCap;
|
||||
private IPeripheral peripheral;
|
||||
private IMount diskMount = null;
|
||||
|
||||
private boolean recordQueued = false;
|
||||
@ -77,13 +68,6 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
|
||||
if (recordPlaying) stopRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
itemHandlerCap = CapabilityUtil.invalidate(itemHandlerCap);
|
||||
peripheralCap = CapabilityUtil.invalidate(peripheralCap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsable(Player player) {
|
||||
return super.isUsable(player) && BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName());
|
||||
@ -434,22 +418,6 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
|
||||
RecordUtil.playRecord(null, null, getLevel(), getBlockPos());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable final Direction side) {
|
||||
if (cap == ForgeCapabilities.ITEM_HANDLER) {
|
||||
if (itemHandlerCap == null) itemHandlerCap = LazyOptional.of(() -> new InvWrapper(this));
|
||||
return itemHandlerCap.cast();
|
||||
}
|
||||
|
||||
if (cap == CAPABILITY_PERIPHERAL) {
|
||||
if (peripheralCap == null) peripheralCap = LazyOptional.of(() -> new DiskDrivePeripheral(this));
|
||||
return peripheralCap.cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomName() {
|
||||
return customName != null;
|
||||
@ -478,4 +446,9 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory
|
||||
public AbstractContainerMenu createMenu(int id, @Nonnull Inventory inventory, @Nonnull Player player) {
|
||||
return new ContainerDiskDrive(id, inventory, this);
|
||||
}
|
||||
|
||||
public IPeripheral peripheral() {
|
||||
if (peripheral != null) return peripheral;
|
||||
return peripheral = new DiskDrivePeripheral(this);
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.command.text.ChatHelpers;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -31,7 +30,6 @@ 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 net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
@ -39,9 +37,6 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT;
|
||||
|
||||
public class TileCable extends TileGeneric {
|
||||
private static final String NBT_PERIPHERAL_ENABLED = "PeirpheralAccess";
|
||||
|
||||
@ -72,13 +67,13 @@ public class TileCable extends TileGeneric {
|
||||
private boolean invalidPeripheral;
|
||||
private boolean peripheralAccessAllowed;
|
||||
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();
|
||||
private LazyOptional<IWiredElement> elementCap;
|
||||
private final IWiredNode node = cable.getNode();
|
||||
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
||||
private final WiredModemPeripheral modem = new WiredModemPeripheral(
|
||||
@ -103,7 +98,6 @@ public class TileCable extends TileGeneric {
|
||||
return TileCable.this;
|
||||
}
|
||||
};
|
||||
private LazyOptional<IPeripheral> modemCap;
|
||||
|
||||
private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged();
|
||||
|
||||
@ -139,13 +133,6 @@ public class TileCable extends TileGeneric {
|
||||
onRemove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
elementCap = CapabilityUtil.invalidate(elementCap);
|
||||
modemCap = CapabilityUtil.invalidate(modemCap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRemoved() {
|
||||
super.clearRemoved(); // TODO: Replace with onLoad
|
||||
@ -157,11 +144,9 @@ public class TileCable extends TileGeneric {
|
||||
public void setBlockState(@Nonnull BlockState state) {
|
||||
var direction = getMaybeDirection();
|
||||
super.setBlockState(state);
|
||||
if (getMaybeDirection() != direction) {
|
||||
// We invalidate both the modem and element if the modem's direction is different.
|
||||
modemCap = CapabilityUtil.invalidate(modemCap);
|
||||
elementCap = CapabilityUtil.invalidate(elementCap);
|
||||
}
|
||||
|
||||
// We invalidate both the modem and element if the modem's direction is different.
|
||||
if (getMaybeDirection() != direction && modemChanged != null) modemChanged.run();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@ -316,7 +301,7 @@ public class TileCable extends TileGeneric {
|
||||
|
||||
void modemChanged() {
|
||||
// Tell anyone who cares that the connection state has changed
|
||||
elementCap = CapabilityUtil.invalidate(elementCap);
|
||||
if (modemChanged != null) modemChanged.run();
|
||||
|
||||
if (getLevel().isClientSide) return;
|
||||
|
||||
@ -359,22 +344,20 @@ public class TileCable extends TileGeneric {
|
||||
node.updatePeripherals(peripherals);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable Direction side) {
|
||||
if (capability == CAPABILITY_WIRED_ELEMENT) {
|
||||
if (destroyed || !BlockCable.canConnectIn(getBlockState(), side)) return LazyOptional.empty();
|
||||
if (elementCap == null) elementCap = LazyOptional.of(() -> cable);
|
||||
return elementCap.cast();
|
||||
}
|
||||
@Nullable
|
||||
public IWiredElement getWiredElement(@Nullable Direction direction) {
|
||||
if (destroyed) return null;
|
||||
return direction == null || BlockCable.canConnectIn(getBlockState(), direction) ? cable : null;
|
||||
}
|
||||
|
||||
if (capability == CAPABILITY_PERIPHERAL) {
|
||||
if (side != null && getMaybeDirection() != side) return LazyOptional.empty();
|
||||
if (modemCap == null) modemCap = LazyOptional.of(() -> modem);
|
||||
return modemCap.cast();
|
||||
}
|
||||
@Nullable
|
||||
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
||||
if (destroyed) return null;
|
||||
return direction == null || getMaybeDirection() == direction ? modem : null;
|
||||
}
|
||||
|
||||
return super.getCapability(capability, side);
|
||||
public void onModemChanged(Runnable callback) {
|
||||
modemChanged = callback;
|
||||
}
|
||||
|
||||
boolean hasCable() {
|
||||
|
@ -13,9 +13,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.command.text.ChatHelpers;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import dan200.computercraft.shared.util.SidedCaps;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -29,7 +27,6 @@ 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 net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
@ -37,8 +34,6 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_WIRED_ELEMENT;
|
||||
import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.MODEM_ON;
|
||||
import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.PERIPHERAL_ON;
|
||||
|
||||
@ -82,7 +77,6 @@ public class TileWiredModemFull extends TileGeneric {
|
||||
}
|
||||
|
||||
private final WiredModemPeripheral[] modems = new WiredModemPeripheral[6];
|
||||
private final SidedCaps<IPeripheral> modemCaps = SidedCaps.ofNonNull(this::getPeripheral);
|
||||
|
||||
private boolean peripheralAccessAllowed = false;
|
||||
private final WiredModemLocalPeripheral[] peripherals = new WiredModemLocalPeripheral[6];
|
||||
@ -93,7 +87,6 @@ public class TileWiredModemFull extends TileGeneric {
|
||||
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
||||
private final ModemState modemState = new ModemState(() -> TickScheduler.schedule(tickToken));
|
||||
private final WiredModemElement element = new FullElement(this);
|
||||
private LazyOptional<IWiredElement> elementCap;
|
||||
private final IWiredNode node = element.getNode();
|
||||
|
||||
private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged();
|
||||
@ -130,13 +123,6 @@ public class TileWiredModemFull extends TileGeneric {
|
||||
doRemove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
elementCap = CapabilityUtil.invalidate(elementCap);
|
||||
modemCaps.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
@ -327,24 +313,14 @@ public class TileWiredModemFull extends TileGeneric {
|
||||
node.updatePeripherals(peripherals);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable Direction side) {
|
||||
if (capability == CAPABILITY_WIRED_ELEMENT) {
|
||||
if (elementCap == null) elementCap = LazyOptional.of(() -> element);
|
||||
return elementCap.cast();
|
||||
}
|
||||
|
||||
if (capability == CAPABILITY_PERIPHERAL) return modemCaps.get(side).cast();
|
||||
|
||||
return super.getCapability(capability, side);
|
||||
}
|
||||
|
||||
public IWiredElement getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
private WiredModemPeripheral getPeripheral(@Nonnull Direction side) {
|
||||
@Nullable
|
||||
public WiredModemPeripheral getPeripheral(@Nullable Direction side) {
|
||||
if (side == null) return null;
|
||||
|
||||
var peripheral = modems[side.ordinal()];
|
||||
if (peripheral != null) return peripheral;
|
||||
|
||||
|
@ -9,7 +9,6 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -17,14 +16,10 @@ import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
public class TileWirelessModem extends TileGeneric {
|
||||
private static class Peripheral extends WirelessModemPeripheral {
|
||||
private final TileWirelessModem entity;
|
||||
@ -62,7 +57,7 @@ public class TileWirelessModem extends TileGeneric {
|
||||
|
||||
private final ModemPeripheral modem;
|
||||
private boolean destroyed = false;
|
||||
private LazyOptional<IPeripheral> modemCap;
|
||||
private @Nullable Runnable modemChanged;
|
||||
private final TickScheduler.Token tickToken = new TickScheduler.Token(this);
|
||||
|
||||
public TileWirelessModem(BlockEntityType<? extends TileWirelessModem> type, BlockPos pos, BlockState state, boolean advanced) {
|
||||
@ -90,7 +85,7 @@ public class TileWirelessModem extends TileGeneric {
|
||||
public void setBlockState(@Nonnull BlockState state) {
|
||||
var direction = getDirection();
|
||||
super.setBlockState(state);
|
||||
if (getDirection() != direction) modemCap = CapabilityUtil.invalidate(modemCap);
|
||||
if (getDirection() != direction && modemChanged != null) modemChanged.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -111,15 +106,13 @@ public class TileWirelessModem extends TileGeneric {
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == CAPABILITY_PERIPHERAL) {
|
||||
if (side != null && getDirection() != side) return LazyOptional.empty();
|
||||
if (modemCap == null) modemCap = LazyOptional.of(() -> modem);
|
||||
return modemCap.cast();
|
||||
}
|
||||
@Nullable
|
||||
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
||||
if (destroyed) return null;
|
||||
return direction == null || getDirection() == direction ? modem : null;
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
public void onModemChanged(Runnable callback) {
|
||||
modemChanged = callback;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import dan200.computercraft.shared.util.TickScheduler;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -25,8 +24,6 @@ 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 net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@ -34,8 +31,6 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
public class TileMonitor extends TileGeneric {
|
||||
public static final double RENDER_BORDER = 2.0 / 16.0;
|
||||
public static final double RENDER_MARGIN = 0.5 / 16.0;
|
||||
@ -51,7 +46,6 @@ public class TileMonitor extends TileGeneric {
|
||||
private ServerMonitor serverMonitor;
|
||||
private ClientMonitor clientMonitor;
|
||||
private MonitorPeripheral peripheral;
|
||||
private LazyOptional<IPeripheral> peripheralCap;
|
||||
private final Set<IComputerAccess> computers = new HashSet<>();
|
||||
|
||||
private boolean needsUpdate = false;
|
||||
@ -160,24 +154,6 @@ public class TileMonitor extends TileGeneric {
|
||||
if (serverMonitor.pollTerminalChanged()) MonitorWatcher.enqueue(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
peripheralCap = CapabilityUtil.invalidate(peripheralCap);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == CAPABILITY_PERIPHERAL) {
|
||||
createServerMonitor(); // Ensure the monitor is created before doing anything else.
|
||||
if (peripheral == null) peripheral = new MonitorPeripheral(this);
|
||||
if (peripheralCap == null) peripheralCap = LazyOptional.of(() -> peripheral);
|
||||
return peripheralCap.cast();
|
||||
}
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@VisibleForTesting
|
||||
public ServerMonitor getCachedServerMonitor() {
|
||||
@ -542,6 +518,11 @@ public class TileMonitor extends TileGeneric {
|
||||
}
|
||||
}
|
||||
|
||||
public IPeripheral peripheral() {
|
||||
if (peripheral != null) return peripheral;
|
||||
return peripheral = new MonitorPeripheral(this);
|
||||
}
|
||||
|
||||
void addComputer(IComputerAccess computer) {
|
||||
computers.add(computer);
|
||||
}
|
||||
|
@ -10,7 +10,9 @@ import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||
import dan200.computercraft.shared.media.items.ItemPrintout;
|
||||
import dan200.computercraft.shared.util.*;
|
||||
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;
|
||||
@ -27,18 +29,10 @@ 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 net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, Nameable, MenuProvider {
|
||||
private static final String NBT_NAME = "CustomName";
|
||||
private static final String NBT_PRINTING = "Printing";
|
||||
@ -54,9 +48,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
|
||||
private LockCode lockCode = LockCode.NO_LOCK;
|
||||
|
||||
private final NonNullList<ItemStack> inventory = NonNullList.withSize(SLOTS, ItemStack.EMPTY);
|
||||
private final SidedCaps<IItemHandler> itemHandlerCaps =
|
||||
SidedCaps.ofNullable(facing -> facing == null ? new InvWrapper(this) : new SidedInvWrapper(this, facing));
|
||||
private LazyOptional<IPeripheral> peripheralCap;
|
||||
private @Nullable IPeripheral peripheral;
|
||||
|
||||
private final NetworkedTerminal page = new NetworkedTerminal(ItemPrintout.LINE_MAX_LENGTH, ItemPrintout.LINES_PER_PAGE, true);
|
||||
private String pageTitle = "";
|
||||
@ -71,13 +63,6 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
|
||||
ejectContents();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
itemHandlerCaps.invalidate();
|
||||
peripheralCap = CapabilityUtil.invalidate(peripheralCap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsable(Player player) {
|
||||
return super.isUsable(player) && BaseContainerBlockEntity.canUnlock(player, lockCode, getDisplayName());
|
||||
@ -387,16 +372,9 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
|
||||
getLevel().setBlockAndUpdate(getBlockPos(), state.setValue(BlockPrinter.TOP, top).setValue(BlockPrinter.BOTTOM, bottom));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> capability, @Nullable Direction facing) {
|
||||
if (capability == ForgeCapabilities.ITEM_HANDLER) return itemHandlerCaps.get(facing).cast();
|
||||
if (capability == CAPABILITY_PERIPHERAL) {
|
||||
if (peripheralCap == null) peripheralCap = LazyOptional.of(() -> new PrinterPeripheral(this));
|
||||
return peripheralCap.cast();
|
||||
}
|
||||
|
||||
return super.getCapability(capability, facing);
|
||||
public IPeripheral peripheral() {
|
||||
if (peripheral == null) peripheral = new PrinterPeripheral(this);
|
||||
return peripheral;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -9,23 +9,16 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
public class TileSpeaker extends TileGeneric {
|
||||
private final SpeakerPeripheral peripheral;
|
||||
private LazyOptional<IPeripheral> peripheralCap;
|
||||
|
||||
public TileSpeaker(BlockEntityType<TileSpeaker> type, BlockPos pos, BlockState state) {
|
||||
super(type, pos, state);
|
||||
@ -44,21 +37,8 @@ public class TileSpeaker extends TileGeneric {
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == CAPABILITY_PERIPHERAL) {
|
||||
if (peripheralCap == null) peripheralCap = LazyOptional.of(() -> peripheral);
|
||||
return peripheralCap.cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
peripheralCap = CapabilityUtil.invalidate(peripheralCap);
|
||||
public IPeripheral peripheral() {
|
||||
return peripheral;
|
||||
}
|
||||
|
||||
private static final class Peripheral extends SpeakerPeripheral {
|
||||
|
@ -14,7 +14,6 @@ import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.computer.blocks.ComputerPeripheral;
|
||||
import dan200.computercraft.shared.computer.blocks.ComputerProxy;
|
||||
import dan200.computercraft.shared.computer.blocks.TileComputerBase;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
@ -43,18 +42,11 @@ 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 net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.IItemHandlerModifiable;
|
||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
|
||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||
|
||||
public class TileTurtle extends TileComputerBase implements ITurtleTile, DefaultInventory {
|
||||
public static final int INVENTORY_SIZE = 16;
|
||||
public static final int INVENTORY_WIDTH = 4;
|
||||
@ -68,12 +60,11 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
|
||||
private final NonNullList<ItemStack> inventory = NonNullList.withSize(INVENTORY_SIZE, ItemStack.EMPTY);
|
||||
private final NonNullList<ItemStack> previousInventory = NonNullList.withSize(INVENTORY_SIZE, ItemStack.EMPTY);
|
||||
private final IItemHandlerModifiable itemHandler = new InvWrapper(this);
|
||||
private LazyOptional<IItemHandlerModifiable> itemHandlerCap;
|
||||
private boolean inventoryChanged = false;
|
||||
private TurtleBrain brain = new TurtleBrain(this);
|
||||
private MoveState moveState = MoveState.NOT_MOVED;
|
||||
private LazyOptional<IPeripheral> peripheral;
|
||||
private IPeripheral peripheral;
|
||||
private Runnable onMoved;
|
||||
|
||||
public TileTurtle(BlockEntityType<? extends TileGeneric> type, BlockPos pos, BlockState state, ComputerFamily family) {
|
||||
super(type, pos, state, family);
|
||||
@ -95,10 +86,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
return computer;
|
||||
}
|
||||
|
||||
public ComputerProxy createProxy() {
|
||||
return brain.getProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (!hasMoved()) {
|
||||
@ -130,13 +117,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCaps() {
|
||||
super.invalidateCaps();
|
||||
itemHandlerCap = CapabilityUtil.invalidate(itemHandlerCap);
|
||||
peripheral = CapabilityUtil.invalidate(peripheral);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public InteractionResult onActivate(Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
@ -469,30 +449,18 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
|
||||
// Mark the other turtle as having moved, and so its peripheral is dead.
|
||||
copy.moveState = MoveState.MOVED;
|
||||
copy.peripheral = CapabilityUtil.invalidate(copy.peripheral);
|
||||
if (onMoved != null) onMoved.run();
|
||||
}
|
||||
|
||||
public IItemHandlerModifiable getItemHandler() {
|
||||
return itemHandler;
|
||||
@Nullable
|
||||
public IPeripheral peripheral() {
|
||||
if (hasMoved()) return null;
|
||||
if (peripheral != null) return peripheral;
|
||||
return peripheral = new ComputerPeripheral("turtle", this);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @Nullable Direction side) {
|
||||
if (cap == ForgeCapabilities.ITEM_HANDLER) {
|
||||
if (itemHandlerCap == null) itemHandlerCap = LazyOptional.of(() -> new InvWrapper(this));
|
||||
return itemHandlerCap.cast();
|
||||
}
|
||||
|
||||
if (cap == CAPABILITY_PERIPHERAL) {
|
||||
if (hasMoved()) return LazyOptional.empty();
|
||||
if (peripheral == null) {
|
||||
peripheral = LazyOptional.of(() -> new ComputerPeripheral("turtle", createProxy()));
|
||||
}
|
||||
return peripheral.cast();
|
||||
}
|
||||
|
||||
return super.getCapability(cap, side);
|
||||
public void onMoved(Runnable onMoved) {
|
||||
this.onMoved = onMoved;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -15,7 +15,6 @@ import dan200.computercraft.api.turtle.*;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
import dan200.computercraft.shared.TurtleUpgrades;
|
||||
import dan200.computercraft.shared.computer.blocks.ComputerProxy;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.turtle.blocks.TileTurtle;
|
||||
@ -65,7 +64,6 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
public static final Predicate<Entity> PUSHABLE_ENTITY = entity -> !entity.isSpectator() && entity.getPistonPushReaction() != PushReaction.IGNORE;
|
||||
|
||||
private TileTurtle owner;
|
||||
private ComputerProxy proxy;
|
||||
private GameProfile owningPlayer;
|
||||
|
||||
private final Container inventory = (InventoryDelegate) () -> owner;
|
||||
@ -101,11 +99,6 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public ComputerProxy getProxy() {
|
||||
if (proxy == null) proxy = new ComputerProxy(() -> owner);
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public ComputerFamily getFamily() {
|
||||
return owner.getFamily();
|
||||
}
|
||||
|
@ -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 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;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A basic {@link ICapabilityProvider} which provides a single capability, returning the same instance for every
|
||||
* direction.
|
||||
* <p>
|
||||
* This is designed for use with {@link AttachCapabilitiesEvent}, to attach individual capabilities to a specific
|
||||
* block entity.
|
||||
*
|
||||
* @param <T> The capability to provide.
|
||||
*/
|
||||
public final class CapabilityProvider<T> implements ICapabilityProvider {
|
||||
private final Capability<T> cap;
|
||||
private final Supplier<T> supplier;
|
||||
private final BooleanSupplier isRemoved;
|
||||
private @Nullable LazyOptional<T> instance;
|
||||
|
||||
private CapabilityProvider(Capability<T> cap, Supplier<T> supplier, BooleanSupplier isRemoved) {
|
||||
this.cap = Objects.requireNonNull(cap, "Capability cannot be null");
|
||||
this.supplier = supplier;
|
||||
this.isRemoved = isRemoved;
|
||||
}
|
||||
|
||||
public static <T> CapabilityProvider<T> attach(AttachCapabilitiesEvent<?> event, ResourceLocation id, Capability<T> cap, Supplier<T> instance) {
|
||||
BooleanSupplier isRemoved
|
||||
= event.getObject() instanceof BlockEntity be ? be::isRemoved
|
||||
: event.getObject() instanceof Entity entity ? entity::isRemoved
|
||||
: () -> true;
|
||||
var provider = new CapabilityProvider<>(cap, instance, isRemoved);
|
||||
event.addCapability(id, provider);
|
||||
event.addListener(provider::invalidate);
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
instance = CapabilityUtil.invalidate(instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U> LazyOptional<U> getCapability(Capability<U> cap, @Nullable Direction side) {
|
||||
if (cap != this.cap || isRemoved.getAsBoolean()) return LazyOptional.empty();
|
||||
|
||||
var instance = this.instance;
|
||||
if (instance == null) {
|
||||
var created = supplier.get();
|
||||
instance = this.instance = created == null ? LazyOptional.empty() : LazyOptional.of(() -> created);
|
||||
}
|
||||
return instance.cast();
|
||||
}
|
||||
}
|
@ -49,11 +49,6 @@ public final class CapabilityUtil {
|
||||
return p.orElseThrow(NullPointerException::new);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T> T unwrapUnsafe(LazyOptional<T> p) {
|
||||
return !p.isPresent() ? null : p.orElseThrow(NullPointerException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a capability, preferring the internal/null side but falling back to a given side if a mod doesn't support
|
||||
* the internal one.
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.core.Direction;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.capabilities.Capability;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.event.AttachCapabilitiesEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link ICapabilityProvider} which provides a different single capability, with different instances for each
|
||||
* direction.
|
||||
* <p>
|
||||
* This is designed for use with {@link AttachCapabilitiesEvent}, to attach individual capabilities to a specific
|
||||
* block entity.
|
||||
*
|
||||
* @param <T> The capability to provide.
|
||||
* @see CapabilityProvider
|
||||
*/
|
||||
public final class SidedCapabilityProvider<T> implements ICapabilityProvider {
|
||||
private final Capability<T> cap;
|
||||
private final Provider<T> supplier;
|
||||
private @Nullable LazyOptional<T>[] instances;
|
||||
|
||||
private SidedCapabilityProvider(Capability<T> cap, Provider<T> supplier) {
|
||||
this.cap = Objects.requireNonNull(cap, "Capability cannot be null");
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
public static <T> SidedCapabilityProvider<T> attach(AttachCapabilitiesEvent<?> event, ResourceLocation id, Capability<T> cap, Provider<T> supplier) {
|
||||
var provider = new SidedCapabilityProvider<>(cap, supplier);
|
||||
event.addCapability(id, provider);
|
||||
event.addListener(provider::invalidate);
|
||||
return provider;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
CapabilityUtil.invalidate(instances);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public <U> LazyOptional<U> getCapability(Capability<U> cap, @Nullable Direction side) {
|
||||
if (cap != this.cap) return LazyOptional.empty();
|
||||
|
||||
var instances = this.instances;
|
||||
if (instances == null) instances = this.instances = new LazyOptional[6];
|
||||
|
||||
var index = side == null ? 6 : side.ordinal();
|
||||
|
||||
var instance = instances[index];
|
||||
if (instance == null) {
|
||||
var created = supplier.get(side);
|
||||
instance = instances[index] = created == null ? LazyOptional.empty() : LazyOptional.of(() -> created);
|
||||
}
|
||||
|
||||
return instance.cast();
|
||||
}
|
||||
|
||||
public interface Provider<T> {
|
||||
@Nullable
|
||||
T get(@Nullable Direction direction);
|
||||
}
|
||||
}
|
@ -1,60 +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.core.Direction;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Provides a constant (but invalidate-able) capability for each side.
|
||||
*
|
||||
* @param <T> The type of the produced capability.
|
||||
*/
|
||||
public final class SidedCaps<T> {
|
||||
private final Function<Direction, T> factory;
|
||||
private final boolean allowNull;
|
||||
private T[] values;
|
||||
private LazyOptional<T>[] caps;
|
||||
|
||||
private SidedCaps(Function<Direction, T> factory, boolean allowNull) {
|
||||
this.factory = factory;
|
||||
this.allowNull = allowNull;
|
||||
}
|
||||
|
||||
public static <T> SidedCaps<T> ofNonNull(Function<Direction, T> factory) {
|
||||
return new SidedCaps<>(factory, false);
|
||||
}
|
||||
|
||||
public static <T> SidedCaps<T> ofNullable(Function<Direction, T> factory) {
|
||||
return new SidedCaps<>(factory, true);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public LazyOptional<T> get(@Nullable Direction direction) {
|
||||
if (direction == null && !allowNull) return LazyOptional.empty();
|
||||
var index = direction == null ? 6 : direction.ordinal();
|
||||
|
||||
var caps = this.caps;
|
||||
if (caps == null) {
|
||||
caps = this.caps = new LazyOptional[allowNull ? 7 : 6];
|
||||
values = (T[]) new Object[caps.length];
|
||||
}
|
||||
|
||||
var cap = caps[index];
|
||||
return cap == null ? caps[index] = LazyOptional.of(() -> {
|
||||
var values = this.values;
|
||||
var value = values[index];
|
||||
return value == null ? values[index] = factory.apply(direction) : value;
|
||||
}) : cap;
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
if (caps != null) CapabilityUtil.invalidate(caps);
|
||||
}
|
||||
}
|
@ -29,8 +29,7 @@ import net.minecraft.world.item.Items
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.FenceBlock
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.array
|
||||
import org.hamcrest.Matchers.instanceOf
|
||||
import org.hamcrest.Matchers.*
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotEquals
|
||||
import java.util.*
|
||||
@ -355,7 +354,8 @@ class Turtle_Test {
|
||||
}
|
||||
thenExecute {
|
||||
helper.assertEntityNotPresent(EntityType.SHEEP)
|
||||
val count = helper.getBlockEntity(turtlePos, ModRegistry.BlockEntities.TURTLE_NORMAL.get()).countItem(Items.WHITE_WOOL)
|
||||
val count = helper.getBlockEntity(turtlePos, ModRegistry.BlockEntities.TURTLE_NORMAL.get())
|
||||
.countItem(Items.WHITE_WOOL)
|
||||
if (count == 0) helper.fail("Expected turtle to have white wool", turtlePos)
|
||||
}
|
||||
}
|
||||
@ -371,7 +371,56 @@ class Turtle_Test {
|
||||
thenWaitUntil { helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 2)) }
|
||||
}
|
||||
|
||||
// TODO: Ghost peripherals?
|
||||
/**
|
||||
* Ensure a turtle never sees itself as a peripheral.
|
||||
*
|
||||
* @see <https://github.com/dan200/ComputerCraft/issues/131>
|
||||
*/
|
||||
@GameTest
|
||||
fun No_ghost_peripheral(helper: GameTestHelper) = helper.sequence {
|
||||
val events = mutableListOf<String>()
|
||||
thenOnComputer {
|
||||
for (i in 0 until 3) {
|
||||
if ((i % 2) == 0) turtle.up() else turtle.down()
|
||||
|
||||
do {
|
||||
val event = pullEvent()[0] as String
|
||||
events.add(event)
|
||||
} while (event != "turtle_response")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a turtle attaches and detaches peripherals as it moves.
|
||||
*/
|
||||
@GameTest
|
||||
fun Peripheral_change(helper: GameTestHelper) = helper.sequence {
|
||||
val events = mutableListOf<Pair<String, String>>()
|
||||
thenStartComputer("listen") {
|
||||
while (true) {
|
||||
val event = pullEvent()
|
||||
if (event[0] == "peripheral" || event[0] == "peripheral_detach") {
|
||||
events.add((event[0] as String) to (event[1] as String))
|
||||
}
|
||||
}
|
||||
}
|
||||
thenOnComputer("turtle") {
|
||||
turtle.forward().await().assertArrayEquals(true, message = "Moved turtle forward")
|
||||
turtle.back().await().assertArrayEquals(true, message = "Moved turtle forward")
|
||||
}
|
||||
thenIdle(1)
|
||||
thenExecute {
|
||||
assertEquals(
|
||||
listOf(
|
||||
"peripheral_detach" to "right",
|
||||
"peripheral" to "right",
|
||||
),
|
||||
events,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Turtle sucking from items
|
||||
}
|
||||
|
||||
|
@ -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:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.no_ghost_peripheral", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}},
|
||||
{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:turtle_normal{facing:south,waterlogged:false}"
|
||||
]
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
{
|
||||
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:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.peripheral_change.turtle", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}},
|
||||
{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:computer_advanced{facing:north,state:blinking}", nbt: {ComputerId: 1, Label: "turtle_test.peripheral_change.listen", On: 1b, id: "computercraft:computer_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:turtle_normal{facing:south,waterlogged:false}",
|
||||
"computercraft:computer_advanced{facing:north,state:blinking}"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user