mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-19 06:35:12 +00:00
Merge branch 'mc-1.16.x' into mc-1.17.x
This commit is contained in:
@@ -18,7 +18,8 @@ import dan200.computercraft.shared.computer.blocks.BlockComputer;
|
||||
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
|
||||
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
|
||||
import dan200.computercraft.shared.computer.items.ItemComputer;
|
||||
import dan200.computercraft.shared.computer.recipe.ComputerUpgradeRecipe;
|
||||
@@ -52,7 +53,6 @@ import dan200.computercraft.shared.peripheral.printer.ContainerPrinter;
|
||||
import dan200.computercraft.shared.peripheral.printer.TilePrinter;
|
||||
import dan200.computercraft.shared.peripheral.speaker.BlockSpeaker;
|
||||
import dan200.computercraft.shared.peripheral.speaker.TileSpeaker;
|
||||
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
|
||||
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
|
||||
@@ -312,11 +312,14 @@ public final class Registry
|
||||
{
|
||||
static final DeferredRegister<MenuType<?>> CONTAINERS = DeferredRegister.create( ForgeRegistries.CONTAINERS, ComputerCraft.MOD_ID );
|
||||
|
||||
public static final RegistryObject<MenuType<ContainerComputer>> COMPUTER = CONTAINERS.register( "computer",
|
||||
() -> ContainerData.toType( ComputerContainerData::new, ContainerComputer::new ) );
|
||||
public static final RegistryObject<MenuType<ContainerComputerBase>> COMPUTER = CONTAINERS.register( "computer",
|
||||
() -> ContainerData.toType( ComputerContainerData::new, ComputerMenuWithoutInventory::new ) );
|
||||
|
||||
public static final RegistryObject<MenuType<ContainerPocketComputer>> POCKET_COMPUTER = CONTAINERS.register( "pocket_computer",
|
||||
() -> ContainerData.toType( ComputerContainerData::new, ContainerPocketComputer::new ) );
|
||||
public static final RegistryObject<MenuType<ContainerComputerBase>> POCKET_COMPUTER = CONTAINERS.register( "pocket_computer",
|
||||
() -> ContainerData.toType( ComputerContainerData::new, ComputerMenuWithoutInventory::new ) );
|
||||
|
||||
public static final RegistryObject<MenuType<ContainerComputerBase>> POCKET_COMPUTER_NO_TERM = CONTAINERS.register( "pocket_computer_no_term",
|
||||
() -> ContainerData.toType( ComputerContainerData::new, ComputerMenuWithoutInventory::new ) );
|
||||
|
||||
public static final RegistryObject<MenuType<ContainerTurtle>> TURTLE = CONTAINERS.register( "turtle",
|
||||
() -> ContainerData.toType( ComputerContainerData::new, ContainerTurtle::new ) );
|
||||
|
||||
@@ -236,7 +236,7 @@ public final class CommandComputerCraft
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu( int id, @Nonnull Inventory player, @Nonnull Player entity )
|
||||
{
|
||||
return new ContainerViewComputer( id, computer );
|
||||
return new ContainerViewComputer( id, player, computer );
|
||||
}
|
||||
} );
|
||||
return 1;
|
||||
|
||||
@@ -56,18 +56,17 @@ public enum UserLevel implements Predicate<CommandSourceStack>
|
||||
public boolean test( CommandSourceStack source )
|
||||
{
|
||||
if( this == ANYONE ) return true;
|
||||
|
||||
if( this == OWNER || this == OWNER_OP )
|
||||
{
|
||||
MinecraftServer server = source.getServer();
|
||||
Entity sender = source.getEntity();
|
||||
if( server.isSingleplayer() && sender instanceof Player &&
|
||||
((Player) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if( this == OWNER ) return isOwner( source );
|
||||
if( this == OWNER_OP && isOwner( source ) ) return true;
|
||||
return source.hasPermission( toLevel() );
|
||||
}
|
||||
|
||||
private static boolean isOwner( CommandSourceStack source )
|
||||
{
|
||||
MinecraftServer server = source.getServer();
|
||||
Entity sender = source.getEntity();
|
||||
return server.isDedicatedServer()
|
||||
? source.getEntity() == null && source.hasPermission( 4 ) && source.getTextName().equals( "Server" )
|
||||
: sender instanceof Player && ((Player) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.*;
|
||||
|
||||
/**
|
||||
* @cc.module commands
|
||||
* @cc.since 1.7
|
||||
*/
|
||||
public class CommandAPI implements ILuaAPI
|
||||
{
|
||||
@@ -90,6 +91,8 @@ public class CommandAPI implements ILuaAPI
|
||||
* @cc.treturn { string... } The output of this command, as a list of lines.
|
||||
* @cc.treturn number|nil The number of "affected" objects, or `nil` if the command failed. The definition of this
|
||||
* varies from command to command.
|
||||
* @cc.changed 1.71 Added return value with command output.
|
||||
* @cc.changed 1.85.0 Added return value with the number of affected objects.
|
||||
* @cc.usage Set the block above the command computer to stone.
|
||||
* <pre>{@code
|
||||
* commands.exec("setblock ~ ~1 ~ minecraft:stone")
|
||||
@@ -118,7 +121,7 @@ public class CommandAPI implements ILuaAPI
|
||||
* @throws LuaException (hidden) If the task cannot be created.
|
||||
* @cc.usage Asynchronously sets the block above the computer to stone.
|
||||
* <pre>{@code
|
||||
* commands.execAsync("~ ~1 ~ minecraft:stone")
|
||||
* commands.execAsync("setblock ~ ~1 ~ minecraft:stone")
|
||||
* }</pre>
|
||||
* @cc.see parallel One may also use the parallel API to run multiple commands at once.
|
||||
*/
|
||||
@@ -193,6 +196,7 @@ public class CommandAPI implements ILuaAPI
|
||||
* @return A list of information about each block.
|
||||
* @throws LuaException If the coordinates are not within the world.
|
||||
* @throws LuaException If trying to get information about more than 4096 blocks.
|
||||
* @cc.since 1.76
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public final List<Map<?, ?>> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException
|
||||
@@ -245,6 +249,7 @@ public class CommandAPI implements ILuaAPI
|
||||
* @param z The z position of the block to query.
|
||||
* @return The given block's information.
|
||||
* @throws LuaException If the coordinates are not within the world, or are not currently loaded.
|
||||
* @cc.changed 1.76 Added block state info to return value
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public final Map<?, ?> getBlockInfo( int x, int y, int z ) throws LuaException
|
||||
|
||||
@@ -8,10 +8,11 @@ package dan200.computercraft.shared.computer.blocks;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerComputer;
|
||||
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
|
||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -51,7 +52,7 @@ public class TileComputer extends TileComputerBase
|
||||
return computer;
|
||||
}
|
||||
|
||||
public boolean isUsableByPlayer( Player player )
|
||||
protected boolean isUsableByPlayer( Player player )
|
||||
{
|
||||
return isUsable( player, false );
|
||||
}
|
||||
@@ -86,7 +87,7 @@ public class TileComputer extends TileComputerBase
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player player )
|
||||
{
|
||||
return new ContainerComputer( id, this );
|
||||
return new ComputerMenuWithoutInventory( Registry.ModContainers.COMPUTER.get(), id, inventory, this::isUsableByPlayer, createServerComputer(), getFamily() );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.computer.core;
|
||||
|
||||
import dan200.computercraft.shared.computer.upload.FileSlice;
|
||||
import dan200.computercraft.shared.computer.upload.FileUpload;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
@@ -12,6 +13,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* An instance of {@link AbstractContainerMenu} which provides a computer. You should implement this
|
||||
@@ -38,12 +40,28 @@ public interface IContainerComputer
|
||||
InputState getInput();
|
||||
|
||||
/**
|
||||
* Attempt to upload a series of files to this computer.
|
||||
* Start a file upload into this container.
|
||||
*
|
||||
* @param uploader The player uploading files.
|
||||
* @param uploadId The unique ID of this upload.
|
||||
* @param files The files to upload.
|
||||
*/
|
||||
void upload( @Nonnull ServerPlayer uploader, @Nonnull List<FileUpload> files );
|
||||
void startUpload( @Nonnull UUID uploadId, @Nonnull List<FileUpload> files );
|
||||
|
||||
/**
|
||||
* Append more data to partially uploaded files.
|
||||
*
|
||||
* @param uploadId The unique ID of this upload.
|
||||
* @param slices Additional parts of file data to upload.
|
||||
*/
|
||||
void continueUpload( @Nonnull UUID uploadId, @Nonnull List<FileSlice> slices );
|
||||
|
||||
/**
|
||||
* Finish off an upload. This either writes the uploaded files or
|
||||
*
|
||||
* @param uploader The player uploading files.
|
||||
* @param uploadId The unique ID of this upload.
|
||||
*/
|
||||
void finishUpload( @Nonnull ServerPlayer uploader, @Nonnull UUID uploadId );
|
||||
|
||||
/**
|
||||
* Continue an upload.
|
||||
@@ -51,5 +69,5 @@ public interface IContainerComputer
|
||||
* @param uploader The player uploading files.
|
||||
* @param overwrite Whether the files should be overwritten or not.
|
||||
*/
|
||||
void continueUpload( @Nonnull ServerPlayer uploader, boolean overwrite );
|
||||
void confirmUpload( @Nonnull ServerPlayer uploader, boolean overwrite );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.computer.inventory;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.IComputer;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.util.InvisibleSlot;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A computer menu which does not have any visible inventory.
|
||||
*
|
||||
* This adds invisible versions of the player's hotbars slots, to ensure they're synced to the client when changed.
|
||||
*/
|
||||
public class ComputerMenuWithoutInventory extends ContainerComputerBase
|
||||
{
|
||||
public ComputerMenuWithoutInventory( MenuType<? extends ContainerComputerBase> type, int id, Inventory player, Predicate<Player> canUse, IComputer computer, ComputerFamily family )
|
||||
{
|
||||
super( type, id, canUse, computer, family );
|
||||
addSlots( player );
|
||||
}
|
||||
|
||||
public ComputerMenuWithoutInventory( MenuType<? extends ContainerComputerBase> type, int id, Inventory player, ComputerContainerData data )
|
||||
{
|
||||
super( type, id, player, data );
|
||||
addSlots( player );
|
||||
}
|
||||
|
||||
private void addSlots( Inventory player )
|
||||
{
|
||||
for( int i = 0; i < 9; i++ ) addSlot( new InvisibleSlot( player, i ) );
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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.computer.inventory;
|
||||
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
|
||||
public class ContainerComputer extends ContainerComputerBase
|
||||
{
|
||||
public ContainerComputer( int id, TileComputer tile )
|
||||
{
|
||||
super( Registry.ModContainers.COMPUTER.get(), id, tile::isUsableByPlayer, tile.createServerComputer(), tile.getFamily() );
|
||||
}
|
||||
|
||||
public ContainerComputer( int id, Inventory player, ComputerContainerData data )
|
||||
{
|
||||
super( Registry.ModContainers.COMPUTER.get(), id, player, data );
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import dan200.computercraft.core.filesystem.FileSystem;
|
||||
import dan200.computercraft.core.filesystem.FileSystemException;
|
||||
import dan200.computercraft.core.filesystem.FileSystemWrapper;
|
||||
import dan200.computercraft.shared.computer.core.*;
|
||||
import dan200.computercraft.shared.computer.upload.FileSlice;
|
||||
import dan200.computercraft.shared.computer.upload.FileUpload;
|
||||
import dan200.computercraft.shared.computer.upload.UploadResult;
|
||||
import dan200.computercraft.shared.network.NetworkHandler;
|
||||
@@ -29,10 +30,11 @@ import java.nio.channels.WritableByteChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ContainerComputerBase extends AbstractContainerMenu implements IContainerComputer
|
||||
public abstract class ContainerComputerBase extends AbstractContainerMenu implements IContainerComputer
|
||||
{
|
||||
private static final String LIST_PREFIX = "\n \u2022 ";
|
||||
|
||||
@@ -40,9 +42,11 @@ public class ContainerComputerBase extends AbstractContainerMenu implements ICon
|
||||
private final IComputer computer;
|
||||
private final ComputerFamily family;
|
||||
private final InputState input = new InputState( this );
|
||||
|
||||
private UUID toUploadId;
|
||||
private List<FileUpload> toUpload;
|
||||
|
||||
protected ContainerComputerBase( MenuType<? extends ContainerComputerBase> type, int id, Predicate<Player> canUse, IComputer computer, ComputerFamily family )
|
||||
public ContainerComputerBase( MenuType<? extends ContainerComputerBase> type, int id, Predicate<Player> canUse, IComputer computer, ComputerFamily family )
|
||||
{
|
||||
super( type, id );
|
||||
this.canUse = canUse;
|
||||
@@ -50,7 +54,7 @@ public class ContainerComputerBase extends AbstractContainerMenu implements ICon
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
protected ContainerComputerBase( MenuType<? extends ContainerComputerBase> type, int id, Inventory player, ComputerContainerData data )
|
||||
public ContainerComputerBase( MenuType<? extends ContainerComputerBase> type, int id, Inventory player, ComputerContainerData data )
|
||||
{
|
||||
this( type, id, x -> true, getComputer( player, data ), data.getFamily() );
|
||||
}
|
||||
@@ -92,25 +96,52 @@ public class ContainerComputerBase extends AbstractContainerMenu implements ICon
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload( @Nonnull ServerPlayer uploader, @Nonnull List<FileUpload> files )
|
||||
public void startUpload( @Nonnull UUID uuid, @Nonnull List<FileUpload> files )
|
||||
{
|
||||
UploadResultMessage message = upload( files, false );
|
||||
toUploadId = uuid;
|
||||
toUpload = files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continueUpload( @Nonnull UUID uploadId, @Nonnull List<FileSlice> slices )
|
||||
{
|
||||
if( toUploadId == null || toUpload == null || !toUploadId.equals( uploadId ) )
|
||||
{
|
||||
ComputerCraft.log.warn( "Invalid continueUpload call, skipping." );
|
||||
return;
|
||||
}
|
||||
|
||||
for( FileSlice slice : slices ) slice.apply( toUpload );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishUpload( @Nonnull ServerPlayer uploader, @Nonnull UUID uploadId )
|
||||
{
|
||||
if( toUploadId == null || toUpload == null || toUpload.isEmpty() || !toUploadId.equals( uploadId ) )
|
||||
{
|
||||
ComputerCraft.log.warn( "Invalid finishUpload call, skipping." );
|
||||
return;
|
||||
}
|
||||
|
||||
UploadResultMessage message = finishUpload( false );
|
||||
NetworkHandler.sendToPlayer( uploader, message );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void continueUpload( @Nonnull ServerPlayer uploader, boolean overwrite )
|
||||
public void confirmUpload( @Nonnull ServerPlayer uploader, boolean overwrite )
|
||||
{
|
||||
List<FileUpload> files = this.toUpload;
|
||||
toUpload = null;
|
||||
if( files == null || files.isEmpty() || !overwrite ) return;
|
||||
if( toUploadId == null || toUpload == null || toUpload.isEmpty() )
|
||||
{
|
||||
ComputerCraft.log.warn( "Invalid finishUpload call, skipping." );
|
||||
return;
|
||||
}
|
||||
|
||||
UploadResultMessage message = upload( files, true );
|
||||
UploadResultMessage message = finishUpload( true );
|
||||
NetworkHandler.sendToPlayer( uploader, message );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private UploadResultMessage upload( @Nonnull List<FileUpload> files, boolean forceOverwrite )
|
||||
private UploadResultMessage finishUpload( boolean forceOverwrite )
|
||||
{
|
||||
ServerComputer computer = (ServerComputer) getComputer();
|
||||
if( computer == null ) return UploadResultMessage.COMPUTER_OFF;
|
||||
@@ -118,9 +149,20 @@ public class ContainerComputerBase extends AbstractContainerMenu implements ICon
|
||||
FileSystem fs = computer.getComputer().getEnvironment().getFileSystem();
|
||||
if( fs == null ) return UploadResultMessage.COMPUTER_OFF;
|
||||
|
||||
for( FileUpload upload : toUpload )
|
||||
{
|
||||
if( !upload.checksumMatches() )
|
||||
{
|
||||
ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() );
|
||||
return new UploadResultMessage( UploadResult.ERROR, new TranslatableComponent( "gui.computercraft.upload.failed.corrupted" ) );
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
List<String> overwrite = new ArrayList<>();
|
||||
List<FileUpload> files = toUpload;
|
||||
toUpload = null;
|
||||
for( FileUpload upload : files )
|
||||
{
|
||||
if( !fs.exists( upload.getName() ) ) continue;
|
||||
@@ -139,7 +181,6 @@ public class ContainerComputerBase extends AbstractContainerMenu implements ICon
|
||||
{
|
||||
StringJoiner joiner = new StringJoiner( LIST_PREFIX, LIST_PREFIX, "" );
|
||||
for( String value : overwrite ) joiner.add( value );
|
||||
|
||||
toUpload = files;
|
||||
return new UploadResultMessage(
|
||||
UploadResult.CONFIRM_OVERWRITE,
|
||||
@@ -167,7 +208,7 @@ public class ContainerComputerBase extends AbstractContainerMenu implements ICon
|
||||
catch( FileSystemException | IOException e )
|
||||
{
|
||||
ComputerCraft.log.error( "Error uploading files", e );
|
||||
return new UploadResultMessage( UploadResult.ERROR, new TranslatableComponent( "computercraft.gui.upload.failed.generic", e.getMessage() ) );
|
||||
return new UploadResultMessage( UploadResult.ERROR, new TranslatableComponent( "gui.computercraft.upload.failed.generic", e.getMessage() ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,14 @@ import net.minecraft.world.entity.player.Player;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class ContainerViewComputer extends ContainerComputerBase
|
||||
public class ContainerViewComputer extends ComputerMenuWithoutInventory
|
||||
{
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public ContainerViewComputer( int id, ServerComputer computer )
|
||||
public ContainerViewComputer( int id, Inventory player, ServerComputer computer )
|
||||
{
|
||||
super( Registry.ModContainers.VIEW_COMPUTER.get(), id, player -> canInteractWith( computer, player ), computer, computer.getFamily() );
|
||||
super( Registry.ModContainers.VIEW_COMPUTER.get(), id, player, p -> canInteractWith( computer, p ), computer, computer.getFamily() );
|
||||
width = height = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.computer.upload;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
public class FileSlice
|
||||
{
|
||||
private final int fileId;
|
||||
private final int offset;
|
||||
private final ByteBuffer bytes;
|
||||
|
||||
public FileSlice( int fileId, int offset, ByteBuffer bytes )
|
||||
{
|
||||
this.fileId = fileId;
|
||||
this.offset = offset;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public int getFileId()
|
||||
{
|
||||
return fileId;
|
||||
}
|
||||
|
||||
public int getOffset()
|
||||
{
|
||||
return offset;
|
||||
}
|
||||
|
||||
public ByteBuffer getBytes()
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void apply( List<FileUpload> files )
|
||||
{
|
||||
if( fileId < 0 || fileId >= files.size() )
|
||||
{
|
||||
ComputerCraft.log.warn( "File ID is out-of-bounds (0 <= {} < {})", fileId, files.size() );
|
||||
return;
|
||||
}
|
||||
|
||||
ByteBuffer file = files.get( fileId ).getBytes();
|
||||
if( offset < 0 || offset + bytes.remaining() > file.capacity() )
|
||||
{
|
||||
ComputerCraft.log.warn( "File offset is out-of-bounds (0 <= {} <= {})", offset, file.capacity() - offset );
|
||||
return;
|
||||
}
|
||||
|
||||
bytes.rewind();
|
||||
file.position( offset );
|
||||
file.put( bytes );
|
||||
file.rewind();
|
||||
|
||||
if( bytes.remaining() != 0 ) throw new IllegalStateException( "Should have read the whole buffer" );
|
||||
}
|
||||
}
|
||||
@@ -5,26 +5,76 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.computer.upload;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FileUpload
|
||||
{
|
||||
private final String name;
|
||||
private final ByteBuffer bytes;
|
||||
public static final int CHECKSUM_LENGTH = 32;
|
||||
|
||||
public FileUpload( String name, ByteBuffer bytes )
|
||||
private final String name;
|
||||
private final int length;
|
||||
private final ByteBuffer bytes;
|
||||
private final byte[] checksum;
|
||||
|
||||
public FileUpload( String name, ByteBuffer bytes, byte[] checksum )
|
||||
{
|
||||
this.name = name;
|
||||
this.bytes = bytes;
|
||||
length = bytes.remaining();
|
||||
this.checksum = checksum;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public ByteBuffer getBytes()
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public int getLength()
|
||||
{
|
||||
return length;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public byte[] getChecksum()
|
||||
{
|
||||
return checksum;
|
||||
}
|
||||
|
||||
public boolean checksumMatches()
|
||||
{
|
||||
// This is meant to be a checksum. Doesn't need to be cryptographically secure, hence non constant time.
|
||||
byte[] digest = getDigest( bytes );
|
||||
return digest != null && Arrays.equals( checksum, digest );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static byte[] getDigest( ByteBuffer bytes )
|
||||
{
|
||||
try
|
||||
{
|
||||
bytes.rewind();
|
||||
MessageDigest digest = MessageDigest.getInstance( "SHA-256" );
|
||||
digest.update( bytes );
|
||||
return digest.digest();
|
||||
}
|
||||
catch( NoSuchAlgorithmException e )
|
||||
{
|
||||
ComputerCraft.log.warn( "Failed to compute digest ({})", e.toString() );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraftforge.common.extensions.IForgeContainerType;
|
||||
import net.minecraftforge.fmllegacy.network.IContainerFactory;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkHooks;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -37,8 +38,36 @@ public interface ContainerData
|
||||
return IForgeContainerType.create( ( id, player, data ) -> factory.create( id, player, reader.apply( data ) ) );
|
||||
}
|
||||
|
||||
static <C extends AbstractContainerMenu, T extends ContainerData> MenuType<C> toType( Function<FriendlyByteBuf, T> reader, FixedFactory<C, T> factory )
|
||||
{
|
||||
return new FixedPointContainerFactory<>( reader, factory ).type;
|
||||
}
|
||||
|
||||
interface Factory<C extends AbstractContainerMenu, T extends ContainerData>
|
||||
{
|
||||
C create( int id, @Nonnull Inventory inventory, T data );
|
||||
}
|
||||
|
||||
interface FixedFactory<C extends AbstractContainerMenu, T extends ContainerData>
|
||||
{
|
||||
C create( MenuType<C> type, int id, @Nonnull Inventory inventory, T data );
|
||||
}
|
||||
|
||||
class FixedPointContainerFactory<C extends AbstractContainerMenu, T extends ContainerData> implements IContainerFactory<C>
|
||||
{
|
||||
private final IContainerFactory<C> impl;
|
||||
private final MenuType<C> type;
|
||||
|
||||
private FixedPointContainerFactory( Function<FriendlyByteBuf, T> reader, FixedFactory<C, T> factory )
|
||||
{
|
||||
MenuType<C> type = this.type = IForgeContainerType.create( this );
|
||||
impl = ( id, player, data ) -> factory.create( type, id, player, reader.apply( data ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public C create( int windowId, Inventory inv, FriendlyByteBuf data )
|
||||
{
|
||||
return impl.create( windowId, inv, data );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,6 @@ public class ContinueUploadMessage extends ComputerServerMessage
|
||||
protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container )
|
||||
{
|
||||
ServerPlayer player = context.getSender();
|
||||
if( player != null ) container.continueUpload( player, overwrite );
|
||||
if( player != null ) container.confirmUpload( player, overwrite );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
*/
|
||||
package dan200.computercraft.shared.network.server;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.IContainerComputer;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.upload.FileSlice;
|
||||
import dan200.computercraft.shared.computer.upload.FileUpload;
|
||||
import dan200.computercraft.shared.network.NetworkHandler;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.fmllegacy.network.NetworkEvent;
|
||||
@@ -16,34 +20,81 @@ import javax.annotation.Nonnull;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UploadFileMessage extends ComputerServerMessage
|
||||
{
|
||||
public static final int MAX_SIZE = 30 * 1024; // Max packet size is 32767. TODO: Bump this in the future
|
||||
private final List<FileUpload> files;
|
||||
public static final int MAX_SIZE = 512 * 1024;
|
||||
static final int MAX_PACKET_SIZE = 30 * 1024; // Max packet size is 32767.
|
||||
|
||||
public UploadFileMessage( int instanceId, List<FileUpload> files )
|
||||
public static final int MAX_FILES = 32;
|
||||
public static final int MAX_FILE_NAME = 128;
|
||||
|
||||
private static final int FLAG_FIRST = 1;
|
||||
private static final int FLAG_LAST = 2;
|
||||
|
||||
private final UUID uuid;
|
||||
private final int flag;
|
||||
private final List<FileUpload> files;
|
||||
private final List<FileSlice> slices;
|
||||
|
||||
UploadFileMessage( int instanceId, UUID uuid, int flag, List<FileUpload> files, List<FileSlice> slices )
|
||||
{
|
||||
super( instanceId );
|
||||
this.uuid = uuid;
|
||||
this.flag = flag;
|
||||
this.files = files;
|
||||
this.slices = slices;
|
||||
}
|
||||
|
||||
public UploadFileMessage( @Nonnull FriendlyByteBuf buf )
|
||||
{
|
||||
super( buf );
|
||||
int nFiles = buf.readVarInt();
|
||||
List<FileUpload> files = this.files = new ArrayList<>( nFiles );
|
||||
for( int i = 0; i < nFiles; i++ )
|
||||
uuid = buf.readUUID();
|
||||
int flag = this.flag = buf.readByte();
|
||||
|
||||
int totalSize = 0;
|
||||
if( (flag & FLAG_FIRST) != 0 )
|
||||
{
|
||||
String name = buf.readUtf( 32767 );
|
||||
int size = buf.readVarInt();
|
||||
if( size > MAX_SIZE ) break;
|
||||
int nFiles = buf.readVarInt();
|
||||
if( nFiles >= MAX_FILES ) throw new DecoderException( "Too many files" );
|
||||
|
||||
List<FileUpload> files = this.files = new ArrayList<>( nFiles );
|
||||
for( int i = 0; i < nFiles; i++ )
|
||||
{
|
||||
String name = buf.readUtf( MAX_FILE_NAME );
|
||||
int size = buf.readVarInt();
|
||||
if( size > MAX_SIZE || (totalSize += size) >= MAX_SIZE )
|
||||
{
|
||||
throw new DecoderException( "Files are too large" );
|
||||
}
|
||||
|
||||
byte[] digest = new byte[FileUpload.CHECKSUM_LENGTH];
|
||||
buf.readBytes( digest );
|
||||
|
||||
files.add( new FileUpload( name, ByteBuffer.allocateDirect( size ), digest ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
files = null;
|
||||
}
|
||||
|
||||
int nSlices = buf.readVarInt();
|
||||
List<FileSlice> slices = this.slices = new ArrayList<>( nSlices );
|
||||
for( int i = 0; i < nSlices; i++ )
|
||||
{
|
||||
int fileId = buf.readUnsignedByte();
|
||||
int offset = buf.readVarInt();
|
||||
|
||||
int size = buf.readUnsignedShort();
|
||||
if( size > MAX_PACKET_SIZE ) throw new DecoderException( "File is too large" );
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect( size );
|
||||
buf.readBytes( buffer );
|
||||
buffer.flip();
|
||||
|
||||
files.add( new FileUpload( name, buffer ) );
|
||||
slices.add( new FileSlice( fileId, offset, buffer ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,19 +102,85 @@ public class UploadFileMessage extends ComputerServerMessage
|
||||
public void toBytes( @Nonnull FriendlyByteBuf buf )
|
||||
{
|
||||
super.toBytes( buf );
|
||||
buf.writeVarInt( files.size() );
|
||||
for( FileUpload file : files )
|
||||
buf.writeUUID( uuid );
|
||||
buf.writeByte( flag );
|
||||
|
||||
if( (flag & FLAG_FIRST) != 0 )
|
||||
{
|
||||
buf.writeUtf( file.getName() );
|
||||
buf.writeVarInt( file.getBytes().remaining() );
|
||||
buf.writeBytes( file.getBytes() );
|
||||
buf.writeVarInt( files.size() );
|
||||
for( FileUpload file : files )
|
||||
{
|
||||
buf.writeUtf( file.getName(), MAX_FILE_NAME );
|
||||
buf.writeVarInt( file.getLength() );
|
||||
buf.writeBytes( file.getChecksum() );
|
||||
}
|
||||
}
|
||||
|
||||
buf.writeVarInt( slices.size() );
|
||||
for( FileSlice slice : slices )
|
||||
{
|
||||
buf.writeByte( slice.getFileId() );
|
||||
buf.writeVarInt( slice.getOffset() );
|
||||
|
||||
slice.getBytes().rewind();
|
||||
buf.writeShort( slice.getBytes().remaining() );
|
||||
buf.writeBytes( slice.getBytes() );
|
||||
}
|
||||
}
|
||||
|
||||
public static void send( int instanceId, List<FileUpload> files )
|
||||
{
|
||||
UUID uuid = UUID.randomUUID();
|
||||
|
||||
int remaining = MAX_PACKET_SIZE;
|
||||
for( FileUpload file : files ) remaining -= file.getName().length() * 4 + FileUpload.CHECKSUM_LENGTH;
|
||||
|
||||
boolean first = true;
|
||||
List<FileSlice> slices = new ArrayList<>( files.size() );
|
||||
for( int fileId = 0; fileId < files.size(); fileId++ )
|
||||
{
|
||||
FileUpload file = files.get( fileId );
|
||||
ByteBuffer contents = file.getBytes();
|
||||
int capacity = contents.limit();
|
||||
|
||||
int currentOffset = 0;
|
||||
while( currentOffset < capacity )
|
||||
{
|
||||
if( remaining <= 0 )
|
||||
{
|
||||
NetworkHandler.sendToServer( first
|
||||
? new UploadFileMessage( instanceId, uuid, FLAG_FIRST, files, new ArrayList<>( slices ) )
|
||||
: new UploadFileMessage( instanceId, uuid, 0, null, new ArrayList<>( slices ) ) );
|
||||
slices.clear();
|
||||
remaining = MAX_PACKET_SIZE;
|
||||
first = false;
|
||||
}
|
||||
|
||||
int canWrite = Math.min( remaining, capacity - currentOffset );
|
||||
|
||||
ComputerCraft.log.info( "Adding slice from {} to {}", currentOffset, currentOffset + canWrite - 1 );
|
||||
contents.position( currentOffset ).limit( currentOffset + canWrite );
|
||||
slices.add( new FileSlice( fileId, currentOffset, contents.slice() ) );
|
||||
currentOffset += canWrite;
|
||||
}
|
||||
|
||||
contents.position( 0 ).limit( capacity );
|
||||
}
|
||||
|
||||
NetworkHandler.sendToServer( first
|
||||
? new UploadFileMessage( instanceId, uuid, FLAG_FIRST | FLAG_LAST, files, new ArrayList<>( slices ) )
|
||||
: new UploadFileMessage( instanceId, uuid, FLAG_LAST, null, new ArrayList<>( slices ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container )
|
||||
{
|
||||
ServerPlayer player = context.getSender();
|
||||
if( player != null ) container.upload( player, files );
|
||||
if( player != null )
|
||||
{
|
||||
if( (flag & FLAG_FIRST) != 0 ) container.startUpload( uuid, files );
|
||||
container.continueUpload( uuid, slices );
|
||||
if( (flag & FLAG_LAST) != 0 ) container.finishUpload( player, uuid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +186,7 @@ public class DiskDrivePeripheral implements IPeripheral
|
||||
*
|
||||
* @return The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted.
|
||||
* @cc.treturn number The The ID of the disk in the drive, or {@code nil} if no disk with an ID is inserted.
|
||||
* @cc.since 1.4
|
||||
*/
|
||||
@LuaFunction
|
||||
public final Object[] getDiskID()
|
||||
|
||||
@@ -187,6 +187,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
*
|
||||
* @return The current computer's name.
|
||||
* @cc.treturn string|nil The current computer's name on the wired network.
|
||||
* @cc.since 1.80pr1.7
|
||||
*/
|
||||
@LuaFunction
|
||||
public final Object[] getNameLocal()
|
||||
|
||||
@@ -71,6 +71,7 @@ public class MonitorPeripheral extends TermMethods implements IPeripheral
|
||||
*
|
||||
* @return The monitor's current scale.
|
||||
* @throws LuaException If the monitor cannot be found.
|
||||
* @cc.since 1.81.0
|
||||
*/
|
||||
@LuaFunction
|
||||
public final double getTextScale() throws LuaException
|
||||
|
||||
@@ -35,6 +35,7 @@ import static dan200.computercraft.api.lua.LuaValues.checkFinite;
|
||||
* Speakers allow playing notes and other sounds.
|
||||
*
|
||||
* @cc.module speaker
|
||||
* @cc.since 1.80pr1
|
||||
*/
|
||||
public abstract class SpeakerPeripheral implements IPeripheral
|
||||
{
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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.pocket.inventory;
|
||||
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.inventory.ContainerComputerBase;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public final class ContainerPocketComputer extends ContainerComputerBase
|
||||
{
|
||||
private ContainerPocketComputer( int id, ServerComputer computer, ItemPocketComputer item, InteractionHand hand )
|
||||
{
|
||||
super( Registry.ModContainers.POCKET_COMPUTER.get(), id, p -> {
|
||||
ItemStack stack = p.getItemInHand( hand );
|
||||
return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer;
|
||||
}, computer, item.getFamily() );
|
||||
}
|
||||
|
||||
public ContainerPocketComputer( int id, Inventory player, ComputerContainerData data )
|
||||
{
|
||||
super( Registry.ModContainers.POCKET_COMPUTER.get(), id, player, data );
|
||||
}
|
||||
|
||||
public static class Factory implements MenuProvider
|
||||
{
|
||||
private final ServerComputer computer;
|
||||
private final Component name;
|
||||
private final ItemPocketComputer item;
|
||||
private final InteractionHand hand;
|
||||
|
||||
public Factory( ServerComputer computer, ItemStack stack, ItemPocketComputer item, InteractionHand hand )
|
||||
{
|
||||
this.computer = computer;
|
||||
name = stack.getHoverName();
|
||||
this.item = item;
|
||||
this.hand = hand;
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Component getDisplayName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player entity )
|
||||
{
|
||||
return new ContainerPocketComputer( id, computer, item, hand );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.pocket.inventory;
|
||||
|
||||
import dan200.computercraft.shared.Registry;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PocketComputerMenuProvider implements MenuProvider
|
||||
{
|
||||
private final ServerComputer computer;
|
||||
private final Component name;
|
||||
private final ItemPocketComputer item;
|
||||
private final InteractionHand hand;
|
||||
private final boolean isTypingOnly;
|
||||
|
||||
public PocketComputerMenuProvider( ServerComputer computer, ItemStack stack, ItemPocketComputer item, InteractionHand hand, boolean isTypingOnly )
|
||||
{
|
||||
this.computer = computer;
|
||||
name = stack.getHoverName();
|
||||
this.item = item;
|
||||
this.hand = hand;
|
||||
this.isTypingOnly = isTypingOnly;
|
||||
}
|
||||
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Component getDisplayName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu( int id, @Nonnull Inventory inventory, @Nonnull Player entity )
|
||||
{
|
||||
return new ComputerMenuWithoutInventory(
|
||||
isTypingOnly ? Registry.ModContainers.POCKET_COMPUTER_NO_TERM.get() : Registry.ModContainers.POCKET_COMPUTER.get(), id, inventory,
|
||||
p -> {
|
||||
ItemStack stack = p.getItemInHand( hand );
|
||||
return stack.getItem() == item && ItemPocketComputer.getServerComputer( stack ) == computer;
|
||||
},
|
||||
computer, item.getFamily()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.pocket.apis.PocketAPI;
|
||||
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||
import dan200.computercraft.shared.pocket.inventory.ContainerPocketComputer;
|
||||
import dan200.computercraft.shared.pocket.inventory.PocketComputerMenuProvider;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -154,7 +154,8 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
|
||||
|
||||
if( !stop && computer != null )
|
||||
{
|
||||
new ComputerContainerData( computer ).open( player, new ContainerPocketComputer.Factory( computer, stack, this, hand ) );
|
||||
boolean isTypingOnly = hand == InteractionHand.OFF_HAND;
|
||||
new ComputerContainerData( computer ).open( player, new PocketComputerMenuProvider( computer, stack, this, hand, isTypingOnly ) );
|
||||
}
|
||||
}
|
||||
return new InteractionResultHolder<>( InteractionResult.SUCCESS, stack );
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.util.Optional;
|
||||
* The turtle API allows you to control your turtle.
|
||||
*
|
||||
* @cc.module turtle
|
||||
* @cc.since 1.3
|
||||
*/
|
||||
public class TurtleAPI implements ILuaAPI
|
||||
{
|
||||
@@ -139,6 +140,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether a block was broken.
|
||||
* @cc.treturn string|nil The reason no block was broken.
|
||||
* @cc.changed 1.6 Added optional side argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult dig( Optional<TurtleSide> side )
|
||||
@@ -154,6 +156,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether a block was broken.
|
||||
* @cc.treturn string|nil The reason no block was broken.
|
||||
* @cc.changed 1.6 Added optional side argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult digUp( Optional<TurtleSide> side )
|
||||
@@ -169,6 +172,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether a block was broken.
|
||||
* @cc.treturn string|nil The reason no block was broken.
|
||||
* @cc.changed 1.6 Added optional side argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult digDown( Optional<TurtleSide> side )
|
||||
@@ -189,6 +193,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
||||
* @cc.treturn boolean Whether the block could be placed.
|
||||
* @cc.treturn string|nil The reason the block was not placed.
|
||||
* @cc.since 1.4
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult place( IArguments args )
|
||||
@@ -204,6 +209,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
||||
* @cc.treturn boolean Whether the block could be placed.
|
||||
* @cc.treturn string|nil The reason the block was not placed.
|
||||
* @cc.since 1.4
|
||||
* @see #place For more information about placing items.
|
||||
*/
|
||||
@LuaFunction
|
||||
@@ -220,6 +226,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
||||
* @cc.treturn boolean Whether the block could be placed.
|
||||
* @cc.treturn string|nil The reason the block was not placed.
|
||||
* @cc.since 1.4
|
||||
* @see #place For more information about placing items.
|
||||
*/
|
||||
@LuaFunction
|
||||
@@ -237,6 +244,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @throws LuaException If dropping an invalid number of items.
|
||||
* @cc.treturn boolean Whether items were dropped.
|
||||
* @cc.treturn string|nil The reason the no items were dropped.
|
||||
* @cc.since 1.31
|
||||
* @see #select
|
||||
*/
|
||||
@LuaFunction
|
||||
@@ -254,6 +262,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @throws LuaException If dropping an invalid number of items.
|
||||
* @cc.treturn boolean Whether items were dropped.
|
||||
* @cc.treturn string|nil The reason the no items were dropped.
|
||||
* @cc.since 1.4
|
||||
* @see #select
|
||||
*/
|
||||
@LuaFunction
|
||||
@@ -271,6 +280,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @throws LuaException If dropping an invalid number of items.
|
||||
* @cc.treturn boolean Whether items were dropped.
|
||||
* @cc.treturn string|nil The reason the no items were dropped.
|
||||
* @cc.since 1.4
|
||||
* @see #select
|
||||
*/
|
||||
@LuaFunction
|
||||
@@ -374,6 +384,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
*
|
||||
* @return If the block and item are equal.
|
||||
* @cc.treturn boolean If the block and item are equal.
|
||||
* @cc.since 1.31
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult compare()
|
||||
@@ -386,6 +397,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
*
|
||||
* @return If the block and item are equal.
|
||||
* @cc.treturn boolean If the block and item are equal.
|
||||
* @cc.since 1.31
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult compareUp()
|
||||
@@ -398,6 +410,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
*
|
||||
* @return If the block and item are equal.
|
||||
* @cc.treturn boolean If the block and item are equal.
|
||||
* @cc.since 1.31
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult compareDown()
|
||||
@@ -412,6 +425,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether an entity was attacked.
|
||||
* @cc.treturn string|nil The reason nothing was attacked.
|
||||
* @cc.since 1.4
|
||||
* @cc.changed 1.6 Added optional side argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult attack( Optional<TurtleSide> side )
|
||||
@@ -426,6 +441,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether an entity was attacked.
|
||||
* @cc.treturn string|nil The reason nothing was attacked.
|
||||
* @cc.since 1.4
|
||||
* @cc.changed 1.6 Added optional side argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult attackUp( Optional<TurtleSide> side )
|
||||
@@ -440,6 +457,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether an entity was attacked.
|
||||
* @cc.treturn string|nil The reason nothing was attacked.
|
||||
* @cc.since 1.4
|
||||
* @cc.changed 1.6 Added optional side argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult attackDown( Optional<TurtleSide> side )
|
||||
@@ -457,6 +476,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @throws LuaException If given an invalid number of items.
|
||||
* @cc.treturn boolean Whether items were picked up.
|
||||
* @cc.treturn string|nil The reason the no items were picked up.
|
||||
* @cc.since 1.4
|
||||
* @cc.changed 1.6 Added an optional limit argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult suck( Optional<Integer> count ) throws LuaException
|
||||
@@ -472,6 +493,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @throws LuaException If given an invalid number of items.
|
||||
* @cc.treturn boolean Whether items were picked up.
|
||||
* @cc.treturn string|nil The reason the no items were picked up.
|
||||
* @cc.since 1.4
|
||||
* @cc.changed 1.6 Added an optional limit argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult suckUp( Optional<Integer> count ) throws LuaException
|
||||
@@ -487,6 +510,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @throws LuaException If given an invalid number of items.
|
||||
* @cc.treturn boolean Whether items were picked up.
|
||||
* @cc.treturn string|nil The reason the no items were picked up.
|
||||
* @cc.since 1.4
|
||||
* @cc.changed 1.6 Added an optional limit argument.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult suckDown( Optional<Integer> count ) throws LuaException
|
||||
@@ -500,6 +525,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The fuel level, or "unlimited".
|
||||
* @cc.treturn [1] number The current amount of fuel a turtle this turtle has.
|
||||
* @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving.
|
||||
* @cc.since 1.4
|
||||
* @see #getFuelLimit()
|
||||
* @see #refuel(Optional)
|
||||
*/
|
||||
@@ -542,6 +568,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* local is_fuel, reason = turtle.refuel(0)
|
||||
* if not is_fuel then printError(reason) end
|
||||
* }</pre>
|
||||
* @cc.since 1.4
|
||||
* @see #getFuelLevel()
|
||||
* @see #getFuelLimit()
|
||||
*/
|
||||
@@ -560,6 +587,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return If the items are the same.
|
||||
* @throws LuaException If the slot is out of range.
|
||||
* @cc.treturn boolean If the two items are equal.
|
||||
* @cc.since 1.4
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult compareTo( int slot ) throws LuaException
|
||||
@@ -576,6 +604,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @throws LuaException If the slot is out of range.
|
||||
* @throws LuaException If the number of items is out of range.
|
||||
* @cc.treturn boolean If some items were successfully moved.
|
||||
* @cc.since 1.45
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult transferTo( int slotArg, Optional<Integer> countArg ) throws LuaException
|
||||
@@ -589,6 +618,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* Get the currently selected slot.
|
||||
*
|
||||
* @return The current slot.
|
||||
* @cc.since 1.6
|
||||
* @see #select
|
||||
*/
|
||||
@LuaFunction
|
||||
@@ -605,6 +635,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The limit, or "unlimited".
|
||||
* @cc.treturn [1] number The maximum amount of fuel a turtle can hold.
|
||||
* @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving.
|
||||
* @cc.since 1.6
|
||||
* @see #getFuelLevel()
|
||||
* @see #refuel(Optional)
|
||||
*/
|
||||
@@ -625,6 +656,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @cc.treturn [1] true If the item was equipped.
|
||||
* @cc.treturn [2] false If we could not equip the item.
|
||||
* @cc.treturn [2] string The reason equipping this item failed.
|
||||
* @cc.since 1.6
|
||||
* @see #equipRight()
|
||||
*/
|
||||
@LuaFunction
|
||||
@@ -644,7 +676,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @cc.treturn [1] true If the item was equipped.
|
||||
* @cc.treturn [2] false If we could not equip the item.
|
||||
* @cc.treturn [2] string The reason equipping this item failed.
|
||||
* @see #equipRight()
|
||||
* @cc.since 1.6
|
||||
* @see #equipLeft()
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult equipRight()
|
||||
@@ -658,6 +691,8 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether there is a block in front of the turtle.
|
||||
* @cc.treturn table|string Information about the block in front, or a message explaining that there is no block.
|
||||
* @cc.since 1.64
|
||||
* @cc.changed 1.76 Added block state to return value.
|
||||
* @cc.usage <pre>{@code
|
||||
* local has_block, data = turtle.inspect()
|
||||
* if has_block then
|
||||
@@ -683,6 +718,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether there is a block above the turtle.
|
||||
* @cc.treturn table|string Information about the above below, or a message explaining that there is no block.
|
||||
* @cc.since 1.64
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult inspectUp()
|
||||
@@ -696,6 +732,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The turtle command result.
|
||||
* @cc.treturn boolean Whether there is a block below the turtle.
|
||||
* @cc.treturn table|string Information about the block below, or a message explaining that there is no block.
|
||||
* @cc.since 1.64
|
||||
*/
|
||||
@LuaFunction
|
||||
public final MethodResult inspectDown()
|
||||
@@ -713,6 +750,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
* @return The command result.
|
||||
* @throws LuaException If the slot is out of range.
|
||||
* @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty.
|
||||
* @cc.since 1.64
|
||||
* @cc.usage Print the current slot, assuming it contains 13 dirt.
|
||||
*
|
||||
* <pre>{@code
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class InvisibleSlot extends Slot
|
||||
{
|
||||
public InvisibleSlot( Container container, int slot )
|
||||
{
|
||||
super( container, slot, 0, 0 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPlace( @Nonnull ItemStack stack )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mayPickup( @Nonnull Player player )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user