mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-26 09:54:49 +00:00
Merge branch 'mc-1.16.x' into mc-1.17.x
This commit is contained in:
@@ -38,13 +38,13 @@ public final class Peripherals
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IPeripheral getPeripheral( Level world, BlockPos pos, Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate )
|
||||
public static IPeripheral getPeripheral( Level world, BlockPos pos, Direction side, NonNullConsumer<Object> invalidate )
|
||||
{
|
||||
return world.isInWorldBounds( pos ) && !world.isClientSide ? getPeripheralAt( world, pos, side, invalidate ) : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static IPeripheral getPeripheralAt( Level world, BlockPos pos, Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate )
|
||||
private static IPeripheral getPeripheralAt( Level world, BlockPos pos, Direction side, NonNullConsumer<? super Object> invalidate )
|
||||
{
|
||||
BlockEntity block = world.getBlockEntity( pos );
|
||||
if( block != null )
|
||||
|
||||
@@ -59,7 +59,7 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
|
||||
super.onPlace( state, world, pos, oldState, isMoving );
|
||||
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( tile instanceof TileComputerBase computer ) computer.updateInput();
|
||||
if( tile instanceof TileComputerBase computer ) computer.updateInputsImmediately( );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,14 +31,9 @@ import net.minecraft.world.Nameable;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.DiodeBlock;
|
||||
import net.minecraft.world.level.block.RedStoneWireBlock;
|
||||
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.LazyOptional;
|
||||
import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -57,7 +52,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
private boolean on = false;
|
||||
boolean startOn = false;
|
||||
private boolean fresh = false;
|
||||
private final NonNullConsumer<LazyOptional<IPeripheral>>[] invalidate;
|
||||
|
||||
private int invalidSides = 0;
|
||||
private final NonNullConsumer<Object>[] invalidate;
|
||||
|
||||
private final ComputerFamily family;
|
||||
|
||||
@@ -68,10 +65,11 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
|
||||
// We cache these so we can guarantee we only ever register one listener for adjacent capabilities.
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" } )
|
||||
NonNullConsumer<LazyOptional<IPeripheral>>[] invalidate = this.invalidate = new NonNullConsumer[6];
|
||||
NonNullConsumer<Object>[] invalidate = this.invalidate = new NonNullConsumer[6];
|
||||
for( Direction direction : Direction.values() )
|
||||
{
|
||||
invalidate[direction.ordinal()] = o -> updateInput( direction );
|
||||
int mask = 1 << direction.ordinal();
|
||||
invalidate[direction.ordinal()] = o -> invalidSides |= mask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,19 +141,26 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
@Override
|
||||
public void onNeighbourChange( @Nonnull BlockPos neighbour )
|
||||
{
|
||||
updateInput( neighbour );
|
||||
updateInputAt( neighbour );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
|
||||
{
|
||||
updateInput( neighbour );
|
||||
updateInputAt( neighbour );
|
||||
}
|
||||
|
||||
protected void serverTick()
|
||||
{
|
||||
ServerComputer computer = createServerComputer();
|
||||
if( computer == null ) return;
|
||||
|
||||
if( invalidSides != 0 )
|
||||
{
|
||||
for( Direction direction : DirectionUtil.FACINGS )
|
||||
{
|
||||
if( (invalidSides & (1 << direction.ordinal())) != 0 ) refreshPeripheral( computer, direction );
|
||||
}
|
||||
}
|
||||
|
||||
// If the computer isn't on and should be, then turn it on
|
||||
if( startOn || (fresh && on) )
|
||||
@@ -222,89 +227,80 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
return localSide;
|
||||
}
|
||||
|
||||
private void updateSideInput( ServerComputer computer, Direction dir, BlockPos offset )
|
||||
private void updateRedstoneInput( @Nonnull ServerComputer computer, Direction dir, BlockPos targetPos )
|
||||
{
|
||||
Direction offsetSide = dir.getOpposite();
|
||||
ComputerSide localDir = remapToLocalSide( dir );
|
||||
|
||||
computer.setRedstoneInput( localDir, getRedstoneInput( level, offset, dir ) );
|
||||
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), offset, offsetSide ) );
|
||||
if( !isPeripheralBlockedOnSide( localDir ) )
|
||||
{
|
||||
IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), offset, offsetSide, invalidate[dir.ordinal()] );
|
||||
computer.setPeripheral( localDir, peripheral );
|
||||
}
|
||||
computer.setRedstoneInput( localDir, RedstoneUtil.getRedstoneInput( level, targetPos, dir ) );
|
||||
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), targetPos, offsetSide ) );
|
||||
}
|
||||
|
||||
private void refreshPeripheral( @Nonnull ServerComputer computer, Direction dir )
|
||||
{
|
||||
invalidSides &= ~(1 << dir.ordinal());
|
||||
|
||||
ComputerSide localDir = remapToLocalSide( dir );
|
||||
if( isPeripheralBlockedOnSide( localDir ) ) return;
|
||||
|
||||
Direction offsetSide = dir.getOpposite();
|
||||
IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), getBlockPos().relative( dir ), offsetSide, invalidate[dir.ordinal()] );
|
||||
computer.setPeripheral( localDir, peripheral );
|
||||
}
|
||||
|
||||
public void updateInputsImmediately()
|
||||
{
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null ) updateInputsImmediately( computer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the redstone input for an adjacent block.
|
||||
* Update all redstone and peripherals.
|
||||
*
|
||||
* @param world The world we exist in
|
||||
* @param pos The position of the neighbour
|
||||
* @param side The side we are reading from
|
||||
* @return The effective redstone power
|
||||
* @see DiodeBlock#getInputSignal(Level, BlockPos, BlockState)
|
||||
* This should only be really be called when the computer is being ticked (though there are some cases where it
|
||||
* won't be), as peripheral scanning requires adjacent tiles to be in a "correct" state - which may not be the case
|
||||
* if they're still updating!
|
||||
*
|
||||
* @param computer The current computer instance.
|
||||
*/
|
||||
protected static int getRedstoneInput( Level world, BlockPos pos, Direction side )
|
||||
private void updateInputsImmediately( @Nonnull ServerComputer computer )
|
||||
{
|
||||
int power = world.getSignal( pos, side );
|
||||
if( power >= 15 ) return power;
|
||||
|
||||
BlockState neighbour = world.getBlockState( pos );
|
||||
return neighbour.getBlock() == Blocks.REDSTONE_WIRE
|
||||
? Math.max( power, neighbour.getValue( RedStoneWireBlock.POWER ) )
|
||||
: power;
|
||||
}
|
||||
|
||||
public void updateInput()
|
||||
{
|
||||
if( getLevel() == null || getLevel().isClientSide ) return;
|
||||
|
||||
// Update all sides
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer == null ) return;
|
||||
|
||||
BlockPos pos = computer.getPosition();
|
||||
BlockPos pos = getBlockPos();
|
||||
for( Direction dir : DirectionUtil.FACINGS )
|
||||
{
|
||||
updateSideInput( computer, dir, pos.relative( dir ) );
|
||||
updateRedstoneInput( computer, dir, pos.relative( dir ) );
|
||||
refreshPeripheral( computer, dir );
|
||||
}
|
||||
}
|
||||
|
||||
private void updateInput( BlockPos neighbour )
|
||||
private void updateInputAt( @Nonnull BlockPos neighbour )
|
||||
{
|
||||
if( getLevel() == null || getLevel().isClientSide ) return;
|
||||
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer == null ) return;
|
||||
|
||||
for( Direction dir : DirectionUtil.FACINGS )
|
||||
{
|
||||
BlockPos offset = worldPosition.relative( dir );
|
||||
BlockPos offset = getBlockPos().relative( dir );
|
||||
if( offset.equals( neighbour ) )
|
||||
{
|
||||
updateSideInput( computer, dir, offset );
|
||||
updateRedstoneInput( computer, dir, offset );
|
||||
invalidSides |= 1 << dir.ordinal();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the position is not any adjacent one, update all inputs.
|
||||
updateInput();
|
||||
}
|
||||
|
||||
private void updateInput( Direction dir )
|
||||
{
|
||||
if( getLevel() == null || getLevel().isClientSide ) return;
|
||||
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer == null ) return;
|
||||
|
||||
updateSideInput( computer, dir, worldPosition.relative( dir ) );
|
||||
// If the position is not any adjacent one, update all inputs. This is pretty terrible, but some redstone mods
|
||||
// handle this incorrectly.
|
||||
BlockPos pos = getBlockPos();
|
||||
for( Direction dir : DirectionUtil.FACINGS ) updateRedstoneInput( computer, dir, pos.relative( dir ) );
|
||||
invalidSides = (1 << 6) - 1; // Mark all peripherals as dirty.
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the block's state and propagate redstone output.
|
||||
*/
|
||||
public void updateOutput()
|
||||
{
|
||||
// Update redstone
|
||||
updateBlock();
|
||||
for( Direction dir : DirectionUtil.FACINGS )
|
||||
{
|
||||
@@ -354,9 +350,10 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
return family;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public ServerComputer createServerComputer()
|
||||
{
|
||||
if( getLevel().isClientSide ) return null;
|
||||
if( getLevel().isClientSide ) throw new IllegalStateException( "Cannot access server computer on the client." );
|
||||
|
||||
boolean changed = false;
|
||||
if( instanceID < 0 )
|
||||
@@ -364,18 +361,21 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID();
|
||||
changed = true;
|
||||
}
|
||||
if( !ComputerCraft.serverComputerRegistry.contains( instanceID ) )
|
||||
|
||||
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instanceID );
|
||||
if( computer == null )
|
||||
{
|
||||
ServerComputer computer = createComputer( instanceID, computerID );
|
||||
computer = createComputer( instanceID, computerID );
|
||||
ComputerCraft.serverComputerRegistry.add( instanceID, computer );
|
||||
fresh = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if( changed ) updateInput();
|
||||
return ComputerCraft.serverComputerRegistry.get( instanceID );
|
||||
if( changed ) updateInputsImmediately( computer );
|
||||
return computer;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ServerComputer getServerComputer()
|
||||
{
|
||||
return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID );
|
||||
|
||||
@@ -128,7 +128,7 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider
|
||||
public static void onCapability( AttachCapabilitiesEvent<BlockEntity> event )
|
||||
{
|
||||
BlockEntity tile = event.getObject();
|
||||
if( tile instanceof CommandBlockEntity )
|
||||
if( ComputerCraft.enableCommandBlock && tile instanceof CommandBlockEntity )
|
||||
{
|
||||
CommandBlockPeripheral peripheral = new CommandBlockPeripheral( (CommandBlockEntity) tile );
|
||||
event.addCapability( CAP_ID, peripheral );
|
||||
|
||||
@@ -18,18 +18,21 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
class GenericPeripheral implements IDynamicPeripheral
|
||||
{
|
||||
private final String type;
|
||||
private final Set<String> additionalTypes;
|
||||
private final BlockEntity tile;
|
||||
private final List<SaturatedMethod> methods;
|
||||
|
||||
GenericPeripheral( BlockEntity tile, String name, List<SaturatedMethod> methods )
|
||||
GenericPeripheral( BlockEntity tile, String name, Set<String> additionalTypes, List<SaturatedMethod> methods )
|
||||
{
|
||||
ResourceLocation type = tile.getType().getRegistryName();
|
||||
this.tile = tile;
|
||||
this.type = name != null ? name : (type != null ? type.toString() : "unknown");
|
||||
this.additionalTypes = additionalTypes;
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
@@ -56,6 +59,13 @@ class GenericPeripheral implements IDynamicPeripheral
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<String> getAdditionalTypes()
|
||||
{
|
||||
return additionalTypes;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getTarget()
|
||||
|
||||
@@ -9,6 +9,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralType;
|
||||
import dan200.computercraft.core.asm.NamedMethod;
|
||||
import dan200.computercraft.core.asm.PeripheralMethod;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
@@ -19,9 +20,7 @@ import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.*;
|
||||
|
||||
public class GenericPeripheralProvider
|
||||
{
|
||||
@@ -34,7 +33,7 @@ public class GenericPeripheralProvider
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate )
|
||||
public static IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer<Object> invalidate )
|
||||
{
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( tile == null ) return null;
|
||||
@@ -52,7 +51,7 @@ public class GenericPeripheralProvider
|
||||
if( capabilityMethods.isEmpty() ) return;
|
||||
|
||||
saturated.addMethods( contents, capabilityMethods );
|
||||
wrapper.addListener( cast( invalidate ) );
|
||||
CapabilityUtil.addListener( wrapper, invalidate );
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -61,15 +60,16 @@ public class GenericPeripheralProvider
|
||||
|
||||
private static class GenericPeripheralBuilder
|
||||
{
|
||||
String name;
|
||||
final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 );
|
||||
private String name;
|
||||
private final Set<String> additionalTypes = new HashSet<>( 0 );
|
||||
private final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 );
|
||||
|
||||
IPeripheral toPeripheral( BlockEntity tile )
|
||||
{
|
||||
if( methods.isEmpty() ) return null;
|
||||
|
||||
methods.trimToSize();
|
||||
return new GenericPeripheral( tile, name, methods );
|
||||
return new GenericPeripheral( tile, name, additionalTypes, methods );
|
||||
}
|
||||
|
||||
void addMethods( Object target, List<NamedMethod<PeripheralMethod>> methods )
|
||||
@@ -88,13 +88,8 @@ public class GenericPeripheralProvider
|
||||
String name = type.getPrimaryType();
|
||||
if( this.name == null || this.name.compareTo( name ) > 0 ) this.name = name;
|
||||
}
|
||||
if( type != null ) additionalTypes.addAll( type.getAdditionalTypes() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" } )
|
||||
private static <T> NonNullConsumer<T> cast( NonNullConsumer<?> consumer )
|
||||
{
|
||||
return (NonNullConsumer) consumer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.GenericPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralType;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.energy.IEnergyStorage;
|
||||
|
||||
@@ -25,8 +26,15 @@ import javax.annotation.Nonnull;
|
||||
*
|
||||
* @cc.module energy_storage
|
||||
*/
|
||||
public class EnergyMethods implements GenericSource
|
||||
public class EnergyMethods implements GenericPeripheral
|
||||
{
|
||||
@Nonnull
|
||||
@Override
|
||||
public PeripheralType getType()
|
||||
{
|
||||
return PeripheralType.ofAdditional( "energy_storage" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ResourceLocation id()
|
||||
|
||||
@@ -6,13 +6,15 @@
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.GenericPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralType;
|
||||
import dan200.computercraft.shared.peripheral.generic.data.FluidData;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
@@ -34,8 +36,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
|
||||
*
|
||||
* @cc.module fluid_storage
|
||||
*/
|
||||
public class FluidMethods implements GenericSource
|
||||
public class FluidMethods implements GenericPeripheral
|
||||
{
|
||||
@Nonnull
|
||||
@Override
|
||||
public PeripheralType getType()
|
||||
{
|
||||
return PeripheralType.ofAdditional( "fluid_storage" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ResourceLocation id()
|
||||
@@ -155,13 +164,15 @@ public class FluidMethods implements GenericSource
|
||||
@Nullable
|
||||
private static IFluidHandler extractHandler( @Nullable Object object )
|
||||
{
|
||||
if( object instanceof ICapabilityProvider )
|
||||
if( object instanceof BlockEntity blockEntity && blockEntity.isRemoved() ) return null;
|
||||
|
||||
if( object instanceof ICapabilityProvider provider )
|
||||
{
|
||||
LazyOptional<IFluidHandler> cap = ((ICapabilityProvider) object).getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY );
|
||||
LazyOptional<IFluidHandler> cap = provider.getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY );
|
||||
if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new );
|
||||
}
|
||||
|
||||
if( object instanceof IFluidHandler ) return (IFluidHandler) object;
|
||||
if( object instanceof IFluidHandler handler ) return handler;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,16 +6,18 @@
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
import dan200.computercraft.api.lua.ILuaContext;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.GenericPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralType;
|
||||
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.items.CapabilityItemHandler;
|
||||
@@ -36,8 +38,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
|
||||
*
|
||||
* @cc.module inventory
|
||||
*/
|
||||
public class InventoryMethods implements GenericSource
|
||||
public class InventoryMethods implements GenericPeripheral
|
||||
{
|
||||
@Nonnull
|
||||
@Override
|
||||
public PeripheralType getType()
|
||||
{
|
||||
return PeripheralType.ofAdditional( "inventory" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ResourceLocation id()
|
||||
@@ -259,14 +268,16 @@ public class InventoryMethods implements GenericSource
|
||||
@Nullable
|
||||
private static IItemHandler extractHandler( @Nullable Object object )
|
||||
{
|
||||
if( object instanceof ICapabilityProvider )
|
||||
if( object instanceof BlockEntity blockEntity && blockEntity.isRemoved() ) return null;
|
||||
|
||||
if( object instanceof ICapabilityProvider provider )
|
||||
{
|
||||
LazyOptional<IItemHandler> cap = ((ICapabilityProvider) object).getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY );
|
||||
LazyOptional<IItemHandler> cap = provider.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY );
|
||||
if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new );
|
||||
}
|
||||
|
||||
if( object instanceof IItemHandler ) return (IItemHandler) object;
|
||||
if( object instanceof Container ) return new InvWrapper( (Container) object );
|
||||
if( object instanceof IItemHandler handler ) return handler;
|
||||
if( object instanceof Container container ) return new InvWrapper( container );
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,8 +77,9 @@ public class TileCable extends TileGeneric
|
||||
}
|
||||
}
|
||||
|
||||
private boolean invalidPeripheral;
|
||||
private boolean peripheralAccessAllowed;
|
||||
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral( this::refreshPeripheral );
|
||||
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral( this::queueRefreshPeripheral );
|
||||
|
||||
private boolean destroyed = false;
|
||||
|
||||
@@ -234,12 +235,20 @@ public class TileCable extends TileGeneric
|
||||
if( !level.isClientSide && peripheralAccessAllowed )
|
||||
{
|
||||
Direction facing = getDirection();
|
||||
if( getBlockPos().relative( facing ).equals( neighbour ) ) refreshPeripheral();
|
||||
if( getBlockPos().relative( facing ).equals( neighbour ) ) queueRefreshPeripheral();
|
||||
}
|
||||
}
|
||||
|
||||
private void queueRefreshPeripheral()
|
||||
{
|
||||
if( invalidPeripheral ) return;
|
||||
invalidPeripheral = true;
|
||||
TickScheduler.schedule( this );
|
||||
}
|
||||
|
||||
private void refreshPeripheral()
|
||||
{
|
||||
invalidPeripheral = false;
|
||||
if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), getDirection() ) )
|
||||
{
|
||||
updateConnectedPeripherals();
|
||||
@@ -310,6 +319,8 @@ public class TileCable extends TileGeneric
|
||||
{
|
||||
if( getLevel().isClientSide ) return;
|
||||
|
||||
if( invalidPeripheral ) refreshPeripheral();
|
||||
|
||||
if( modem.getModemState().pollChanged() ) updateBlockState();
|
||||
|
||||
if( !connectionsFormed )
|
||||
|
||||
@@ -108,13 +108,15 @@ public class TileWiredModemFull extends TileGeneric
|
||||
|
||||
private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged();
|
||||
|
||||
private int invalidSides = 0;
|
||||
|
||||
public TileWiredModemFull( BlockEntityType<TileWiredModemFull> type, BlockPos pos, BlockState state )
|
||||
{
|
||||
super( type, pos, state );
|
||||
for( int i = 0; i < peripherals.length; i++ )
|
||||
{
|
||||
Direction facing = Direction.from3DDataValue( i );
|
||||
peripherals[i] = new WiredModemLocalPeripheral( () -> refreshPeripheral( facing ) );
|
||||
peripherals[i] = new WiredModemLocalPeripheral( () -> queueRefreshPeripheral( facing ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,13 +175,20 @@ public class TileWiredModemFull extends TileGeneric
|
||||
{
|
||||
for( Direction facing : DirectionUtil.FACINGS )
|
||||
{
|
||||
if( getBlockPos().relative( facing ).equals( neighbour ) ) refreshPeripheral( facing );
|
||||
if( getBlockPos().relative( facing ).equals( neighbour ) ) queueRefreshPeripheral( facing );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void queueRefreshPeripheral( @Nonnull Direction facing )
|
||||
{
|
||||
if( invalidSides == 0 ) TickScheduler.schedule( this );
|
||||
invalidSides |= 1 << facing.ordinal();
|
||||
}
|
||||
|
||||
private void refreshPeripheral( @Nonnull Direction facing )
|
||||
{
|
||||
invalidSides &= ~(1 << facing.ordinal());
|
||||
WiredModemLocalPeripheral peripheral = peripherals[facing.ordinal()];
|
||||
if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), facing ) )
|
||||
{
|
||||
@@ -262,6 +271,14 @@ public class TileWiredModemFull extends TileGeneric
|
||||
{
|
||||
if( getLevel().isClientSide ) return;
|
||||
|
||||
if( invalidSides != 0 )
|
||||
{
|
||||
for( Direction direction : DirectionUtil.FACINGS )
|
||||
{
|
||||
if( (invalidSides & (1 << direction.ordinal())) != 0 ) refreshPeripheral( direction );
|
||||
}
|
||||
}
|
||||
|
||||
if( modemState.pollChanged() ) updateBlockState();
|
||||
|
||||
if( !connectionsFormed )
|
||||
|
||||
@@ -15,7 +15,6 @@ import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.common.util.LazyOptional;
|
||||
import net.minecraftforge.common.util.NonNullConsumer;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -38,7 +37,7 @@ public final class WiredModemLocalPeripheral
|
||||
private String type;
|
||||
|
||||
private IPeripheral peripheral;
|
||||
private final NonNullConsumer<LazyOptional<IPeripheral>> invalidate;
|
||||
private final NonNullConsumer<Object> invalidate;
|
||||
|
||||
public WiredModemLocalPeripheral( @Nonnull Runnable invalidate )
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ import dan200.computercraft.core.apis.PeripheralAPI;
|
||||
import dan200.computercraft.core.asm.PeripheralMethod;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.modem.ModemState;
|
||||
import dan200.computercraft.shared.util.LuaUtil;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -118,13 +119,35 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
* @param name The peripheral's name.
|
||||
* @return The peripheral's name.
|
||||
* @cc.treturn string|nil The peripheral's type, or {@code nil} if it is not present.
|
||||
* @cc.changed 1.99 Peripherals can have multiple types - this function returns multiple values.
|
||||
* @see PeripheralAPI#getType
|
||||
*/
|
||||
@LuaFunction
|
||||
public final Object[] getTypeRemote( IComputerAccess computer, String name )
|
||||
{
|
||||
RemotePeripheralWrapper wrapper = getWrapper( computer, name );
|
||||
return wrapper != null ? new Object[] { wrapper.getType() } : null;
|
||||
return wrapper == null ? null : LuaUtil.consArray( wrapper.getType(), wrapper.getAdditionalTypes() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a peripheral is of a particular type.
|
||||
*
|
||||
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
|
||||
* returns false before calling it.</blockquote>
|
||||
*
|
||||
* @param computer The calling computer.
|
||||
* @param name The peripheral's name.
|
||||
* @param type The type to check.
|
||||
* @return The peripheral's name.
|
||||
* @cc.treturn boolean|nil If a peripheral has a particular type, or {@literal nil} if it is not present.
|
||||
* @cc.since 1.99
|
||||
* @see PeripheralAPI#getType
|
||||
*/
|
||||
@LuaFunction
|
||||
public final Object[] hasTypeRemote( IComputerAccess computer, String name, String type )
|
||||
{
|
||||
RemotePeripheralWrapper wrapper = getWrapper( computer, name );
|
||||
return wrapper == null ? null : new Object[] { wrapper.getType().equals( type ) || wrapper.getAdditionalTypes().contains( getType() ) };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -307,6 +330,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
private final String name;
|
||||
|
||||
private final String type;
|
||||
private final Set<String> additionalTypes;
|
||||
private final Map<String, PeripheralMethod> methodMap;
|
||||
|
||||
private volatile boolean attached;
|
||||
@@ -320,6 +344,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
this.name = name;
|
||||
|
||||
type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" );
|
||||
additionalTypes = peripheral.getAdditionalTypes();
|
||||
methodMap = PeripheralAPI.getMethods( peripheral );
|
||||
}
|
||||
|
||||
@@ -353,6 +378,11 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
return type;
|
||||
}
|
||||
|
||||
public Set<String> getAdditionalTypes()
|
||||
{
|
||||
return additionalTypes;
|
||||
}
|
||||
|
||||
public Collection<String> getMethodNames()
|
||||
{
|
||||
return methodMap.keySet();
|
||||
|
||||
@@ -331,8 +331,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
{
|
||||
if( dir.getAxis() == Direction.Axis.Y ) dir = Direction.NORTH;
|
||||
level.setBlockAndUpdate( worldPosition, getBlockState().setValue( BlockTurtle.FACING, dir ) );
|
||||
|
||||
updateOutput();
|
||||
updateInput();
|
||||
updateInputsImmediately();
|
||||
|
||||
onTileEntityChange();
|
||||
}
|
||||
|
||||
|
||||
@@ -332,16 +332,17 @@ public class TurtleBrain implements ITurtleAccess
|
||||
// Copy the old turtle state into the new turtle
|
||||
newTurtle.setLevel( world );
|
||||
newTurtle.transferStateFrom( oldOwner );
|
||||
newTurtle.createServerComputer().setLevel( world );
|
||||
newTurtle.createServerComputer().setPosition( pos );
|
||||
|
||||
ServerComputer computer = newTurtle.createServerComputer();
|
||||
computer.setLevel( world );
|
||||
computer.setPosition( pos );
|
||||
|
||||
// Remove the old turtle
|
||||
oldWorld.removeBlock( oldPos, false );
|
||||
|
||||
// Make sure everybody knows about it
|
||||
newTurtle.updateBlock();
|
||||
newTurtle.updateInput();
|
||||
newTurtle.updateOutput();
|
||||
newTurtle.updateInputsImmediately();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -613,16 +614,16 @@ public class TurtleBrain implements ITurtleAccess
|
||||
@Override
|
||||
public void setUpgrade( @Nonnull TurtleSide side, ITurtleUpgrade upgrade )
|
||||
{
|
||||
if( !setUpgradeDirect( side, upgrade ) ) return;
|
||||
if( !setUpgradeDirect( side, upgrade ) || owner.getLevel() == null ) return;
|
||||
|
||||
// This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as
|
||||
// either the block is newly placed (and so won't have changed) or is being updated with /data, which calls
|
||||
// updateBlock for us.
|
||||
if( owner.getLevel() != null )
|
||||
{
|
||||
owner.updateBlock();
|
||||
owner.updateInput();
|
||||
}
|
||||
owner.updateBlock();
|
||||
|
||||
// Recompute peripherals in case an upgrade being removed has exposed a new peripheral.
|
||||
// TODO: Only update peripherals, or even only two sides?
|
||||
owner.updateInputsImmediately();
|
||||
}
|
||||
|
||||
private boolean setUpgradeDirect( @Nonnull TurtleSide side, ITurtleUpgrade upgrade )
|
||||
@@ -644,7 +645,7 @@ public class TurtleBrain implements ITurtleAccess
|
||||
if( upgrade != null ) upgrades.put( side, upgrade );
|
||||
|
||||
// Notify clients and create peripherals
|
||||
if( owner.getLevel() != null )
|
||||
if( owner.getLevel() != null && !owner.getLevel().isClientSide )
|
||||
{
|
||||
updatePeripherals( owner.createServerComputer() );
|
||||
}
|
||||
|
||||
@@ -35,12 +35,20 @@ public final class CapabilityUtil
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void addListener( LazyOptional<T> p, NonNullConsumer<? super LazyOptional<T>> invalidate )
|
||||
{
|
||||
// We can make this safe with invalidate::accept, but then we're allocating it's just kind of absurd.
|
||||
@SuppressWarnings( "unchecked" )
|
||||
NonNullConsumer<LazyOptional<T>> safeInvalidate = (NonNullConsumer<LazyOptional<T>>) invalidate;
|
||||
p.addListener( safeInvalidate );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T> T unwrap( LazyOptional<T> p, NonNullConsumer<LazyOptional<T>> invalidate )
|
||||
public static <T> T unwrap( LazyOptional<T> p, NonNullConsumer<? super LazyOptional<T>> invalidate )
|
||||
{
|
||||
if( !p.isPresent() ) return null;
|
||||
|
||||
p.addListener( invalidate );
|
||||
addListener( p, invalidate );
|
||||
return p.orElseThrow( NullPointerException::new );
|
||||
}
|
||||
|
||||
|
||||
23
src/main/java/dan200/computercraft/shared/util/LuaUtil.java
Normal file
23
src/main/java/dan200/computercraft/shared/util/LuaUtil.java
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class LuaUtil
|
||||
{
|
||||
public static Object[] consArray( Object value, Collection<?> rest )
|
||||
{
|
||||
if( rest.isEmpty() ) return new Object[] { value };
|
||||
|
||||
// I'm not proud of this code.
|
||||
Object[] out = new Object[rest.size() + 1];
|
||||
out[0] = value;
|
||||
int i = 1;
|
||||
for( Object additionalType : rest ) out[i++] = additionalType;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@ package dan200.computercraft.shared.util;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.DiodeBlock;
|
||||
import net.minecraft.world.level.block.RedStoneWireBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.event.ForgeEventFactory;
|
||||
|
||||
@@ -15,6 +18,30 @@ import java.util.EnumSet;
|
||||
|
||||
public final class RedstoneUtil
|
||||
{
|
||||
private RedstoneUtil()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the redstone input for an adjacent block.
|
||||
*
|
||||
* @param world The world we exist in
|
||||
* @param pos The position of the neighbour
|
||||
* @param side The side we are reading from
|
||||
* @return The effective redstone power
|
||||
* @see DiodeBlock#getInputSignal(Level, BlockPos, BlockState)
|
||||
*/
|
||||
public static int getRedstoneInput( Level world, BlockPos pos, Direction side )
|
||||
{
|
||||
int power = world.getSignal( pos, side );
|
||||
if( power >= 15 ) return power;
|
||||
|
||||
BlockState neighbour = world.getBlockState( pos );
|
||||
return neighbour.getBlock() == Blocks.REDSTONE_WIRE
|
||||
? Math.max( power, neighbour.getValue( RedStoneWireBlock.POWER ) )
|
||||
: power;
|
||||
}
|
||||
|
||||
public static void propagateRedstoneOutput( Level world, BlockPos pos, Direction side )
|
||||
{
|
||||
// Propagate ordinary output. See BlockRedstoneDiode.notifyNeighbors
|
||||
|
||||
Reference in New Issue
Block a user