mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 21:52:59 +00:00 
			
		
		
		
	Access capabilities using PlatformHelper
We provide a new abstraction: ComponentAccess, which is a view of capabilities (or block lookups for Fabric) for adjacent blocks.
This commit is contained in:
		| @@ -111,7 +111,8 @@ 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()) | ||||
|                 // FIXME: We need this for running in-dev but not from Gradle: | ||||
|                 // source(project(":core").sourceSets.testFixtures.get()) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -11,11 +11,11 @@ import net.minecraft.client.gui.components.Button; | ||||
| import net.minecraft.client.gui.screens.Screen; | ||||
| import net.minecraft.network.chat.Component; | ||||
| import net.minecraft.resources.ResourceLocation; | ||||
| import net.minecraftforge.common.util.NonNullSupplier; | ||||
| 
 | ||||
| import javax.annotation.Nonnull; | ||||
| import java.util.List; | ||||
| import java.util.function.IntSupplier; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| /** | ||||
|  * Version of {@link net.minecraft.client.gui.components.ImageButton} which allows changing some properties | ||||
| @@ -29,7 +29,7 @@ public class DynamicImageButton extends Button { | ||||
|     private final int yDiffTex; | ||||
|     private final int textureWidth; | ||||
|     private final int textureHeight; | ||||
|     private final NonNullSupplier<List<Component>> tooltip; | ||||
|     private final Supplier<List<Component>> tooltip; | ||||
| 
 | ||||
|     public DynamicImageButton( | ||||
|         Screen screen, int x, int y, int width, int height, int xTexStart, int yTexStart, int yDiffTex, | ||||
| @@ -47,7 +47,7 @@ public class DynamicImageButton extends Button { | ||||
|     public DynamicImageButton( | ||||
|         Screen screen, int x, int y, int width, int height, IntSupplier xTexStart, int yTexStart, int yDiffTex, | ||||
|         ResourceLocation texture, int textureWidth, int textureHeight, | ||||
|         OnPress onPress, NonNullSupplier<List<Component>> tooltip | ||||
|         OnPress onPress, Supplier<List<Component>> tooltip | ||||
|     ) { | ||||
|         super(x, y, width, height, Component.empty(), onPress); | ||||
|         this.screen = screen; | ||||
|   | ||||
| @@ -5,25 +5,28 @@ | ||||
|  */ | ||||
| package dan200.computercraft.shared.computer.blocks; | ||||
| 
 | ||||
| import com.google.common.base.Strings; | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.core.computer.ComputerSide; | ||||
| import dan200.computercraft.shared.BundledRedstone; | ||||
| import dan200.computercraft.shared.Peripherals; | ||||
| import dan200.computercraft.shared.common.TileGeneric; | ||||
| 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.core.ServerContext; | ||||
| import dan200.computercraft.shared.network.container.ComputerContainerData; | ||||
| import dan200.computercraft.shared.platform.ComponentAccess; | ||||
| import dan200.computercraft.shared.platform.PlatformHelper; | ||||
| import dan200.computercraft.shared.util.DirectionUtil; | ||||
| import dan200.computercraft.shared.util.IDAssigner; | ||||
| import dan200.computercraft.shared.util.RedstoneUtil; | ||||
| import joptsimple.internal.Strings; | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| import net.minecraft.network.chat.Component; | ||||
| import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; | ||||
| import net.minecraft.server.level.ServerLevel; | ||||
| import net.minecraft.world.*; | ||||
| import net.minecraft.world.entity.player.Player; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| @@ -32,7 +35,6 @@ 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.util.NonNullConsumer; | ||||
| 
 | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| @@ -51,7 +53,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT | ||||
|     private boolean fresh = false; | ||||
| 
 | ||||
|     private int invalidSides = 0; | ||||
|     private final NonNullConsumer<Object>[] invalidate; | ||||
|     private final ComponentAccess<IPeripheral> peripherals = PlatformHelper.get().createPeripheralAccess(d -> invalidSides |= 1 << d.ordinal()); | ||||
| 
 | ||||
|     private LockCode lockCode = LockCode.NO_LOCK; | ||||
| 
 | ||||
| @@ -60,14 +62,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT | ||||
|     public TileComputerBase(BlockEntityType<? extends TileGeneric> type, BlockPos pos, BlockState state, ComputerFamily family) { | ||||
|         super(type, pos, state); | ||||
|         this.family = family; | ||||
| 
 | ||||
|         // We cache these so we can guarantee we only ever register one listener for adjacent capabilities. | ||||
|         @SuppressWarnings({ "unchecked", "rawtypes" }) | ||||
|         var invalidate = this.invalidate = new NonNullConsumer[6]; | ||||
|         for (var direction : Direction.values()) { | ||||
|             var mask = 1 << direction.ordinal(); | ||||
|             invalidate[direction.ordinal()] = o -> invalidSides |= mask; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     protected void unload() { | ||||
| @@ -231,8 +225,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT | ||||
|         var localDir = remapToLocalSide(dir); | ||||
|         if (isPeripheralBlockedOnSide(localDir)) return; | ||||
| 
 | ||||
|         var offsetSide = dir.getOpposite(); | ||||
|         var peripheral = Peripherals.getPeripheral(getLevel(), getBlockPos().relative(dir), offsetSide, invalidate[dir.ordinal()]); | ||||
|         var peripheral = peripherals.get((ServerLevel) getLevel(), getBlockPos(), dir); | ||||
|         computer.setPeripheral(localDir, peripheral); | ||||
|     } | ||||
| 
 | ||||
|   | ||||
| @@ -6,9 +6,9 @@ | ||||
| package dan200.computercraft.shared.peripheral.modem.wired; | ||||
| 
 | ||||
| import com.google.common.collect.ImmutableMap; | ||||
| import dan200.computercraft.api.ForgeComputerCraftAPI; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.common.BlockGeneric; | ||||
| import dan200.computercraft.shared.platform.PlatformHelper; | ||||
| import dan200.computercraft.shared.util.WaterloggableHelpers; | ||||
| import dan200.computercraft.shared.util.WorldUtil; | ||||
| import net.minecraft.core.BlockPos; | ||||
| @@ -76,10 +76,10 @@ public class BlockCable extends BlockGeneric implements SimpleWaterloggedBlock { | ||||
|         return state.getValue(BlockCable.CABLE) && state.getValue(BlockCable.MODEM).getFacing() != direction; | ||||
|     } | ||||
| 
 | ||||
|     public static boolean doesConnectVisually(BlockState state, BlockGetter world, BlockPos pos, Direction direction) { | ||||
|     public static boolean doesConnectVisually(BlockState state, Level level, BlockPos pos, Direction direction) { | ||||
|         if (!state.getValue(CABLE)) return false; | ||||
|         if (state.getValue(MODEM).getFacing() == direction) return true; | ||||
|         return ForgeComputerCraftAPI.getWiredElementAt(world, pos.relative(direction), direction.getOpposite()).isPresent(); | ||||
|         return PlatformHelper.get().hasWiredElementIn(level, pos, direction); | ||||
|     } | ||||
| 
 | ||||
|     @Nonnull | ||||
| @@ -171,7 +171,7 @@ public class BlockCable extends BlockGeneric implements SimpleWaterloggedBlock { | ||||
|             return getFluidState(state).createLegacyBlock(); | ||||
|         } | ||||
| 
 | ||||
|         return state.setValue(CONNECTIONS.get(side), doesConnectVisually(state, world, pos, side)); | ||||
|         return world instanceof Level level ? state.setValue(CONNECTIONS.get(side), doesConnectVisually(state, level, pos, side)) : state; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
| package dan200.computercraft.shared.peripheral.modem.wired; | ||||
| 
 | ||||
| import com.google.common.base.Objects; | ||||
| import dan200.computercraft.api.ForgeComputerCraftAPI; | ||||
| import dan200.computercraft.api.network.wired.IWiredElement; | ||||
| import dan200.computercraft.api.network.wired.IWiredNode; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| @@ -14,12 +13,15 @@ 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.platform.ComponentAccess; | ||||
| import dan200.computercraft.shared.platform.PlatformHelper; | ||||
| import dan200.computercraft.shared.util.DirectionUtil; | ||||
| import dan200.computercraft.shared.util.TickScheduler; | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| import net.minecraft.network.chat.Component; | ||||
| import net.minecraft.server.level.ServerLevel; | ||||
| import net.minecraft.world.InteractionHand; | ||||
| import net.minecraft.world.InteractionResult; | ||||
| import net.minecraft.world.entity.player.Player; | ||||
| @@ -30,8 +32,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.util.LazyOptional; | ||||
| import net.minecraftforge.common.util.NonNullConsumer; | ||||
| 
 | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| @@ -99,7 +99,7 @@ public class TileCable extends TileGeneric { | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged(); | ||||
|     private final ComponentAccess<IWiredElement> connectedElements = PlatformHelper.get().createWiredElementAccess(x -> connectionsChanged()); | ||||
| 
 | ||||
|     public TileCable(BlockEntityType<? extends TileCable> type, BlockPos pos, BlockState state) { | ||||
|         super(type, pos, state); | ||||
| @@ -284,11 +284,10 @@ public class TileCable extends TileGeneric { | ||||
|             var offset = current.relative(facing); | ||||
|             if (!world.isLoaded(offset)) continue; | ||||
| 
 | ||||
|             var element = ForgeComputerCraftAPI.getWiredElementAt(world, offset, facing.getOpposite()); | ||||
|             if (!element.isPresent()) continue; | ||||
|             var element = connectedElements.get((ServerLevel) world, current, facing); | ||||
|             if (element == null) continue; | ||||
| 
 | ||||
|             element.addListener(connectedNodeChanged); | ||||
|             var node = element.orElseThrow(NullPointerException::new).getNode(); | ||||
|             var node = element.getNode(); | ||||
|             if (BlockCable.canConnectIn(state, facing)) { | ||||
|                 // If we can connect to it then do so | ||||
|                 this.node.connectTo(node); | ||||
|   | ||||
| @@ -6,19 +6,21 @@ | ||||
| package dan200.computercraft.shared.peripheral.modem.wired; | ||||
| 
 | ||||
| import com.google.common.base.Objects; | ||||
| import dan200.computercraft.api.ForgeComputerCraftAPI; | ||||
| import dan200.computercraft.api.network.wired.IWiredElement; | ||||
| import dan200.computercraft.api.network.wired.IWiredNode; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.shared.command.text.ChatHelpers; | ||||
| import dan200.computercraft.shared.common.TileGeneric; | ||||
| import dan200.computercraft.shared.peripheral.modem.ModemState; | ||||
| import dan200.computercraft.shared.platform.ComponentAccess; | ||||
| import dan200.computercraft.shared.platform.PlatformHelper; | ||||
| import dan200.computercraft.shared.util.DirectionUtil; | ||||
| import dan200.computercraft.shared.util.TickScheduler; | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| import net.minecraft.network.chat.Component; | ||||
| import net.minecraft.server.level.ServerLevel; | ||||
| import net.minecraft.world.InteractionHand; | ||||
| import net.minecraft.world.InteractionResult; | ||||
| import net.minecraft.world.entity.player.Player; | ||||
| @@ -27,8 +29,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.util.LazyOptional; | ||||
| import net.minecraftforge.common.util.NonNullConsumer; | ||||
| 
 | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| @@ -89,7 +89,7 @@ public class TileWiredModemFull extends TileGeneric { | ||||
|     private final WiredModemElement element = new FullElement(this); | ||||
|     private final IWiredNode node = element.getNode(); | ||||
| 
 | ||||
|     private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged(); | ||||
|     private final ComponentAccess<IWiredElement> connectedElements = PlatformHelper.get().createWiredElementAccess(x -> connectionsChanged()); | ||||
| 
 | ||||
|     private int invalidSides = 0; | ||||
| 
 | ||||
| @@ -252,11 +252,10 @@ public class TileWiredModemFull extends TileGeneric { | ||||
|             var offset = current.relative(facing); | ||||
|             if (!world.isLoaded(offset)) continue; | ||||
| 
 | ||||
|             var element = ForgeComputerCraftAPI.getWiredElementAt(world, offset, facing.getOpposite()); | ||||
|             if (!element.isPresent()) continue; | ||||
|             var element = connectedElements.get((ServerLevel) getLevel(), getBlockPos(), facing); | ||||
|             if (element == null) return; | ||||
| 
 | ||||
|             element.addListener(connectedNodeChanged); | ||||
|             node.connectTo(element.orElseThrow(NullPointerException::new).getNode()); | ||||
|             node.connectTo(element.getNode()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|   | ||||
| @@ -7,14 +7,15 @@ package dan200.computercraft.shared.peripheral.modem.wired; | ||||
| 
 | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.shared.ModRegistry; | ||||
| import dan200.computercraft.shared.Peripherals; | ||||
| import dan200.computercraft.shared.computer.core.ServerContext; | ||||
| import dan200.computercraft.shared.platform.ComponentAccess; | ||||
| import dan200.computercraft.shared.platform.PlatformHelper; | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| import net.minecraft.nbt.Tag; | ||||
| import net.minecraft.server.level.ServerLevel; | ||||
| import net.minecraft.world.level.Level; | ||||
| import net.minecraftforge.common.util.NonNullConsumer; | ||||
| 
 | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| @@ -35,10 +36,10 @@ public final class WiredModemLocalPeripheral { | ||||
|     private String type; | ||||
| 
 | ||||
|     private IPeripheral peripheral; | ||||
|     private final NonNullConsumer<Object> invalidate; | ||||
|     private final ComponentAccess<IPeripheral> peripherals; | ||||
| 
 | ||||
|     public WiredModemLocalPeripheral(@Nonnull Runnable invalidate) { | ||||
|         this.invalidate = x -> invalidate.run(); | ||||
|         peripherals = PlatformHelper.get().createPeripheralAccess(x -> invalidate.run()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @@ -126,7 +127,7 @@ public final class WiredModemLocalPeripheral { | ||||
|         var block = world.getBlockState(offset).getBlock(); | ||||
|         if (block == ModRegistry.Blocks.WIRED_MODEM_FULL.get() || block == ModRegistry.Blocks.CABLE.get()) return null; | ||||
| 
 | ||||
|         var peripheral = Peripherals.getPeripheral(world, offset, direction.getOpposite(), invalidate); | ||||
|         var peripheral = peripherals.get((ServerLevel) world, pos, direction); | ||||
|         return peripheral instanceof WiredModemPeripheral ? null : peripheral; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,33 @@ | ||||
| /* | ||||
|  * 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.platform; | ||||
| 
 | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| import net.minecraft.server.level.ServerLevel; | ||||
| 
 | ||||
| import javax.annotation.Nullable; | ||||
| 
 | ||||
| /** | ||||
|  * A (possibly cached) provider of a component at a specific location. | ||||
|  * | ||||
|  * @param <T> The type of the component. | ||||
|  */ | ||||
| public interface ComponentAccess<T> { | ||||
|     /** | ||||
|      * Get a peripheral for the current block. | ||||
|      * <p> | ||||
|      * Both {@code level} and {@code pos} must be constant for the lifetime of the store. | ||||
|      * | ||||
|      * @param level     The current level. | ||||
|      * @param pos       The position of the block fetching the peripheral, for instance the computer or modem. | ||||
|      * @param direction The direction the peripheral is in. | ||||
|      * @return The peripheral, or {@literal null} if not found. | ||||
|      * @throws IllegalStateException If the level or position have changed. | ||||
|      */ | ||||
|     @Nullable | ||||
|     T get(ServerLevel level, BlockPos pos, Direction direction); | ||||
| } | ||||
| @@ -5,10 +5,13 @@ | ||||
|  */ | ||||
| package dan200.computercraft.shared.platform; | ||||
| 
 | ||||
| import dan200.computercraft.api.network.wired.IWiredElement; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.shared.network.NetworkMessage; | ||||
| import dan200.computercraft.shared.network.client.ClientNetworkContext; | ||||
| import dan200.computercraft.shared.network.container.ContainerData; | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.network.FriendlyByteBuf; | ||||
| import net.minecraft.resources.ResourceKey; | ||||
| @@ -20,6 +23,7 @@ import net.minecraft.world.MenuProvider; | ||||
| import net.minecraft.world.entity.player.Player; | ||||
| import net.minecraft.world.inventory.AbstractContainerMenu; | ||||
| import net.minecraft.world.inventory.MenuType; | ||||
| import net.minecraft.world.level.Level; | ||||
| import net.minecraft.world.level.block.Block; | ||||
| import net.minecraft.world.level.block.entity.BlockEntity; | ||||
| import net.minecraft.world.level.block.entity.BlockEntityType; | ||||
| @@ -30,6 +34,7 @@ import net.minecraft.world.phys.Vec3; | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.Collection; | ||||
| import java.util.function.BiFunction; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.function.Function; | ||||
| 
 | ||||
| /** | ||||
| @@ -146,4 +151,34 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper | ||||
|      * @param chunk   The chunk players must be tracking. | ||||
|      */ | ||||
|     void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, LevelChunk chunk); | ||||
| 
 | ||||
|     /** | ||||
|      * Create a {@link ComponentAccess} for surrounding peripherals. | ||||
|      * | ||||
|      * @param invalidate The function to call when a neighbouring peripheral potentially changes. This <em>MAY NOT</em> | ||||
|      *                   include all changes, and so block updates should still be listened to. | ||||
|      * @return The peripheral component access. | ||||
|      */ | ||||
|     ComponentAccess<IPeripheral> createPeripheralAccess(Consumer<Direction> invalidate); | ||||
| 
 | ||||
|     /** | ||||
|      * Create a {@link ComponentAccess} for surrounding wired nodes. | ||||
|      * | ||||
|      * @param invalidate The function to call when a neighbouring wired node potentially changes. This <em>MAY NOT</em> | ||||
|      *                   include all changes, and so block updates should still be listened to. | ||||
|      * @return The peripheral component access. | ||||
|      */ | ||||
|     ComponentAccess<IWiredElement> createWiredElementAccess(Consumer<Direction> invalidate); | ||||
| 
 | ||||
|     /** | ||||
|      * Determine if there is a wired element in the given direction. This is equivalent to | ||||
|      * {@code createWiredElementAt(x -> {}).get(level, pos, dir) != null}, but is intended for when we don't need the | ||||
|      * cache. | ||||
|      * | ||||
|      * @param level     The current level. | ||||
|      * @param pos       The <em>current</em> block's position. | ||||
|      * @param direction The direction to check in. | ||||
|      * @return Whether there is a wired element in the given direction. | ||||
|      */ | ||||
|     boolean hasWiredElementIn(Level level, BlockPos pos, Direction direction); | ||||
| } | ||||
|   | ||||
| @@ -7,10 +7,16 @@ package dan200.computercraft.shared.platform; | ||||
| 
 | ||||
| import com.google.auto.service.AutoService; | ||||
| import dan200.computercraft.api.ComputerCraftAPI; | ||||
| import dan200.computercraft.api.network.wired.IWiredElement; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.shared.Capabilities; | ||||
| import dan200.computercraft.shared.Peripherals; | ||||
| import dan200.computercraft.shared.network.NetworkMessage; | ||||
| import dan200.computercraft.shared.network.client.ClientNetworkContext; | ||||
| import dan200.computercraft.shared.network.container.ContainerData; | ||||
| import dan200.computercraft.shared.util.CapabilityUtil; | ||||
| import net.minecraft.core.BlockPos; | ||||
| import net.minecraft.core.Direction; | ||||
| import net.minecraft.core.Registry; | ||||
| import net.minecraft.nbt.CompoundTag; | ||||
| import net.minecraft.network.FriendlyByteBuf; | ||||
| @@ -24,13 +30,16 @@ import net.minecraft.world.entity.player.Player; | ||||
| import net.minecraft.world.inventory.AbstractContainerMenu; | ||||
| import net.minecraft.world.inventory.MenuType; | ||||
| import net.minecraft.world.item.ItemStack; | ||||
| import net.minecraft.world.level.Level; | ||||
| import net.minecraft.world.level.block.Block; | ||||
| import net.minecraft.world.level.block.entity.BlockEntity; | ||||
| import net.minecraft.world.level.block.entity.BlockEntityType; | ||||
| import net.minecraft.world.level.block.state.BlockState; | ||||
| import net.minecraft.world.level.chunk.LevelChunk; | ||||
| import net.minecraft.world.phys.Vec3; | ||||
| import net.minecraftforge.common.capabilities.Capability; | ||||
| import net.minecraftforge.common.extensions.IForgeMenuType; | ||||
| import net.minecraftforge.common.util.NonNullConsumer; | ||||
| import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; | ||||
| import net.minecraftforge.network.NetworkHooks; | ||||
| import net.minecraftforge.registries.DeferredRegister; | ||||
| @@ -43,6 +52,7 @@ import java.util.Collection; | ||||
| import java.util.Iterator; | ||||
| import java.util.Set; | ||||
| import java.util.function.BiFunction; | ||||
| import java.util.function.Consumer; | ||||
| import java.util.function.Function; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| @@ -118,6 +128,24 @@ public class PlatformHelperImpl implements PlatformHelper { | ||||
|         NetworkHandler.sendToAllTracking(message, chunk); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ComponentAccess<IPeripheral> createPeripheralAccess(Consumer<Direction> invalidate) { | ||||
|         return new PeripheralAccess(invalidate); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public ComponentAccess<IWiredElement> createWiredElementAccess(Consumer<Direction> invalidate) { | ||||
|         return new CapabilityAccess<>(Capabilities.CAPABILITY_WIRED_ELEMENT, invalidate); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public boolean hasWiredElementIn(Level level, BlockPos pos, Direction direction) { | ||||
|         if (!level.isLoaded(pos)) return false; | ||||
| 
 | ||||
|         var blockEntity = level.getBlockEntity(pos.relative(direction)); | ||||
|         return blockEntity != null && blockEntity.getCapability(Capabilities.CAPABILITY_WIRED_ELEMENT, direction.getOpposite()).isPresent(); | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public CompoundTag getShareTag(ItemStack item) { | ||||
| @@ -190,4 +218,62 @@ public class PlatformHelperImpl implements PlatformHelper { | ||||
|             return object.get(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private abstract static class ComponentAccessImpl<T> implements ComponentAccess<T> { | ||||
|         private final NonNullConsumer<Object>[] invalidators; | ||||
|         private @Nullable Level level; | ||||
|         private @Nullable BlockPos pos; | ||||
| 
 | ||||
|         ComponentAccessImpl(Consumer<Direction> invalidate) { | ||||
|             // Generate a cache of invalidation functions so we can guarantee we only ever have one registered per | ||||
|             // capability - there's no way to remove these callbacks! | ||||
|             @SuppressWarnings({ "unchecked", "rawtypes" }) | ||||
|             var invalidators = this.invalidators = new NonNullConsumer[6]; | ||||
|             for (var dir : Direction.values()) invalidators[dir.ordinal()] = x -> invalidate.accept(dir); | ||||
|         } | ||||
| 
 | ||||
|         @Nullable | ||||
|         protected abstract T get(ServerLevel world, BlockPos pos, Direction side, NonNullConsumer<Object> invalidate); | ||||
| 
 | ||||
|         @Nullable | ||||
|         @Override | ||||
|         public T get(ServerLevel level, BlockPos pos, Direction direction) { | ||||
|             if (this.level != null && this.level != level) throw new IllegalStateException("Level has changed"); | ||||
|             if (this.pos != null && this.pos != pos) throw new IllegalStateException("Position has changed"); | ||||
| 
 | ||||
|             this.level = level; | ||||
|             this.pos = pos; | ||||
|             return get(level, pos.relative(direction), direction.getOpposite(), invalidators[direction.ordinal()]); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static class PeripheralAccess extends ComponentAccessImpl<IPeripheral> { | ||||
|         PeripheralAccess(Consumer<Direction> invalidate) { | ||||
|             super(invalidate); | ||||
|         } | ||||
| 
 | ||||
|         @Nullable | ||||
|         @Override | ||||
|         protected IPeripheral get(ServerLevel world, BlockPos pos, Direction side, NonNullConsumer<Object> invalidate) { | ||||
|             return Peripherals.getPeripheral(world, pos, side, invalidate); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static class CapabilityAccess<T> extends ComponentAccessImpl<T> { | ||||
|         private final Capability<T> capability; | ||||
| 
 | ||||
|         CapabilityAccess(Capability<T> capability, Consumer<Direction> invalidate) { | ||||
|             super(invalidate); | ||||
|             this.capability = capability; | ||||
|         } | ||||
| 
 | ||||
|         @Nullable | ||||
|         @Override | ||||
|         protected T get(ServerLevel world, BlockPos pos, Direction side, NonNullConsumer<Object> invalidate) { | ||||
|             if (!world.isLoaded(pos)) return null; | ||||
| 
 | ||||
|             var blockEntity = world.getBlockEntity(pos); | ||||
|             return blockEntity != null ? CapabilityUtil.unwrap(blockEntity.getCapability(capability, side), invalidate) : null; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates