diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java new file mode 100644 index 000000000..01fd02cea --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralTile.java @@ -0,0 +1,31 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2019. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.peripheral; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; + +/** + * A {@link net.minecraft.block.entity.BlockEntity} which may act as a peripheral. + * + * If you need more complex capabilities (such as handling TEs not belonging to your mod), you should use {@link IPeripheralProvider}. + */ +public interface IPeripheralTile { + /** + * Get the peripheral on the given {@code side}. + * + * @param side The side to get the peripheral from. + * @return A peripheral, or {@code null} if there is not a peripheral here. + * @see IPeripheralProvider#getPeripheral(World, BlockPos, Direction) + */ + @Nullable + IPeripheral getPeripheral(@Nonnull Direction side); +} diff --git a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java index a9d54c101..5aca6a644 100644 --- a/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/TileEntityMonitorRenderer.java @@ -6,6 +6,7 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.platform.GlStateManager; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.FrameInfo; import dan200.computercraft.client.gui.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; @@ -60,6 +61,7 @@ public class TileEntityMonitorRenderer extends BlockEntityRenderer public void render( @Nonnull TileMonitor monitor, float partialTicks, @Nonnull MatrixStack transform, @Nonnull VertexConsumerProvider renderer, int lightmapCoord, int overlayLight ) { // Render from the origin monitor + // TODO Figure out why this is null. ClientMonitor originTerminal = monitor.getClientMonitor(); if( originTerminal == null ) return; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java index 205161aeb..aee67ebd5 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java @@ -13,7 +13,7 @@ import java.util.function.Supplier; /** * A proxy object for computer objects, delegating to {@link IComputer} or {@link TileComputer} where appropriate. */ -public final class ComputerProxy +public class ComputerProxy { private final Supplier get; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 2c156d113..c7818b3ae 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -81,4 +81,18 @@ public class TileComputer extends TileComputerBase { return new ContainerComputer( id, this ); } + + @Override + public ComputerProxy createProxy() { + if (this.proxy == null) { + this.proxy = new ComputerProxy(() -> this) { + @Override + protected TileComputerBase getTile() { + return TileComputer.this; + } + }; + } + return this.proxy; + } + } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 9110f0388..bc17712e2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -7,6 +7,8 @@ package dan200.computercraft.shared.computer.blocks; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.BundledRedstone; import dan200.computercraft.shared.Peripherals; @@ -46,7 +48,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Objects; -public abstract class TileComputerBase extends TileGeneric implements IComputerTile, Tickable, Nameable, NamedScreenHandlerFactory, ExtendedScreenHandlerFactory +public abstract class TileComputerBase extends TileGeneric implements IComputerTile, Tickable, IPeripheralTile, Nameable, NamedScreenHandlerFactory, ExtendedScreenHandlerFactory { private static final String NBT_ID = "ComputerId"; private static final String NBT_LABEL = "Label"; @@ -406,6 +408,14 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT copy.m_instanceID = -1; } + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { + return new ComputerPeripheral("computer", this.createProxy()); + } + + public abstract ComputerProxy createProxy(); + @Nonnull @Override public Text getName() diff --git a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java index 8f0593491..86b558586 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/diskdrive/TileDiskDrive.java @@ -10,6 +10,8 @@ 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.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.MediaProviders; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.util.DefaultInventory; @@ -32,6 +34,7 @@ import net.minecraft.util.*; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -39,7 +42,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; -public final class TileDiskDrive extends TileGeneric implements DefaultInventory, Tickable, Nameable, NamedScreenHandlerFactory +public final class TileDiskDrive extends TileGeneric implements DefaultInventory, Tickable, IPeripheralTile, Nameable, NamedScreenHandlerFactory { private static final String NBT_NAME = "CustomName"; private static final String NBT_ITEM = "Item"; @@ -288,6 +291,12 @@ public final class TileDiskDrive extends TileGeneric implements DefaultInventory setStack( 0, ItemStack.EMPTY ); } + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { + return new DiskDrivePeripheral(this); + } + @Nonnull ItemStack getDiskStack() { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java index 1ef767c84..dcdaeca9f 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileCable.java @@ -10,6 +10,8 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.ComputerCraftRegistry; import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; @@ -36,7 +38,7 @@ import javax.annotation.Nullable; import java.util.Collections; import java.util.Map; -public class TileCable extends TileGeneric +public class TileCable extends TileGeneric implements IPeripheralTile { private static final String NBT_PERIPHERAL_ENABLED = "PeirpheralAccess"; @@ -313,24 +315,23 @@ public class TileCable extends TileGeneric BlockState state = getCachedState(); World world = getWorld(); BlockPos current = getPos(); - for( Direction facing : DirectionUtil.FACINGS ) - { - BlockPos offset = current.offset( facing ); - if( !world.isChunkLoaded( offset ) ) continue; + for( Direction facing : DirectionUtil.FACINGS ) { + BlockPos offset = current.offset(facing); + if (!world.isChunkLoaded(offset)) continue; - IWiredElement element = ComputerCraftAPI.getWiredElementAt( world, offset, facing.getOpposite() ); - if( element != null ) continue; + IWiredElement element = ComputerCraftAPI.getWiredElementAt(world, offset, facing.getOpposite()); + if (element != null) continue; + // TODO Figure out why this crashes. IWiredNode node = element.getNode(); - if( BlockCable.canConnectIn( state, facing ) ) - { - // If we can connect to it then do so - m_node.connectTo( node ); - } - else if( m_node.getNetwork() == node.getNetwork() ) - { - // Otherwise if we're on the same network then attempt to void it. - m_node.disconnectFrom( node ); + if (node != null && m_node != null) { + if (BlockCable.canConnectIn(state, facing)) { + // If we can connect to it then do so + m_node.connectTo(node); + } else if (m_node.getNetwork() == node.getNetwork()) { + // Otherwise if we're on the same network then attempt to void it. + m_node.disconnectFrom(node); + } } } } @@ -356,6 +357,12 @@ public class TileCable extends TileGeneric return BlockCable.canConnectIn(this.getCachedState(), facing) ? this.m_cable : null; } + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { + return !this.m_destroyed && this.hasModem() && side == this.getDirection() ? this.m_modem : null; + } + private void togglePeripheralAccess() { if( !m_peripheralAccessAllowed ) diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java index aed9da94b..81bf9ad0c 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wired/TileWiredModemFull.java @@ -11,6 +11,8 @@ import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.network.wired.IWiredElement; import dan200.computercraft.api.network.wired.IWiredNode; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.command.CommandCopy; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemState; @@ -37,7 +39,7 @@ import java.util.*; import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.MODEM_ON; import static dan200.computercraft.shared.peripheral.modem.wired.BlockWiredModemFull.PERIPHERAL_ON; -public class TileWiredModemFull extends TileGeneric +public class TileWiredModemFull extends TileGeneric implements IPeripheralTile { private static final String NBT_PERIPHERAL_ENABLED = "PeripheralAccess"; @@ -341,33 +343,30 @@ public class TileWiredModemFull extends TileGeneric return m_element; } - private WiredModemPeripheral getPeripheral( @Nonnull Direction side ) - { + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { WiredModemPeripheral peripheral = modems[side.ordinal()]; - if( peripheral != null ) return peripheral; + if (peripheral != null) return peripheral; WiredModemLocalPeripheral localPeripheral = m_peripherals[side.ordinal()]; - return modems[side.ordinal()] = new WiredModemPeripheral( m_modemState, m_element ) - { + return modems[side.ordinal()] = new WiredModemPeripheral(m_modemState, m_element) { @Nonnull @Override - protected WiredModemLocalPeripheral getLocalPeripheral() - { + protected WiredModemLocalPeripheral getLocalPeripheral() { return localPeripheral; } @Nonnull @Override - public Vec3d getPosition() - { - BlockPos pos = getPos().offset( side ); - return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ); + public Vec3d getPosition() { + BlockPos pos = getPos().offset(side); + return new Vec3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); } @Nonnull @Override - public Object getTarget() - { + public Object getTarget() { return TileWiredModemFull.this; } }; diff --git a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java index 4db8318de..7606a3e7d 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/wireless/TileWirelessModem.java @@ -6,6 +6,8 @@ package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemState; @@ -20,7 +22,7 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TileWirelessModem extends TileGeneric +public class TileWirelessModem extends TileGeneric implements IPeripheralTile { private static class Peripheral extends WirelessModemPeripheral { @@ -119,6 +121,13 @@ public class TileWirelessModem extends TileGeneric modemDirection = getCachedState().get( BlockWirelessModem.FACING ); } + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { + this.refreshDirection(); + return side == this.modemDirection ? this.modem : null; + } + private void updateBlockState() { boolean on = modem.getModemState().isOpen(); diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java index 4acd1212b..837800760 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/TileMonitor.java @@ -7,6 +7,9 @@ package dan200.computercraft.shared.peripheral.monitor; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.ServerTerminal; import dan200.computercraft.shared.common.TileGeneric; @@ -32,7 +35,7 @@ import javax.annotation.Nullable; import java.util.HashSet; import java.util.Set; -public class TileMonitor extends TileGeneric +public class TileMonitor extends TileGeneric implements IPeripheralTile { public static final double RENDER_BORDER = 2.0 / 16.0; public static final double RENDER_MARGIN = 0.5 / 16.0; @@ -134,6 +137,16 @@ public class TileMonitor extends TileGeneric m_height = nbt.getInt( NBT_HEIGHT ); } + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { + this.createServerMonitor(); // Ensure the monitor is created before doing anything else. + if (this.peripheral == null) { + this.peripheral = new MonitorPeripheral(this); + } + return this.peripheral; + } + @Override public void blockTick() { @@ -252,7 +265,7 @@ public class TileMonitor extends TileGeneric { // 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. - if(world.isClient() && oldXIndex == 0 && oldYIndex == 0 && m_clientMonitor != null) m_clientMonitor.destroy(); + if(oldXIndex == 0 && oldYIndex == 0 && m_clientMonitor != null) m_clientMonitor.destroy(); m_clientMonitor = null; } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java index b825b7e24..8f57c1c16 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/printer/TilePrinter.java @@ -6,6 +6,8 @@ package dan200.computercraft.shared.peripheral.printer; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.media.items.ItemPrintout; @@ -25,13 +27,15 @@ import net.minecraft.text.TranslatableText; import net.minecraft.util.*; import net.minecraft.util.collection.DefaultedList; import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, Nameable, NamedScreenHandlerFactory +public final class TilePrinter extends TileGeneric implements DefaultSidedInventory, IPeripheralTile, Nameable, NamedScreenHandlerFactory { private static final String NBT_NAME = "CustomName"; private static final String NBT_PRINTING = "Printing"; @@ -231,6 +235,12 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent } } + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { + return new PrinterPeripheral(this); + } + @Nullable Terminal getCurrentPage() { diff --git a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java index dd9dd1900..08f18b146 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/speaker/TileSpeaker.java @@ -6,6 +6,8 @@ package dan200.computercraft.shared.peripheral.speaker; import dan200.computercraft.api.peripheral.IPeripheral; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.shared.common.TileGeneric; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.util.Tickable; @@ -17,7 +19,7 @@ import net.minecraft.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public class TileSpeaker extends TileGeneric implements Tickable +public class TileSpeaker extends TileGeneric implements Tickable, IPeripheralTile { public static final int MIN_TICKS_BETWEEN_SOUNDS = 1; @@ -35,6 +37,12 @@ public class TileSpeaker extends TileGeneric implements Tickable peripheral.update(); } + @Nonnull + @Override + public IPeripheral getPeripheral(Direction side) { + return this.peripheral; + } + private static final class Peripheral extends SpeakerPeripheral { private final TileSpeaker speaker; diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 6f5f7d310..08788fb85 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -8,6 +8,7 @@ package dan200.computercraft.shared.proxy; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.media.IMedia; +import dan200.computercraft.api.peripheral.IPeripheralTile; import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.core.computer.MainThread; import dan200.computercraft.core.tracking.Tracking; @@ -20,12 +21,15 @@ import dan200.computercraft.shared.data.HasComputerIdLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import dan200.computercraft.shared.turtle.FurnaceRefuelHandler; import dan200.computercraft.shared.util.TickScheduler; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.CommandBlockBlockEntity; import net.minecraft.item.Item; import net.minecraft.item.MusicDiscItem; import net.minecraft.loot.condition.LootConditionType; @@ -60,6 +64,17 @@ public final class ComputerCraftProxyCommon private static void registerProviders() { + ComputerCraftAPI.registerPeripheralProvider((world, pos, side) -> { + BlockEntity tile = world.getBlockEntity(pos); + return tile instanceof IPeripheralTile ? ((IPeripheralTile) tile).getPeripheral(side) : null; + }); + + ComputerCraftAPI.registerPeripheralProvider((world, pos, side) -> { + BlockEntity tile = world.getBlockEntity(pos); + return ComputerCraft.enableCommandBlock && tile instanceof CommandBlockBlockEntity ? + new CommandBlockPeripheral((CommandBlockBlockEntity) tile) : null; + }); + // Register bundled power providers ComputerCraftAPI.registerBundledRedstoneProvider( new DefaultBundledRedstoneProvider() );