1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-11-05 09:36:19 +00:00

Construct ComponentAccesses with the BE

After embarrassing, let's do some proper work.

Rather than passing the level and position each time we call
ComponentAccess.get(), we now pass them at construction time (in the
form of the BE). This makes the consuming code a little cleaner, and is
required for the NeoForge changes in 1.20.4.
This commit is contained in:
Jonathan Coates 2024-01-14 17:46:37 +00:00
parent e6ee292850
commit be4512d1c3
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
10 changed files with 71 additions and 73 deletions

View File

@ -25,7 +25,6 @@ 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;
@ -51,7 +50,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
private boolean fresh = false;
private int invalidSides = 0;
private final ComponentAccess<IPeripheral> peripherals = PlatformHelper.get().createPeripheralAccess(d -> invalidSides |= 1 << d.ordinal());
private final ComponentAccess<IPeripheral> peripherals = PlatformHelper.get().createPeripheralAccess(this, d -> invalidSides |= 1 << d.ordinal());
private LockCode lockCode = LockCode.NO_LOCK;
@ -218,7 +217,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
var localDir = remapToLocalSide(dir);
if (isPeripheralBlockedOnSide(localDir)) return;
var peripheral = peripherals.get((ServerLevel) getLevel(), getBlockPos(), dir);
var peripheral = peripherals.get(dir);
computer.setPeripheral(localDir, peripheral);
}

View File

@ -18,7 +18,6 @@ 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.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
@ -60,7 +59,7 @@ public class CableBlockEntity extends BlockEntity {
private boolean invalidPeripheral;
private boolean peripheralAccessAllowed;
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral(this::queueRefreshPeripheral);
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral(PlatformHelper.get().createPeripheralAccess(this, x -> queueRefreshPeripheral()));
private @Nullable Runnable modemChanged;
private boolean connectionsFormed = false;
@ -88,7 +87,7 @@ public class CableBlockEntity extends BlockEntity {
}
};
private final ComponentAccess<WiredElement> connectedElements = PlatformHelper.get().createWiredElementAccess(x -> connectionsChanged());
private final ComponentAccess<WiredElement> connectedElements = PlatformHelper.get().createWiredElementAccess(this, x -> connectionsChanged());
public CableBlockEntity(BlockEntityType<? extends CableBlockEntity> type, BlockPos pos, BlockState state) {
super(type, pos, state);
@ -249,7 +248,7 @@ public class CableBlockEntity extends BlockEntity {
var offset = current.relative(facing);
if (!world.isLoaded(offset)) continue;
var element = connectedElements.get((ServerLevel) world, current, facing);
var element = connectedElements.get(facing);
if (element == null) continue;
var node = element.getNode();

View File

@ -17,7 +17,6 @@ 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.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
@ -81,15 +80,15 @@ public class WiredModemFullBlockEntity extends BlockEntity {
private final WiredModemElement element = new FullElement(this);
private final WiredNode node = element.getNode();
private final ComponentAccess<WiredElement> connectedElements = PlatformHelper.get().createWiredElementAccess(x -> connectionsChanged());
private final ComponentAccess<WiredElement> connectedElements = PlatformHelper.get().createWiredElementAccess(this, x -> connectionsChanged());
private int invalidSides = 0;
public WiredModemFullBlockEntity(BlockEntityType<WiredModemFullBlockEntity> type, BlockPos pos, BlockState state) {
super(type, pos, state);
var peripheralAccess = PlatformHelper.get().createPeripheralAccess(this, this::queueRefreshPeripheral);
for (var i = 0; i < peripherals.length; i++) {
var facing = Direction.from3DDataValue(i);
peripherals[i] = new WiredModemLocalPeripheral(() -> queueRefreshPeripheral(facing));
peripherals[i] = new WiredModemLocalPeripheral(peripheralAccess);
}
}
@ -216,7 +215,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
var offset = current.relative(facing);
if (!world.isLoaded(offset)) continue;
var element = connectedElements.get((ServerLevel) getLevel(), getBlockPos(), facing);
var element = connectedElements.get(facing);
if (element == null) continue;
node.connectTo(element.getNode());

View File

@ -8,12 +8,10 @@ import dan200.computercraft.api.ComputerCraftTags;
import dan200.computercraft.api.peripheral.IPeripheral;
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 javax.annotation.Nullable;
@ -38,8 +36,8 @@ public final class WiredModemLocalPeripheral {
private @Nullable IPeripheral peripheral;
private final ComponentAccess<IPeripheral> peripherals;
public WiredModemLocalPeripheral(Runnable invalidate) {
peripherals = PlatformHelper.get().createPeripheralAccess(x -> invalidate.run());
public WiredModemLocalPeripheral(ComponentAccess<IPeripheral> peripherals) {
this.peripherals = peripherals;
}
/**
@ -126,7 +124,7 @@ public final class WiredModemLocalPeripheral {
if (world.getBlockState(offset).is(ComputerCraftTags.Blocks.PERIPHERAL_HUB_IGNORE)) return null;
var peripheral = peripherals.get((ServerLevel) world, pos, direction);
var peripheral = peripherals.get(direction);
return peripheral instanceof WiredModemPeripheral ? null : peripheral;
}
}

View File

@ -4,9 +4,7 @@
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;
@ -18,15 +16,11 @@ import javax.annotation.Nullable;
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);
T get(Direction direction);
}

View File

@ -222,20 +222,22 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper
/**
* Create a {@link ComponentAccess} for surrounding peripherals.
*
* @param owner The block entity requesting 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);
ComponentAccess<IPeripheral> createPeripheralAccess(BlockEntity owner, Consumer<Direction> invalidate);
/**
* Create a {@link ComponentAccess} for surrounding wired nodes.
*
* @param owner The block entity requesting surrounding wired elements.
* @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<WiredElement> createWiredElementAccess(Consumer<Direction> invalidate);
ComponentAccess<WiredElement> createWiredElementAccess(BlockEntity owner, Consumer<Direction> invalidate);
/**
* Determine if there is a wired element in the given direction. This is equivalent to

View File

@ -177,12 +177,12 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat
}
@Override
public ComponentAccess<IPeripheral> createPeripheralAccess(Consumer<Direction> invalidate) {
public ComponentAccess<IPeripheral> createPeripheralAccess(BlockEntity owner, Consumer<Direction> invalidate) {
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
}
@Override
public ComponentAccess<WiredElement> createWiredElementAccess(Consumer<Direction> invalidate) {
public ComponentAccess<WiredElement> createWiredElementAccess(BlockEntity owner, Consumer<Direction> invalidate) {
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
}

View File

@ -4,6 +4,7 @@
package dan200.computercraft.gametest.api
import dan200.computercraft.api.peripheral.IPeripheral
import dan200.computercraft.gametest.core.ManagedComputers
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
@ -21,6 +22,8 @@ import net.minecraft.world.Container
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.EntityType
import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.block.Blocks
import net.minecraft.world.level.block.entity.BarrelBlockEntity
import net.minecraft.world.level.block.entity.BlockEntity
import net.minecraft.world.level.block.entity.BlockEntityType
import net.minecraft.world.level.block.state.BlockState
@ -206,9 +209,17 @@ private fun GameTestHelper.assertContainerExactlyImpl(pos: BlockPos, container:
}
}
/**
* A nasty hack to get a peripheral at a given position, by creating a dummy [BlockEntity].
*/
private fun GameTestHelper.getPeripheralAt(pos: BlockPos, direction: Direction): IPeripheral? {
val be = BarrelBlockEntity(absolutePos(pos).relative(direction), Blocks.BARREL.defaultBlockState())
be.setLevel(level)
return PlatformHelper.get().createPeripheralAccess(be) { }.get(direction.opposite)
}
fun GameTestHelper.assertPeripheral(pos: BlockPos, direction: Direction = Direction.UP, type: String) {
val peripheral = PlatformHelper.get().createPeripheralAccess { }
.get(level, absolutePos(pos).relative(direction), direction.opposite)
val peripheral = getPeripheralAt(pos, direction)
when {
peripheral == null -> fail("No peripheral at position", pos)
peripheral.type != type -> fail("Peripheral is of type ${peripheral.type}, expected $type", pos)
@ -216,8 +227,7 @@ fun GameTestHelper.assertPeripheral(pos: BlockPos, direction: Direction = Direct
}
fun GameTestHelper.assertNoPeripheral(pos: BlockPos, direction: Direction = Direction.UP) {
val peripheral = PlatformHelper.get().createPeripheralAccess { }
.get(level, absolutePos(pos).relative(direction), direction.opposite)
val peripheral = getPeripheralAt(pos, direction)
if (peripheral != null) fail("Expected no peripheral, got a ${peripheral.type}", pos)
}

View File

@ -83,10 +83,7 @@ import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.*;
import java.util.function.*;
@AutoService(dan200.computercraft.impl.PlatformHelper.class)
@ -217,13 +214,13 @@ public class PlatformHelperImpl implements PlatformHelper {
}
@Override
public ComponentAccess<IPeripheral> createPeripheralAccess(Consumer<Direction> invalidate) {
return new PeripheralAccessImpl(invalidate);
public ComponentAccess<IPeripheral> createPeripheralAccess(BlockEntity owner, Consumer<Direction> invalidate) {
return new PeripheralAccessImpl(owner, invalidate);
}
@Override
public ComponentAccess<WiredElement> createWiredElementAccess(Consumer<Direction> invalidate) {
return new ComponentAccessImpl<>(WiredElementLookup.get());
public ComponentAccess<WiredElement> createWiredElementAccess(BlockEntity owner, Consumer<Direction> invalidate) {
return new ComponentAccessImpl<>(owner, WiredElementLookup.get());
}
@Override
@ -464,50 +461,49 @@ public class PlatformHelperImpl implements PlatformHelper {
}
private static class ComponentAccessImpl<T> implements ComponentAccess<T> {
private final BlockEntity owner;
private final BlockApiLookup<T, Direction> lookup;
@SuppressWarnings({ "unchecked", "rawtypes" })
final BlockApiCache<T, Direction>[] caches = new BlockApiCache[6];
private @Nullable Level level;
private @Nullable BlockPos pos;
private ComponentAccessImpl(BlockApiLookup<T, Direction> lookup) {
private ComponentAccessImpl(BlockEntity owner, BlockApiLookup<T, Direction> lookup) {
this.owner = owner;
this.lookup = lookup;
}
@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;
public T get(Direction direction) {
var cache = caches[direction.ordinal()];
if (cache == null) {
cache = caches[direction.ordinal()] = BlockApiCache.create(lookup, level, pos.relative(direction));
cache = caches[direction.ordinal()] = BlockApiCache.create(lookup, getLevel(), owner.getBlockPos().relative(direction));
}
return cache.find(direction.getOpposite());
}
private ServerLevel getLevel() {
return Objects.requireNonNull((ServerLevel) owner.getLevel(), "Block entity is not in a level");
}
}
private static final class PeripheralAccessImpl extends ComponentAccessImpl<IPeripheral> {
private final Runnable[] invalidators = new Runnable[6];
private PeripheralAccessImpl(Consumer<Direction> invalidate) {
super(PeripheralLookup.get());
private PeripheralAccessImpl(BlockEntity owner, Consumer<Direction> invalidate) {
super(owner, PeripheralLookup.get());
for (var dir : Direction.values()) invalidators[dir.ordinal()] = () -> invalidate.accept(dir);
}
@Nullable
@Override
public IPeripheral get(ServerLevel level, BlockPos pos, Direction direction) {
var result = super.get(level, pos, direction);
public IPeripheral get(Direction direction) {
var result = super.get(direction);
if (result != null) return result;
var cache = caches[direction.ordinal()];
var invalidate = invalidators[direction.ordinal()];
return Peripherals.getGenericPeripheral(level, cache.getPos(), direction.getOpposite(), cache.getBlockEntity(), invalidate);
return Peripherals.getGenericPeripheral(cache.getWorld(), cache.getPos(), direction.getOpposite(), cache.getBlockEntity(), invalidate);
}
}
}

View File

@ -189,13 +189,13 @@ public class PlatformHelperImpl implements PlatformHelper {
}
@Override
public ComponentAccess<IPeripheral> createPeripheralAccess(Consumer<Direction> invalidate) {
return new PeripheralAccess(invalidate);
public ComponentAccess<IPeripheral> createPeripheralAccess(BlockEntity owner, Consumer<Direction> invalidate) {
return new PeripheralAccess(owner, invalidate);
}
@Override
public ComponentAccess<WiredElement> createWiredElementAccess(Consumer<Direction> invalidate) {
return new CapabilityAccess<>(Capabilities.CAPABILITY_WIRED_ELEMENT, invalidate);
public ComponentAccess<WiredElement> createWiredElementAccess(BlockEntity owner, Consumer<Direction> invalidate) {
return new CapabilityAccess<>(owner, Capabilities.CAPABILITY_WIRED_ELEMENT, invalidate);
}
@Override
@ -434,11 +434,12 @@ public class PlatformHelperImpl implements PlatformHelper {
}
private abstract static class ComponentAccessImpl<T> implements ComponentAccess<T> {
private final BlockEntity owner;
private final InvalidateCallback[] invalidators;
private @Nullable Level level;
private @Nullable BlockPos pos;
ComponentAccessImpl(Consumer<Direction> invalidate) {
ComponentAccessImpl(BlockEntity owner, Consumer<Direction> invalidate) {
this.owner = owner;
// 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!
var invalidators = this.invalidators = new InvalidateCallback[6];
@ -450,19 +451,19 @@ public class PlatformHelperImpl implements PlatformHelper {
@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()]);
public T get(Direction direction) {
return get(getLevel(), owner.getBlockPos().relative(direction), direction.getOpposite(), invalidators[direction.ordinal()]);
}
final ServerLevel getLevel() {
return Objects.requireNonNull((ServerLevel) owner.getLevel(), "Block entity is not in a level");
}
}
private static class PeripheralAccess extends ComponentAccessImpl<IPeripheral> {
PeripheralAccess(Consumer<Direction> invalidate) {
super(invalidate);
PeripheralAccess(BlockEntity owner, Consumer<Direction> invalidate) {
super(owner, invalidate);
}
@Nullable
@ -475,8 +476,8 @@ public class PlatformHelperImpl implements PlatformHelper {
private static class CapabilityAccess<T> extends ComponentAccessImpl<T> {
private final Capability<T> capability;
CapabilityAccess(Capability<T> capability, Consumer<Direction> invalidate) {
super(invalidate);
CapabilityAccess(BlockEntity owner, Capability<T> capability, Consumer<Direction> invalidate) {
super(owner, invalidate);
this.capability = capability;
}