mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-03 07:03:00 +00:00
gradle=7.1.1, gradle migrateMappings
This commit is contained in:
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* 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.apis;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.*;
|
||||
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
||||
import dan200.computercraft.shared.util.NBTUtil;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.state.property.Property;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @cc.module commands
|
||||
*/
|
||||
public class CommandAPI implements ILuaAPI
|
||||
{
|
||||
private final TileCommandComputer computer;
|
||||
|
||||
public CommandAPI( TileCommandComputer computer )
|
||||
{
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] { "commands" };
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a specific command.
|
||||
*
|
||||
* @param command The command to execute.
|
||||
* @return See {@code cc.treturn}.
|
||||
* @cc.treturn boolean Whether the command executed successfully.
|
||||
* @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.usage Set the block above the command computer to stone.
|
||||
* <pre>
|
||||
* commands.exec("setblock ~ ~1 ~ minecraft:stone")
|
||||
* </pre>
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public final Object[] exec( String command )
|
||||
{
|
||||
return doCommand( command );
|
||||
}
|
||||
|
||||
private Object[] doCommand( String command )
|
||||
{
|
||||
MinecraftServer server = computer.getWorld()
|
||||
.getServer();
|
||||
if( server == null || !server.areCommandBlocksEnabled() )
|
||||
{
|
||||
return new Object[] { false, createOutput( "Command blocks disabled by server" ) };
|
||||
}
|
||||
|
||||
CommandManager commandManager = server.getCommandManager();
|
||||
TileCommandComputer.CommandReceiver receiver = computer.getReceiver();
|
||||
try
|
||||
{
|
||||
receiver.clearOutput();
|
||||
int result = commandManager.execute( computer.getSource(), command );
|
||||
return new Object[] { result > 0, receiver.copyOutput(), result };
|
||||
}
|
||||
catch( Throwable t )
|
||||
{
|
||||
if( ComputerCraft.logComputerErrors )
|
||||
{
|
||||
ComputerCraft.log.error( "Error running command.", t );
|
||||
}
|
||||
return new Object[] { false, createOutput( "Java Exception Thrown: " + t ) };
|
||||
}
|
||||
}
|
||||
|
||||
private static Object createOutput( String output )
|
||||
{
|
||||
return new Object[] { output };
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously execute a command.
|
||||
*
|
||||
* Unlike {@link #exec}, this will immediately return, instead of waiting for the command to execute. This allows you to run multiple commands at the
|
||||
* same time.
|
||||
*
|
||||
* When this command has finished executing, it will queue a `task_complete` event containing the result of executing this command (what {@link #exec}
|
||||
* would return).
|
||||
*
|
||||
* @param context The context this command executes under.
|
||||
* @param command The command to execute.
|
||||
* @return The "task id". When this command has been executed, it will queue a `task_complete` event with a matching id.
|
||||
* @throws LuaException (hidden) If the task cannot be created.
|
||||
* @cc.usage Asynchronously sets the block above the computer to stone.
|
||||
* <pre>
|
||||
* commands.execAsync("~ ~1 ~ minecraft:stone")
|
||||
* </pre>
|
||||
* @cc.see parallel One may also use the parallel API to run multiple commands at once.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final long execAsync( ILuaContext context, String command ) throws LuaException
|
||||
{
|
||||
return context.issueMainThreadTask( () -> doCommand( command ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* List all available commands which the computer has permission to execute.
|
||||
*
|
||||
* @param args Arguments to this function.
|
||||
* @return A list of all available commands
|
||||
* @throws LuaException (hidden) On non-string arguments.
|
||||
* @cc.tparam string ... The sub-command to complete.
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public final List<String> list( IArguments args ) throws LuaException
|
||||
{
|
||||
MinecraftServer server = computer.getWorld()
|
||||
.getServer();
|
||||
|
||||
if( server == null )
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
CommandNode<ServerCommandSource> node = server.getCommandManager()
|
||||
.getDispatcher()
|
||||
.getRoot();
|
||||
for( int j = 0; j < args.count(); j++ )
|
||||
{
|
||||
String name = args.getString( j );
|
||||
node = node.getChild( name );
|
||||
if( !(node instanceof LiteralCommandNode) )
|
||||
{
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
List<String> result = new ArrayList<>();
|
||||
for( CommandNode<?> child : node.getChildren() )
|
||||
{
|
||||
if( child instanceof LiteralCommandNode<?> )
|
||||
{
|
||||
result.add( child.getName() );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position of the current command computer.
|
||||
*
|
||||
* @return The block's position.
|
||||
* @cc.treturn number This computer's x position.
|
||||
* @cc.treturn number This computer's y position.
|
||||
* @cc.treturn number This computer's z position.
|
||||
* @cc.see gps.locate To get the position of a non-command computer.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final Object[] getBlockPosition()
|
||||
{
|
||||
// This is probably safe to do on the Lua thread. Probably.
|
||||
BlockPos pos = computer.getPos();
|
||||
return new Object[] { pos.getX(), pos.getY(), pos.getZ() };
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about a range of blocks.
|
||||
*
|
||||
* This returns the same information as @{getBlockInfo}, just for multiple blocks at once.
|
||||
*
|
||||
* Blocks are traversed by ascending y level, followed by z and x - the returned table may be indexed using `x + z*width + y*depth*depth`.
|
||||
*
|
||||
* @param minX The start x coordinate of the range to query.
|
||||
* @param minY The start y coordinate of the range to query.
|
||||
* @param minZ The start z coordinate of the range to query.
|
||||
* @param maxX The end x coordinate of the range to query.
|
||||
* @param maxY The end y coordinate of the range to query.
|
||||
* @param maxZ The end z coordinate of the range to query.
|
||||
* @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.
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public final List<Map<?, ?>> getBlockInfos( int minX, int minY, int minZ, int maxX, int maxY, int maxZ ) throws LuaException
|
||||
{
|
||||
// Get the details of the block
|
||||
World world = computer.getWorld();
|
||||
BlockPos min = new BlockPos( Math.min( minX, maxX ), Math.min( minY, maxY ), Math.min( minZ, maxZ ) );
|
||||
BlockPos max = new BlockPos( Math.max( minX, maxX ), Math.max( minY, maxY ), Math.max( minZ, maxZ ) );
|
||||
if( !World.isInBuildLimit( min ) || !World.isInBuildLimit( max ) )
|
||||
{
|
||||
throw new LuaException( "Co-ordinates out of range" );
|
||||
}
|
||||
|
||||
int blocks = (max.getX() - min.getX() + 1) * (max.getY() - min.getY() + 1) * (max.getZ() - min.getZ() + 1);
|
||||
if( blocks > 4096 )
|
||||
{
|
||||
throw new LuaException( "Too many blocks" );
|
||||
}
|
||||
|
||||
List<Map<?, ?>> results = new ArrayList<>( blocks );
|
||||
for( int y = min.getY(); y <= max.getY(); y++ )
|
||||
{
|
||||
for( int z = min.getZ(); z <= max.getZ(); z++ )
|
||||
{
|
||||
for( int x = min.getX(); x <= max.getX(); x++ )
|
||||
{
|
||||
BlockPos pos = new BlockPos( x, y, z );
|
||||
results.add( getBlockInfo( world, pos ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private static Map<?, ?> getBlockInfo( World world, BlockPos pos )
|
||||
{
|
||||
// Get the details of the block
|
||||
BlockState state = world.getBlockState( pos );
|
||||
Block block = state.getBlock();
|
||||
|
||||
Map<Object, Object> table = new HashMap<>();
|
||||
table.put( "name", Registry.BLOCK.getId( block ).toString() );
|
||||
table.put( "world", world.getRegistryKey() );
|
||||
|
||||
Map<Object, Object> stateTable = new HashMap<>();
|
||||
for( ImmutableMap.Entry<Property<?>, Comparable<?>> entry : state.getEntries().entrySet() )
|
||||
{
|
||||
Property<?> property = entry.getKey();
|
||||
stateTable.put( property.getName(), getPropertyValue( property, entry.getValue() ) );
|
||||
}
|
||||
table.put( "state", stateTable );
|
||||
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( tile != null )
|
||||
{
|
||||
table.put( "nbt", NBTUtil.toLua( tile.writeNbt( new NbtCompound() ) ) );
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
@SuppressWarnings( {
|
||||
"unchecked",
|
||||
"rawtypes"
|
||||
} )
|
||||
private static Object getPropertyValue( Property property, Comparable value )
|
||||
{
|
||||
if( value instanceof String || value instanceof Number || value instanceof Boolean )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return property.name( value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get some basic information about a block.
|
||||
*
|
||||
* The returned table contains the current name, metadata and block state (as with @{turtle.inspect}). If there is a tile entity for that block, its NBT
|
||||
* will also be returned.
|
||||
*
|
||||
* @param x The x position of the block to query.
|
||||
* @param y The y position of the block to query.
|
||||
* @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.
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public final Map<?, ?> getBlockInfo( int x, int y, int z ) throws LuaException
|
||||
{
|
||||
// Get the details of the block
|
||||
World world = computer.getWorld();
|
||||
BlockPos position = new BlockPos( x, y, z );
|
||||
if( World.isInBuildLimit( position ) )
|
||||
{
|
||||
return getBlockInfo( world, position );
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new LuaException( "Co-ordinates out of range" );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.items.ComputerItemFactory;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.item.ItemPlacementContext;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.state.StateManager;
|
||||
import net.minecraft.state.property.DirectionProperty;
|
||||
import net.minecraft.state.property.EnumProperty;
|
||||
import net.minecraft.state.property.Properties;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BlockComputer extends BlockComputerBase<TileComputer>
|
||||
{
|
||||
public static final EnumProperty<ComputerState> STATE = EnumProperty.of( "state", ComputerState.class );
|
||||
public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING;
|
||||
|
||||
public BlockComputer( Settings settings, ComputerFamily family, BlockEntityType<? extends TileComputer> type )
|
||||
{
|
||||
super( settings, family, type );
|
||||
setDefaultState( getDefaultState().with( FACING, Direction.NORTH )
|
||||
.with( STATE, ComputerState.OFF ) );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState getPlacementState( ItemPlacementContext placement )
|
||||
{
|
||||
return getDefaultState().with( FACING,
|
||||
placement.getPlayerFacing()
|
||||
.getOpposite() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void appendProperties( StateManager.Builder<Block, BlockState> builder )
|
||||
{
|
||||
builder.add( FACING, STATE );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected ItemStack getItem( TileComputerBase tile )
|
||||
{
|
||||
return tile instanceof TileComputer ? ComputerItemFactory.create( (TileComputer) tile ) : ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
import dan200.computercraft.shared.common.BlockGeneric;
|
||||
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.loot.context.LootContext;
|
||||
import net.minecraft.loot.context.LootContextParameters;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.stat.Stats;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.BlockView;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class BlockComputerBase<T extends TileComputerBase> extends BlockGeneric implements IBundledRedstoneBlock
|
||||
{
|
||||
private static final Identifier DROP = new Identifier( ComputerCraft.MOD_ID, "computer" );
|
||||
|
||||
private final ComputerFamily family;
|
||||
|
||||
protected BlockComputerBase( Settings settings, ComputerFamily family, BlockEntityType<? extends T> type )
|
||||
{
|
||||
super( settings, type );
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void onBlockAdded( @Nonnull BlockState state, @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState oldState, boolean isMoving )
|
||||
{
|
||||
super.onBlockAdded( state, world, pos, oldState, isMoving );
|
||||
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( tile instanceof TileComputerBase )
|
||||
{
|
||||
((TileComputerBase) tile).updateInput();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean emitsRedstonePower( @Nonnull BlockState state )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getWeakRedstonePower( @Nonnull BlockState state, @Nonnull BlockView world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
|
||||
{
|
||||
return getStrongRedstonePower( state, world, pos, incomingSide );
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public int getStrongRedstonePower( @Nonnull BlockState state, BlockView world, @Nonnull BlockPos pos, @Nonnull Direction incomingSide )
|
||||
{
|
||||
BlockEntity entity = world.getBlockEntity( pos );
|
||||
if( !(entity instanceof TileComputerBase) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
TileComputerBase computerEntity = (TileComputerBase) entity;
|
||||
ServerComputer computer = computerEntity.getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ComputerSide localSide = computerEntity.remapToLocalSide( incomingSide.getOpposite() );
|
||||
return computer.getRedstoneOutput( localSide );
|
||||
}
|
||||
|
||||
public ComputerFamily getFamily()
|
||||
{
|
||||
return family;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBundledRedstoneConnectivity( World world, BlockPos pos, Direction side )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBundledRedstoneOutput( World world, BlockPos pos, Direction side )
|
||||
{
|
||||
BlockEntity entity = world.getBlockEntity( pos );
|
||||
if( !(entity instanceof TileComputerBase) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
TileComputerBase computerEntity = (TileComputerBase) entity;
|
||||
ServerComputer computer = computerEntity.getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ComputerSide localSide = computerEntity.remapToLocalSide( side );
|
||||
return computer.getBundledRedstoneOutput( localSide );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterBreak( @Nonnull World world, PlayerEntity player, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nullable BlockEntity tile,
|
||||
@Nonnull ItemStack tool )
|
||||
{
|
||||
// Don't drop blocks here - see onBlockHarvested.
|
||||
player.incrementStat( Stats.MINED.getOrCreateStat( this ) );
|
||||
player.addExhaustion( 0.005F );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaced( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, LivingEntity placer, @Nonnull ItemStack stack )
|
||||
{
|
||||
super.onPlaced( world, pos, state, placer, stack );
|
||||
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( !world.isClient && tile instanceof IComputerTile && stack.getItem() instanceof IComputerItem )
|
||||
{
|
||||
IComputerTile computer = (IComputerTile) tile;
|
||||
IComputerItem item = (IComputerItem) stack.getItem();
|
||||
|
||||
int id = item.getComputerID( stack );
|
||||
if( id != -1 )
|
||||
{
|
||||
computer.setComputerID( id );
|
||||
}
|
||||
|
||||
String label = item.getLabel( stack );
|
||||
if( label != null )
|
||||
{
|
||||
computer.setLabel( label );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack getPickStack( BlockView world, BlockPos pos, BlockState state )
|
||||
{
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( tile instanceof TileComputerBase )
|
||||
{
|
||||
ItemStack result = getItem( (TileComputerBase) tile );
|
||||
if( !result.isEmpty() )
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return super.getPickStack( world, pos, state );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected abstract ItemStack getItem( TileComputerBase tile );
|
||||
|
||||
@Override
|
||||
public void onBreak( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull BlockState state, @Nonnull PlayerEntity player )
|
||||
{
|
||||
// Call super as it is what provides sound and block break particles. Does not do anything else.
|
||||
super.onBreak( world, pos, state, player );
|
||||
|
||||
if( !(world instanceof ServerWorld) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
ServerWorld serverWorld = (ServerWorld) world;
|
||||
|
||||
// We drop the item here instead of doing it in the harvest method, as we should
|
||||
// drop computers for creative players too.
|
||||
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( tile instanceof TileComputerBase )
|
||||
{
|
||||
TileComputerBase computer = (TileComputerBase) tile;
|
||||
LootContext.Builder context = new LootContext.Builder( serverWorld ).random( world.random )
|
||||
.parameter( LootContextParameters.ORIGIN, Vec3d.ofCenter( pos ) )
|
||||
.parameter( LootContextParameters.TOOL, player.getMainHandStack() )
|
||||
.parameter( LootContextParameters.THIS_ENTITY, player )
|
||||
.parameter( LootContextParameters.BLOCK_ENTITY, tile )
|
||||
.putDrop( DROP, ( ctx, out ) -> out.accept( getItem( computer ) ) );
|
||||
for( ItemStack item : state.getDroppedStacks( context ) )
|
||||
{
|
||||
dropStack( world, pos, item );
|
||||
}
|
||||
|
||||
state.onStacksDropped( serverWorld, pos, player.getMainHandStack() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.apis.OSAPI;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A computer or turtle wrapped as a peripheral.
|
||||
*
|
||||
* This allows for basic interaction with adjacent computers. Computers wrapped as peripherals will have the type {@code computer} while turtles will be
|
||||
* {@code turtle}.
|
||||
*
|
||||
* @cc.module computer
|
||||
*/
|
||||
public class ComputerPeripheral implements IPeripheral
|
||||
{
|
||||
private final String type;
|
||||
private final ComputerProxy computer;
|
||||
|
||||
public ComputerPeripheral( String type, ComputerProxy computer )
|
||||
{
|
||||
this.type = type;
|
||||
this.computer = computer;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Object getTarget()
|
||||
{
|
||||
return computer.getTile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( IPeripheral other )
|
||||
{
|
||||
return other instanceof ComputerPeripheral && computer == ((ComputerPeripheral) other).computer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn the other computer on.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final void turnOn()
|
||||
{
|
||||
computer.turnOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the other computer.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final void shutdown()
|
||||
{
|
||||
computer.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reboot or turn on the other computer.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final void reboot()
|
||||
{
|
||||
computer.reboot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the other computer's ID.
|
||||
*
|
||||
* @return The computer's ID.
|
||||
* @see OSAPI#getComputerID() To get your computer's ID.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final int getID()
|
||||
{
|
||||
return computer.assignID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the other computer is on.
|
||||
*
|
||||
* @return If the computer is on.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final boolean isOn()
|
||||
{
|
||||
return computer.isOn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the other computer's label.
|
||||
*
|
||||
* @return The computer's label.
|
||||
* @see OSAPI#getComputerLabel() To get your label.
|
||||
*/
|
||||
@Nullable
|
||||
@LuaFunction
|
||||
public final String getLabel()
|
||||
{
|
||||
return computer.getLabel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.IComputer;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* A proxy object for computer objects, delegating to {@link IComputer} or {@link TileComputer} where appropriate.
|
||||
*/
|
||||
public class ComputerProxy
|
||||
{
|
||||
private final Supplier<TileComputerBase> get;
|
||||
|
||||
public ComputerProxy( Supplier<TileComputerBase> get )
|
||||
{
|
||||
this.get = get;
|
||||
}
|
||||
|
||||
public void turnOn()
|
||||
{
|
||||
TileComputerBase tile = getTile();
|
||||
ServerComputer computer = tile.getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
tile.startOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
computer.turnOn();
|
||||
}
|
||||
}
|
||||
|
||||
protected TileComputerBase getTile()
|
||||
{
|
||||
return get.get();
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
TileComputerBase tile = getTile();
|
||||
ServerComputer computer = tile.getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
tile.startOn = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
computer.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
public void reboot()
|
||||
{
|
||||
TileComputerBase tile = getTile();
|
||||
ServerComputer computer = tile.getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
tile.startOn = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
computer.reboot();
|
||||
}
|
||||
}
|
||||
|
||||
public int assignID()
|
||||
{
|
||||
TileComputerBase tile = getTile();
|
||||
ServerComputer computer = tile.getServerComputer();
|
||||
return computer == null ? tile.getComputerID() : computer.getID();
|
||||
}
|
||||
|
||||
public boolean isOn()
|
||||
{
|
||||
ServerComputer computer = getTile().getServerComputer();
|
||||
return computer != null && computer.isOn();
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
TileComputerBase tile = getTile();
|
||||
ServerComputer computer = tile.getServerComputer();
|
||||
return computer == null ? tile.getLabel() : computer.getLabel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
|
||||
public interface IComputerTile
|
||||
{
|
||||
int getComputerID();
|
||||
|
||||
void setComputerID( int id );
|
||||
|
||||
String getLabel();
|
||||
|
||||
void setLabel( String label );
|
||||
|
||||
ComputerFamily getFamily();
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.computer.apis.CommandAPI;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.command.CommandOutput;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.math.Vec2f;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.GameRules;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class TileCommandComputer extends TileComputer
|
||||
{
|
||||
private final CommandReceiver receiver;
|
||||
|
||||
public TileCommandComputer( ComputerFamily family, BlockEntityType<? extends TileCommandComputer> type )
|
||||
{
|
||||
super( family, type );
|
||||
receiver = new CommandReceiver();
|
||||
}
|
||||
|
||||
public CommandReceiver getReceiver()
|
||||
{
|
||||
return receiver;
|
||||
}
|
||||
|
||||
public ServerCommandSource getSource()
|
||||
{
|
||||
ServerComputer computer = getServerComputer();
|
||||
String name = "@";
|
||||
if( computer != null )
|
||||
{
|
||||
String label = computer.getLabel();
|
||||
if( label != null )
|
||||
{
|
||||
name = label;
|
||||
}
|
||||
}
|
||||
|
||||
return new ServerCommandSource( receiver,
|
||||
new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 ),
|
||||
Vec2f.ZERO,
|
||||
(ServerWorld) getWorld(),
|
||||
2,
|
||||
name,
|
||||
new LiteralText( name ),
|
||||
getWorld().getServer(),
|
||||
null );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerComputer createComputer( int instanceID, int id )
|
||||
{
|
||||
ServerComputer computer = super.createComputer( instanceID, id );
|
||||
computer.addAPI( new CommandAPI( this ) );
|
||||
return computer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsable( PlayerEntity player, boolean ignoreRange )
|
||||
{
|
||||
return isUsable( player ) && super.isUsable( player, ignoreRange );
|
||||
}
|
||||
|
||||
public static boolean isUsable( PlayerEntity player )
|
||||
{
|
||||
MinecraftServer server = player.getServer();
|
||||
if( server == null || !server.areCommandBlocksEnabled() )
|
||||
{
|
||||
player.sendMessage( new TranslatableText( "advMode.notEnabled" ), true );
|
||||
return false;
|
||||
}
|
||||
else if( ComputerCraft.commandRequireCreative ? !player.isCreativeLevelTwoOp() : !server.getPlayerManager()
|
||||
.isOperator( player.getGameProfile() ) )
|
||||
{
|
||||
player.sendMessage( new TranslatableText( "advMode.notAllowed" ), true );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public class CommandReceiver implements CommandOutput
|
||||
{
|
||||
private final Map<Integer, String> output = new HashMap<>();
|
||||
|
||||
public void clearOutput()
|
||||
{
|
||||
output.clear();
|
||||
}
|
||||
|
||||
public Map<Integer, String> getOutput()
|
||||
{
|
||||
return output;
|
||||
}
|
||||
|
||||
public Map<Integer, String> copyOutput()
|
||||
{
|
||||
return new HashMap<>( output );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSystemMessage( @Nonnull Text textComponent, @Nonnull UUID id )
|
||||
{
|
||||
output.put( output.size() + 1, textComponent.getString() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldReceiveFeedback()
|
||||
{
|
||||
return getWorld().getGameRules()
|
||||
.getBoolean( GameRules.SEND_COMMAND_FEEDBACK );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldTrackOutput()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBroadcastConsoleToOps()
|
||||
{
|
||||
return getWorld().getGameRules()
|
||||
.getBoolean( GameRules.COMMAND_BLOCK_OUTPUT );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
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 net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class TileComputer extends TileComputerBase
|
||||
{
|
||||
private ComputerProxy proxy;
|
||||
|
||||
public TileComputer( ComputerFamily family, BlockEntityType<? extends TileComputer> type )
|
||||
{
|
||||
super( type, family );
|
||||
}
|
||||
|
||||
public boolean isUsableByPlayer( PlayerEntity player )
|
||||
{
|
||||
return isUsable( player, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateBlockState( ComputerState newState )
|
||||
{
|
||||
BlockState existing = getCachedState();
|
||||
if( existing.get( BlockComputer.STATE ) != newState )
|
||||
{
|
||||
getWorld().setBlockState( getPos(), existing.with( BlockComputer.STATE, newState ), 3 );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Direction getDirection()
|
||||
{
|
||||
return getCachedState().get( BlockComputer.FACING );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ComputerSide remapLocalSide( ComputerSide localSide )
|
||||
{
|
||||
// For legacy reasons, computers invert the meaning of "left" and "right". A computer's front is facing
|
||||
// towards you, but a turtle's front is facing the other way.
|
||||
if( localSide == ComputerSide.RIGHT )
|
||||
{
|
||||
return ComputerSide.LEFT;
|
||||
}
|
||||
if( localSide == ComputerSide.LEFT )
|
||||
{
|
||||
return ComputerSide.RIGHT;
|
||||
}
|
||||
return localSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerComputer createComputer( int instanceID, int id )
|
||||
{
|
||||
ComputerFamily family = getFamily();
|
||||
ServerComputer computer = new ServerComputer( getWorld(),
|
||||
id, label,
|
||||
instanceID,
|
||||
family,
|
||||
ComputerCraft.computerTermWidth,
|
||||
ComputerCraft.computerTermHeight );
|
||||
computer.setPosition( getPos() );
|
||||
return computer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputerProxy createProxy()
|
||||
{
|
||||
if( proxy == null )
|
||||
{
|
||||
proxy = new ComputerProxy( () -> this )
|
||||
{
|
||||
@Override
|
||||
protected TileComputerBase getTile()
|
||||
{
|
||||
return TileComputer.this;
|
||||
}
|
||||
};
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ScreenHandler createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player )
|
||||
{
|
||||
return new ContainerComputer( id, this );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
* 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.blocks;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IPeripheralTile;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
import dan200.computercraft.shared.BundledRedstone;
|
||||
import dan200.computercraft.shared.Peripherals;
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import dan200.computercraft.shared.util.RedstoneUtil;
|
||||
import joptsimple.internal.Strings;
|
||||
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.RedstoneWireBlock;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.Nameable;
|
||||
import net.minecraft.util.Tickable;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class TileComputerBase extends TileGeneric implements IComputerTile, Tickable, IPeripheralTile, Nameable,
|
||||
ExtendedScreenHandlerFactory
|
||||
{
|
||||
private static final String NBT_ID = "ComputerId";
|
||||
private static final String NBT_LABEL = "Label";
|
||||
private static final String NBT_ON = "On";
|
||||
private final ComputerFamily family;
|
||||
protected String label = null;
|
||||
boolean startOn = false;
|
||||
private int instanceID = -1;
|
||||
private int computerID = -1;
|
||||
private boolean on = false;
|
||||
private boolean fresh = false;
|
||||
|
||||
public TileComputerBase( BlockEntityType<? extends TileGeneric> type, ComputerFamily family )
|
||||
{
|
||||
super( type );
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
unload();
|
||||
for( Direction dir : DirectionUtil.FACINGS )
|
||||
{
|
||||
RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkUnloaded()
|
||||
{
|
||||
unload();
|
||||
}
|
||||
|
||||
protected void unload()
|
||||
{
|
||||
if( instanceID >= 0 )
|
||||
{
|
||||
if( !getWorld().isClient )
|
||||
{
|
||||
ComputerCraft.serverComputerRegistry.remove( instanceID );
|
||||
}
|
||||
instanceID = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ActionResult onActivate( PlayerEntity player, Hand hand, BlockHitResult hit )
|
||||
{
|
||||
ItemStack currentItem = player.getStackInHand( hand );
|
||||
if( !currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag( player ) && currentItem.hasCustomName() )
|
||||
{
|
||||
// Label to rename computer
|
||||
if( !getWorld().isClient )
|
||||
{
|
||||
setLabel( currentItem.getName()
|
||||
.getString() );
|
||||
currentItem.decrement( 1 );
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
else if( !player.isInSneakingPose() )
|
||||
{
|
||||
// Regular right click to activate computer
|
||||
if( !getWorld().isClient && isUsable( player, false ) )
|
||||
{
|
||||
createServerComputer().turnOn();
|
||||
createServerComputer().sendTerminalState( player );
|
||||
new ComputerContainerData( createServerComputer() ).open( player, this );
|
||||
}
|
||||
return ActionResult.SUCCESS;
|
||||
}
|
||||
return ActionResult.PASS;
|
||||
}
|
||||
|
||||
protected boolean canNameWithTag( PlayerEntity player )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public ServerComputer createServerComputer()
|
||||
{
|
||||
if( getWorld().isClient )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
if( instanceID < 0 )
|
||||
{
|
||||
instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID();
|
||||
changed = true;
|
||||
}
|
||||
if( !ComputerCraft.serverComputerRegistry.contains( instanceID ) )
|
||||
{
|
||||
ServerComputer computer = createComputer( instanceID, computerID );
|
||||
ComputerCraft.serverComputerRegistry.add( instanceID, computer );
|
||||
fresh = true;
|
||||
changed = true;
|
||||
}
|
||||
if( changed )
|
||||
{
|
||||
updateBlock();
|
||||
updateInput();
|
||||
}
|
||||
return ComputerCraft.serverComputerRegistry.get( instanceID );
|
||||
}
|
||||
|
||||
public ServerComputer getServerComputer()
|
||||
{
|
||||
return getWorld().isClient ? null : ComputerCraft.serverComputerRegistry.get( instanceID );
|
||||
}
|
||||
|
||||
protected abstract ServerComputer createComputer( int instanceID, int id );
|
||||
|
||||
public void updateInput()
|
||||
{
|
||||
if( getWorld() == null || getWorld().isClient )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update all sides
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos pos = computer.getPosition();
|
||||
for( Direction dir : DirectionUtil.FACINGS )
|
||||
{
|
||||
updateSideInput( computer, dir, pos.offset( dir ) );
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSideInput( ServerComputer computer, Direction dir, BlockPos offset )
|
||||
{
|
||||
Direction offsetSide = dir.getOpposite();
|
||||
ComputerSide localDir = remapToLocalSide( dir );
|
||||
|
||||
computer.setRedstoneInput( localDir, getRedstoneInput( world, offset, dir ) );
|
||||
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
|
||||
if( !isPeripheralBlockedOnSide( localDir ) )
|
||||
{
|
||||
IPeripheral peripheral = Peripherals.getPeripheral( getWorld(), offset, offsetSide );
|
||||
computer.setPeripheral( localDir, peripheral );
|
||||
}
|
||||
}
|
||||
|
||||
protected ComputerSide remapToLocalSide( Direction globalSide )
|
||||
{
|
||||
return remapLocalSide( DirectionUtil.toLocal( getDirection(), globalSide ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
protected static int getRedstoneInput( World world, BlockPos pos, Direction side )
|
||||
{
|
||||
int power = world.getEmittedRedstonePower( pos, side );
|
||||
if( power >= 15 )
|
||||
{
|
||||
return power;
|
||||
}
|
||||
|
||||
BlockState neighbour = world.getBlockState( pos );
|
||||
return neighbour.getBlock() == Blocks.REDSTONE_WIRE ? Math.max( power, neighbour.get( RedstoneWireBlock.POWER ) ) : power;
|
||||
}
|
||||
|
||||
protected boolean isPeripheralBlockedOnSide( ComputerSide localSide )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected ComputerSide remapLocalSide( ComputerSide localSide )
|
||||
{
|
||||
return localSide;
|
||||
}
|
||||
|
||||
protected abstract Direction getDirection();
|
||||
|
||||
@Override
|
||||
public void onNeighbourChange( @Nonnull BlockPos neighbour )
|
||||
{
|
||||
updateInput( neighbour );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
|
||||
{
|
||||
updateInput( neighbour );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readDescription( @Nonnull NbtCompound nbt )
|
||||
{
|
||||
super.readDescription( nbt );
|
||||
label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
|
||||
computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeDescription( @Nonnull NbtCompound nbt )
|
||||
{
|
||||
super.writeDescription( nbt );
|
||||
if( label != null )
|
||||
{
|
||||
nbt.putString( NBT_LABEL, label );
|
||||
}
|
||||
if( computerID >= 0 )
|
||||
{
|
||||
nbt.putInt( NBT_ID, computerID );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick()
|
||||
{
|
||||
if( !getWorld().isClient )
|
||||
{
|
||||
ServerComputer computer = createServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If the computer isn't on and should be, then turn it on
|
||||
if( startOn || (fresh && on) )
|
||||
{
|
||||
computer.turnOn();
|
||||
startOn = false;
|
||||
}
|
||||
|
||||
computer.keepAlive();
|
||||
|
||||
fresh = false;
|
||||
computerID = computer.getID();
|
||||
label = computer.getLabel();
|
||||
on = computer.isOn();
|
||||
|
||||
if( computer.hasOutputChanged() )
|
||||
{
|
||||
updateOutput();
|
||||
}
|
||||
|
||||
// Update the block state if needed. We don't fire a block update intentionally,
|
||||
// as this only really is needed on the client side.
|
||||
updateBlockState( computer.getState() );
|
||||
|
||||
if( computer.hasOutputChanged() )
|
||||
{
|
||||
updateOutput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateOutput()
|
||||
{
|
||||
// Update redstone
|
||||
updateBlock();
|
||||
for( Direction dir : DirectionUtil.FACINGS )
|
||||
{
|
||||
RedstoneUtil.propagateRedstoneOutput( getWorld(), getPos(), dir );
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void updateBlockState( ComputerState newState );
|
||||
|
||||
@Override
|
||||
public void readNbt( @Nonnull BlockState state, @Nonnull NbtCompound nbt )
|
||||
{
|
||||
super.readNbt( state, nbt );
|
||||
|
||||
// Load ID, label and power state
|
||||
computerID = nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
|
||||
label = nbt.contains( NBT_LABEL ) ? nbt.getString( NBT_LABEL ) : null;
|
||||
on = startOn = nbt.getBoolean( NBT_ON );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public NbtCompound writeNbt( @Nonnull NbtCompound nbt )
|
||||
{
|
||||
// Save ID, label and power state
|
||||
if( computerID >= 0 )
|
||||
{
|
||||
nbt.putInt( NBT_ID, computerID );
|
||||
}
|
||||
if( label != null )
|
||||
{
|
||||
nbt.putString( NBT_LABEL, label );
|
||||
}
|
||||
nbt.putBoolean( NBT_ON, on );
|
||||
|
||||
return super.writeNbt( nbt );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markRemoved()
|
||||
{
|
||||
unload();
|
||||
super.markRemoved();
|
||||
}
|
||||
|
||||
private void updateInput( BlockPos neighbour )
|
||||
{
|
||||
if( getWorld() == null || getWorld().isClient )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for( Direction dir : DirectionUtil.FACINGS )
|
||||
{
|
||||
BlockPos offset = pos.offset( dir );
|
||||
if( offset.equals( neighbour ) )
|
||||
{
|
||||
updateSideInput( computer, dir, offset );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If the position is not any adjacent one, update all inputs.
|
||||
updateInput();
|
||||
}
|
||||
|
||||
private void updateInput( Direction dir )
|
||||
{
|
||||
if( getWorld() == null || getWorld().isClient )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
updateSideInput( computer, dir, pos.offset( dir ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getComputerID()
|
||||
{
|
||||
return computerID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setComputerID( int id )
|
||||
{
|
||||
if( getWorld().isClient || computerID == id )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
computerID = id;
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.setID( computerID );
|
||||
}
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getLabel()
|
||||
{
|
||||
return label;
|
||||
}
|
||||
|
||||
// Networking stuff
|
||||
|
||||
@Override
|
||||
public final void setLabel( String label )
|
||||
{
|
||||
if( getWorld().isClient || Objects.equals( this.label, label ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.label = label;
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.setLabel( label );
|
||||
}
|
||||
markDirty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComputerFamily getFamily()
|
||||
{
|
||||
return family;
|
||||
}
|
||||
|
||||
protected void transferStateFrom( TileComputerBase copy )
|
||||
{
|
||||
if( copy.computerID != computerID || copy.instanceID != instanceID )
|
||||
{
|
||||
unload();
|
||||
instanceID = copy.instanceID;
|
||||
computerID = copy.computerID;
|
||||
label = copy.label;
|
||||
on = copy.on;
|
||||
startOn = copy.startOn;
|
||||
updateBlock();
|
||||
}
|
||||
copy.instanceID = -1;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public IPeripheral getPeripheral( Direction side )
|
||||
{
|
||||
return new ComputerPeripheral( "computer", createProxy() );
|
||||
}
|
||||
|
||||
public abstract ComputerProxy createProxy();
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Text getName()
|
||||
{
|
||||
return hasCustomName() ? new LiteralText( label ) : new TranslatableText( getCachedState().getBlock()
|
||||
.getTranslationKey() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomName()
|
||||
{
|
||||
return !Strings.isNullOrEmpty( label );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Text getDisplayName()
|
||||
{
|
||||
return Nameable.super.getDisplayName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Text getCustomName()
|
||||
{
|
||||
return hasCustomName() ? new LiteralText( label ) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeScreenOpeningData( ServerPlayerEntity serverPlayerEntity, PacketByteBuf packetByteBuf )
|
||||
{
|
||||
packetByteBuf.writeInt( getServerComputer().getInstanceID() );
|
||||
packetByteBuf.writeEnumConstant( getServerComputer().getFamily() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import dan200.computercraft.shared.common.ClientTerminal;
|
||||
import dan200.computercraft.shared.network.NetworkHandler;
|
||||
import dan200.computercraft.shared.network.server.*;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
|
||||
public class ClientComputer extends ClientTerminal implements IComputer
|
||||
{
|
||||
private final int instanceID;
|
||||
|
||||
private boolean on = false;
|
||||
private boolean blinking = false;
|
||||
private NbtCompound userData = null;
|
||||
|
||||
|
||||
public ClientComputer( int instanceID )
|
||||
{
|
||||
super( false );
|
||||
this.instanceID = instanceID;
|
||||
}
|
||||
|
||||
public NbtCompound getUserData()
|
||||
{
|
||||
return userData;
|
||||
}
|
||||
|
||||
public void requestState()
|
||||
{
|
||||
// Request state from server
|
||||
NetworkHandler.sendToServer( new RequestComputerMessage( getInstanceID() ) );
|
||||
}
|
||||
|
||||
// IComputer
|
||||
|
||||
@Override
|
||||
public int getInstanceID()
|
||||
{
|
||||
return instanceID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void turnOn()
|
||||
{
|
||||
// Send turnOn to server
|
||||
NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.TURN_ON ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown()
|
||||
{
|
||||
// Send shutdown to server
|
||||
NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.SHUTDOWN ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reboot()
|
||||
{
|
||||
// Send reboot to server
|
||||
NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.REBOOT ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueEvent( String event, Object[] arguments )
|
||||
{
|
||||
// Send event to server
|
||||
NetworkHandler.sendToServer( new QueueEventServerMessage( instanceID, event, arguments ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOn()
|
||||
{
|
||||
return on;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCursorDisplayed()
|
||||
{
|
||||
return on && blinking;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown( int key, boolean repeat )
|
||||
{
|
||||
NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID,
|
||||
repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN,
|
||||
key ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyUp( int key )
|
||||
{
|
||||
NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID, KeyEventServerMessage.TYPE_UP, key ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClick( int button, int x, int y )
|
||||
{
|
||||
NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_CLICK, button, x, y ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp( int button, int x, int y )
|
||||
{
|
||||
NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_UP, button, x, y ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDrag( int button, int x, int y )
|
||||
{
|
||||
NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_DRAG, button, x, y ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseScroll( int direction, int x, int y )
|
||||
{
|
||||
NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) );
|
||||
}
|
||||
|
||||
public void setState( ComputerState state, NbtCompound userData )
|
||||
{
|
||||
on = state != ComputerState.OFF;
|
||||
blinking = state == ComputerState.BLINKING;
|
||||
this.userData = userData;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
public class ClientComputerRegistry extends ComputerRegistry<ClientComputer>
|
||||
{
|
||||
@Override
|
||||
public void add( int instanceID, ClientComputer computer )
|
||||
{
|
||||
super.add( instanceID, computer );
|
||||
computer.requestState();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
public enum ComputerFamily
|
||||
{
|
||||
NORMAL, ADVANCED, COMMAND
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class ComputerRegistry<T extends IComputer>
|
||||
{
|
||||
private final Map<Integer, T> computers;
|
||||
private int nextUnusedInstanceID;
|
||||
private int sessionID;
|
||||
|
||||
protected ComputerRegistry()
|
||||
{
|
||||
computers = new HashMap<>();
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
computers.clear();
|
||||
nextUnusedInstanceID = 0;
|
||||
sessionID = new Random().nextInt();
|
||||
}
|
||||
|
||||
public int getSessionID()
|
||||
{
|
||||
return sessionID;
|
||||
}
|
||||
|
||||
public int getUnusedInstanceID()
|
||||
{
|
||||
return nextUnusedInstanceID++;
|
||||
}
|
||||
|
||||
public Collection<T> getComputers()
|
||||
{
|
||||
return computers.values();
|
||||
}
|
||||
|
||||
public T get( int instanceID )
|
||||
{
|
||||
if( instanceID >= 0 )
|
||||
{
|
||||
if( computers.containsKey( instanceID ) )
|
||||
{
|
||||
return computers.get( instanceID );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean contains( int instanceID )
|
||||
{
|
||||
return computers.containsKey( instanceID );
|
||||
}
|
||||
|
||||
public void add( int instanceID, T computer )
|
||||
{
|
||||
if( computers.containsKey( instanceID ) )
|
||||
{
|
||||
remove( instanceID );
|
||||
}
|
||||
computers.put( instanceID, computer );
|
||||
nextUnusedInstanceID = Math.max( nextUnusedInstanceID, instanceID + 1 );
|
||||
}
|
||||
|
||||
public void remove( int instanceID )
|
||||
{
|
||||
computers.remove( instanceID );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import net.minecraft.util.StringIdentifiable;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public enum ComputerState implements StringIdentifiable
|
||||
{
|
||||
OFF( "off" ), ON( "on" ), BLINKING( "blinking" );
|
||||
|
||||
private final String name;
|
||||
|
||||
ComputerState( String name )
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String asString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -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.core;
|
||||
|
||||
import dan200.computercraft.shared.common.ITerminal;
|
||||
|
||||
public interface IComputer extends ITerminal, InputHandler
|
||||
{
|
||||
int getInstanceID();
|
||||
|
||||
void turnOn();
|
||||
|
||||
void shutdown();
|
||||
|
||||
void reboot();
|
||||
|
||||
default void queueEvent( String event )
|
||||
{
|
||||
queueEvent( event, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
void queueEvent( String event, Object[] arguments );
|
||||
|
||||
default ComputerState getState()
|
||||
{
|
||||
if( !isOn() )
|
||||
{
|
||||
return ComputerState.OFF;
|
||||
}
|
||||
return isCursorDisplayed() ? ComputerState.BLINKING : ComputerState.ON;
|
||||
}
|
||||
|
||||
boolean isOn();
|
||||
|
||||
boolean isCursorDisplayed();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An instance of {@link Container} which provides a computer. You should implement this if you provide custom computers/GUIs to interact with them.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IContainerComputer
|
||||
{
|
||||
/**
|
||||
* Get the computer you are interacting with.
|
||||
*
|
||||
* This will only be called on the server.
|
||||
*
|
||||
* @return The computer you are interacting with.
|
||||
*/
|
||||
@Nullable
|
||||
IComputer getComputer();
|
||||
|
||||
/**
|
||||
* Get the input controller for this container.
|
||||
*
|
||||
* @return This container's input.
|
||||
*/
|
||||
@Nonnull
|
||||
default InputState getInput()
|
||||
{
|
||||
return new InputState( this );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
/**
|
||||
* Receives some input and forwards it to a computer.
|
||||
*
|
||||
* @see InputState
|
||||
* @see IComputer
|
||||
*/
|
||||
public interface InputHandler
|
||||
{
|
||||
void queueEvent( String event, Object[] arguments );
|
||||
|
||||
default void keyDown( int key, boolean repeat )
|
||||
{
|
||||
queueEvent( "key", new Object[] { key, repeat } );
|
||||
}
|
||||
|
||||
default void keyUp( int key )
|
||||
{
|
||||
queueEvent( "key_up", new Object[] { key } );
|
||||
}
|
||||
|
||||
default void mouseClick( int button, int x, int y )
|
||||
{
|
||||
queueEvent( "mouse_click", new Object[] { button, x, y } );
|
||||
}
|
||||
|
||||
default void mouseUp( int button, int x, int y )
|
||||
{
|
||||
queueEvent( "mouse_up", new Object[] { button, x, y } );
|
||||
}
|
||||
|
||||
default void mouseDrag( int button, int x, int y )
|
||||
{
|
||||
queueEvent( "mouse_drag", new Object[] { button, x, y } );
|
||||
}
|
||||
|
||||
default void mouseScroll( int direction, int x, int y )
|
||||
{
|
||||
queueEvent( "mouse_scroll", new Object[] { direction, x, y } );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntIterator;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
/**
|
||||
* An {@link InputHandler} which keeps track of the current key and mouse state, and releases them when the container is closed.
|
||||
*/
|
||||
public class InputState implements InputHandler
|
||||
{
|
||||
private final IContainerComputer owner;
|
||||
private final IntSet keysDown = new IntOpenHashSet( 4 );
|
||||
|
||||
private int lastMouseX;
|
||||
private int lastMouseY;
|
||||
private int lastMouseDown = -1;
|
||||
|
||||
public InputState( IContainerComputer owner )
|
||||
{
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueEvent( String event, Object[] arguments )
|
||||
{
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.queueEvent( event, arguments );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown( int key, boolean repeat )
|
||||
{
|
||||
keysDown.add( key );
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.keyDown( key, repeat );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyUp( int key )
|
||||
{
|
||||
keysDown.remove( key );
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.keyUp( key );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClick( int button, int x, int y )
|
||||
{
|
||||
lastMouseX = x;
|
||||
lastMouseY = y;
|
||||
lastMouseDown = button;
|
||||
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.mouseClick( button, x, y );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp( int button, int x, int y )
|
||||
{
|
||||
lastMouseX = x;
|
||||
lastMouseY = y;
|
||||
lastMouseDown = -1;
|
||||
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.mouseUp( button, x, y );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDrag( int button, int x, int y )
|
||||
{
|
||||
lastMouseX = x;
|
||||
lastMouseY = y;
|
||||
lastMouseDown = button;
|
||||
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.mouseDrag( button, x, y );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseScroll( int direction, int x, int y )
|
||||
{
|
||||
lastMouseX = x;
|
||||
lastMouseY = y;
|
||||
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
computer.mouseScroll( direction, x, y );
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
IComputer computer = owner.getComputer();
|
||||
if( computer != null )
|
||||
{
|
||||
IntIterator keys = keysDown.iterator();
|
||||
while( keys.hasNext() )
|
||||
{
|
||||
computer.keyUp( keys.nextInt() );
|
||||
}
|
||||
|
||||
if( lastMouseDown != -1 )
|
||||
{
|
||||
computer.mouseUp( lastMouseDown, lastMouseX, lastMouseY );
|
||||
}
|
||||
}
|
||||
|
||||
keysDown.clear();
|
||||
lastMouseDown = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.ComputerCraftAPIImpl;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||
import dan200.computercraft.api.lua.ILuaAPI;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||
import dan200.computercraft.core.computer.Computer;
|
||||
import dan200.computercraft.core.computer.ComputerSide;
|
||||
import dan200.computercraft.core.computer.IComputerEnvironment;
|
||||
import dan200.computercraft.shared.common.ServerTerminal;
|
||||
import dan200.computercraft.shared.network.NetworkHandler;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.client.ComputerDataClientMessage;
|
||||
import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage;
|
||||
import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage;
|
||||
import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ServerComputer extends ServerTerminal implements IComputer, IComputerEnvironment
|
||||
{
|
||||
private final int instanceID;
|
||||
private final ComputerFamily family;
|
||||
private final Computer computer;
|
||||
private World world;
|
||||
private BlockPos position;
|
||||
private NbtCompound userData;
|
||||
private boolean changed;
|
||||
|
||||
private boolean changedLastFrame;
|
||||
private int ticksSincePing;
|
||||
|
||||
public ServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight )
|
||||
{
|
||||
super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight );
|
||||
this.instanceID = instanceID;
|
||||
|
||||
this.world = world;
|
||||
position = null;
|
||||
|
||||
this.family = family;
|
||||
computer = new Computer( this, getTerminal(), computerID );
|
||||
computer.setLabel( label );
|
||||
userData = null;
|
||||
changed = false;
|
||||
|
||||
changedLastFrame = false;
|
||||
ticksSincePing = 0;
|
||||
}
|
||||
|
||||
public ComputerFamily getFamily()
|
||||
{
|
||||
return family;
|
||||
}
|
||||
|
||||
public World getWorld()
|
||||
{
|
||||
return world;
|
||||
}
|
||||
|
||||
public void setWorld( World world )
|
||||
{
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
public BlockPos getPosition()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition( BlockPos pos )
|
||||
{
|
||||
position = new BlockPos( pos );
|
||||
}
|
||||
|
||||
public IAPIEnvironment getAPIEnvironment()
|
||||
{
|
||||
return computer.getAPIEnvironment();
|
||||
}
|
||||
|
||||
public Computer getComputer()
|
||||
{
|
||||
return computer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update()
|
||||
{
|
||||
super.update();
|
||||
computer.tick();
|
||||
|
||||
changedLastFrame = computer.pollAndResetChanged() || changed;
|
||||
changed = false;
|
||||
|
||||
ticksSincePing++;
|
||||
}
|
||||
|
||||
public void keepAlive()
|
||||
{
|
||||
ticksSincePing = 0;
|
||||
}
|
||||
|
||||
public boolean hasTimedOut()
|
||||
{
|
||||
return ticksSincePing > 100;
|
||||
}
|
||||
|
||||
public void unload()
|
||||
{
|
||||
computer.unload();
|
||||
}
|
||||
|
||||
public NbtCompound getUserData()
|
||||
{
|
||||
if( userData == null )
|
||||
{
|
||||
userData = new NbtCompound();
|
||||
}
|
||||
return userData;
|
||||
}
|
||||
|
||||
public void updateUserData()
|
||||
{
|
||||
changed = true;
|
||||
}
|
||||
|
||||
public void broadcastState( boolean force )
|
||||
{
|
||||
if( hasOutputChanged() || force )
|
||||
{
|
||||
// Send computer state to all clients
|
||||
MinecraftServer server = GameInstanceUtils.getServer();
|
||||
if( server != null )
|
||||
{
|
||||
NetworkHandler.sendToAllPlayers( server, createComputerPacket() );
|
||||
}
|
||||
}
|
||||
|
||||
if( hasTerminalChanged() || force )
|
||||
{
|
||||
MinecraftServer server = GameInstanceUtils.getServer();
|
||||
if( server != null )
|
||||
{
|
||||
// Send terminal state to clients who are currently interacting with the computer.
|
||||
|
||||
NetworkMessage packet = null;
|
||||
for( PlayerEntity player : server.getPlayerManager()
|
||||
.getPlayerList() )
|
||||
{
|
||||
if( isInteracting( player ) )
|
||||
{
|
||||
if( packet == null )
|
||||
{
|
||||
packet = createTerminalPacket();
|
||||
}
|
||||
NetworkHandler.sendToPlayer( player, packet );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasOutputChanged()
|
||||
{
|
||||
return changedLastFrame;
|
||||
}
|
||||
|
||||
private NetworkMessage createComputerPacket()
|
||||
{
|
||||
return new ComputerDataClientMessage( this );
|
||||
}
|
||||
|
||||
protected boolean isInteracting( PlayerEntity player )
|
||||
{
|
||||
return getContainer( player ) != null;
|
||||
}
|
||||
|
||||
protected NetworkMessage createTerminalPacket()
|
||||
{
|
||||
return new ComputerTerminalClientMessage( getInstanceID(), write() );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IContainerComputer getContainer( PlayerEntity player )
|
||||
{
|
||||
if( player == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ScreenHandler container = player.currentScreenHandler;
|
||||
if( !(container instanceof IContainerComputer) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IContainerComputer computerContainer = (IContainerComputer) container;
|
||||
return computerContainer.getComputer() != this ? null : computerContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstanceID()
|
||||
{
|
||||
return instanceID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void turnOn()
|
||||
{
|
||||
// Turn on
|
||||
computer.turnOn();
|
||||
}
|
||||
|
||||
// IComputer
|
||||
|
||||
@Override
|
||||
public void shutdown()
|
||||
{
|
||||
// Shutdown
|
||||
computer.shutdown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reboot()
|
||||
{
|
||||
// Reboot
|
||||
computer.reboot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueEvent( String event, Object[] arguments )
|
||||
{
|
||||
// Queue event
|
||||
computer.queueEvent( event, arguments );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOn()
|
||||
{
|
||||
return computer.isOn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCursorDisplayed()
|
||||
{
|
||||
return computer.isOn() && computer.isBlinking();
|
||||
}
|
||||
|
||||
public void sendComputerState( PlayerEntity player )
|
||||
{
|
||||
// Send state to client
|
||||
NetworkHandler.sendToPlayer( player, createComputerPacket() );
|
||||
}
|
||||
|
||||
public void sendTerminalState( PlayerEntity player )
|
||||
{
|
||||
// Send terminal state to client
|
||||
NetworkHandler.sendToPlayer( player, createTerminalPacket() );
|
||||
}
|
||||
|
||||
public void broadcastDelete()
|
||||
{
|
||||
// Send deletion to client
|
||||
MinecraftServer server = GameInstanceUtils.getServer();
|
||||
if( server != null )
|
||||
{
|
||||
NetworkHandler.sendToAllPlayers( server, new ComputerDeletedClientMessage( getInstanceID() ) );
|
||||
}
|
||||
}
|
||||
|
||||
public int getID()
|
||||
{
|
||||
return computer.getID();
|
||||
}
|
||||
|
||||
public void setID( int id )
|
||||
{
|
||||
computer.setID( id );
|
||||
}
|
||||
|
||||
public String getLabel()
|
||||
{
|
||||
return computer.getLabel();
|
||||
}
|
||||
|
||||
public void setLabel( String label )
|
||||
{
|
||||
computer.setLabel( label );
|
||||
}
|
||||
|
||||
public int getRedstoneOutput( ComputerSide side )
|
||||
{
|
||||
return computer.getEnvironment()
|
||||
.getExternalRedstoneOutput( side );
|
||||
}
|
||||
|
||||
public void setRedstoneInput( ComputerSide side, int level )
|
||||
{
|
||||
computer.getEnvironment()
|
||||
.setRedstoneInput( side, level );
|
||||
}
|
||||
|
||||
public int getBundledRedstoneOutput( ComputerSide side )
|
||||
{
|
||||
return computer.getEnvironment()
|
||||
.getExternalBundledRedstoneOutput( side );
|
||||
}
|
||||
|
||||
public void setBundledRedstoneInput( ComputerSide side, int combination )
|
||||
{
|
||||
computer.getEnvironment()
|
||||
.setBundledRedstoneInput( side, combination );
|
||||
}
|
||||
|
||||
public void addAPI( ILuaAPI api )
|
||||
{
|
||||
computer.addApi( api );
|
||||
}
|
||||
|
||||
// IComputerEnvironment implementation
|
||||
|
||||
public void setPeripheral( ComputerSide side, IPeripheral peripheral )
|
||||
{
|
||||
computer.getEnvironment()
|
||||
.setPeripheral( side, peripheral );
|
||||
}
|
||||
|
||||
public IPeripheral getPeripheral( ComputerSide side )
|
||||
{
|
||||
return computer.getEnvironment()
|
||||
.getPeripheral( side );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDay()
|
||||
{
|
||||
return (int) ((world.getTimeOfDay() + 6000) / 24000) + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getTimeOfDay()
|
||||
{
|
||||
return (world.getTimeOfDay() + 6000) % 24000 / 1000.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getComputerSpaceLimit()
|
||||
{
|
||||
return ComputerCraft.computerSpaceLimit;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getHostString()
|
||||
{
|
||||
return String.format( "ComputerCraft %s (Minecraft %s)", ComputerCraftAPI.getInstalledVersion(), "1.16.4" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getUserAgent()
|
||||
{
|
||||
return ComputerCraft.MOD_ID + "/" + ComputerCraftAPI.getInstalledVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int assignNewID()
|
||||
{
|
||||
return ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWritableMount createSaveDirMount( String subPath, long capacity )
|
||||
{
|
||||
return ComputerCraftAPI.createSaveDirMount( world, subPath, capacity );
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMount createResourceMount( String domain, String subPath )
|
||||
{
|
||||
return ComputerCraftAPI.createResourceMount( domain, subPath );
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream createResourceFile( String domain, String subPath )
|
||||
{
|
||||
return ComputerCraftAPIImpl.getResourceFile( domain, subPath );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ServerComputerRegistry extends ComputerRegistry<ServerComputer>
|
||||
{
|
||||
public void update()
|
||||
{
|
||||
Iterator<ServerComputer> it = getComputers().iterator();
|
||||
while( it.hasNext() )
|
||||
{
|
||||
ServerComputer computer = it.next();
|
||||
if( computer.hasTimedOut() )
|
||||
{
|
||||
//System.out.println( "TIMED OUT SERVER COMPUTER " + computer.getInstanceID() );
|
||||
computer.unload();
|
||||
computer.broadcastDelete();
|
||||
it.remove();
|
||||
//System.out.println( getComputers().size() + " SERVER COMPUTERS" );
|
||||
}
|
||||
else
|
||||
{
|
||||
computer.update();
|
||||
if( computer.hasTerminalChanged() || computer.hasOutputChanged() )
|
||||
{
|
||||
computer.broadcastState( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
//System.out.println( "RESET SERVER COMPUTERS" );
|
||||
for( ServerComputer computer : getComputers() )
|
||||
{
|
||||
computer.unload();
|
||||
}
|
||||
super.reset();
|
||||
//System.out.println( getComputers().size() + " SERVER COMPUTERS" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( int instanceID, ServerComputer computer )
|
||||
{
|
||||
//System.out.println( "ADD SERVER COMPUTER " + instanceID );
|
||||
super.add( instanceID, computer );
|
||||
computer.broadcastState( true );
|
||||
//System.out.println( getComputers().size() + " SERVER COMPUTERS" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove( int instanceID )
|
||||
{
|
||||
//System.out.println( "REMOVE SERVER COMPUTER " + instanceID );
|
||||
ServerComputer computer = get( instanceID );
|
||||
if( computer != null )
|
||||
{
|
||||
computer.unload();
|
||||
computer.broadcastDelete();
|
||||
}
|
||||
super.remove( instanceID );
|
||||
//System.out.println( getComputers().size() + " SERVER COMPUTERS" );
|
||||
}
|
||||
|
||||
public ServerComputer lookup( int computerID )
|
||||
{
|
||||
if( computerID < 0 )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for( ServerComputer computer : getComputers() )
|
||||
{
|
||||
if( computer.getID() == computerID )
|
||||
{
|
||||
return computer;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.ComputerCraftRegistry;
|
||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
public class ContainerComputer extends ContainerComputerBase
|
||||
{
|
||||
public ContainerComputer( int id, TileComputer tile )
|
||||
{
|
||||
super( ComputerCraftRegistry.ModContainers.COMPUTER, id, tile::isUsableByPlayer, tile.createServerComputer(), tile.getFamily() );
|
||||
}
|
||||
|
||||
public ContainerComputer( int i, PlayerInventory playerInventory, PacketByteBuf packetByteBuf )
|
||||
{
|
||||
super( ComputerCraftRegistry.ModContainers.COMPUTER, i, playerInventory, packetByteBuf );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.ComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.*;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ContainerComputerBase extends ScreenHandler implements IContainerComputer
|
||||
{
|
||||
private final Predicate<PlayerEntity> canUse;
|
||||
private final IComputer computer;
|
||||
private final ComputerFamily family;
|
||||
private final InputState input = new InputState( this );
|
||||
|
||||
protected ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, PlayerInventory player, PacketByteBuf packetByteBuf )
|
||||
{
|
||||
this( type,
|
||||
id,
|
||||
x -> true,
|
||||
getComputer( player, new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ) ),
|
||||
new ComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) ).getFamily() );
|
||||
}
|
||||
|
||||
protected ContainerComputerBase( ScreenHandlerType<? extends ContainerComputerBase> type, int id, Predicate<PlayerEntity> canUse, IComputer computer,
|
||||
ComputerFamily family )
|
||||
{
|
||||
super( type, id );
|
||||
this.canUse = canUse;
|
||||
this.computer = Objects.requireNonNull( computer );
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
protected static IComputer getComputer( PlayerInventory player, ComputerContainerData data )
|
||||
{
|
||||
int id = data.getInstanceId();
|
||||
if( !player.player.world.isClient )
|
||||
{
|
||||
return ComputerCraft.serverComputerRegistry.get( id );
|
||||
}
|
||||
|
||||
ClientComputer computer = ComputerCraft.clientComputerRegistry.get( id );
|
||||
if( computer == null )
|
||||
{
|
||||
ComputerCraft.clientComputerRegistry.add( id, computer = new ClientComputer( id ) );
|
||||
}
|
||||
return computer;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public ComputerFamily getFamily()
|
||||
{
|
||||
return family;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IComputer getComputer()
|
||||
{
|
||||
return computer;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public InputState getInput()
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close( @Nonnull PlayerEntity player )
|
||||
{
|
||||
super.close( player );
|
||||
input.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse( @Nonnull PlayerEntity player )
|
||||
{
|
||||
return canUse.test( player );
|
||||
}
|
||||
}
|
||||
@@ -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.computer.inventory;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.ComputerCraftRegistry;
|
||||
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.network.container.ViewComputerContainerData;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class ContainerViewComputer extends ContainerComputerBase
|
||||
{
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public ContainerViewComputer( int id, ServerComputer computer )
|
||||
{
|
||||
super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player -> canInteractWith( computer, player ), computer, computer.getFamily() );
|
||||
width = height = 0;
|
||||
}
|
||||
|
||||
public ContainerViewComputer( int id, PlayerInventory player, PacketByteBuf packetByteBuf )
|
||||
{
|
||||
super( ComputerCraftRegistry.ModContainers.VIEW_COMPUTER, id, player, packetByteBuf );
|
||||
ViewComputerContainerData data = new ViewComputerContainerData( new PacketByteBuf( packetByteBuf.copy() ) );
|
||||
width = data.getWidth();
|
||||
height = data.getHeight();
|
||||
}
|
||||
|
||||
private static boolean canInteractWith( @Nonnull ServerComputer computer, @Nonnull PlayerEntity player )
|
||||
{
|
||||
// If this computer no longer exists then discard it.
|
||||
if( ComputerCraft.serverComputerRegistry.get( computer.getInstanceID() ) != computer )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're a command computer then ensure we're in creative
|
||||
return computer.getFamily() != ComputerFamily.COMMAND || TileCommandComputer.isUsable( player );
|
||||
}
|
||||
|
||||
public int getWidth()
|
||||
{
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight()
|
||||
{
|
||||
return height;
|
||||
}
|
||||
}
|
||||
@@ -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.items;
|
||||
|
||||
import dan200.computercraft.shared.ComputerCraftRegistry;
|
||||
import dan200.computercraft.shared.computer.blocks.TileComputer;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public final class ComputerItemFactory
|
||||
{
|
||||
private ComputerItemFactory() {}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack create( TileComputer tile )
|
||||
{
|
||||
return create( tile.getComputerID(), tile.getLabel(), tile.getFamily() );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ItemStack create( int id, String label, ComputerFamily family )
|
||||
{
|
||||
switch( family )
|
||||
{
|
||||
case NORMAL:
|
||||
return ComputerCraftRegistry.ModItems.COMPUTER_NORMAL.create( id, label );
|
||||
case ADVANCED:
|
||||
return ComputerCraftRegistry.ModItems.COMPUTER_ADVANCED.create( id, label );
|
||||
case COMMAND:
|
||||
return ComputerCraftRegistry.ModItems.COMPUTER_COMMAND.create( id, label );
|
||||
default:
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.items;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public interface IComputerItem
|
||||
{
|
||||
String NBT_ID = "ComputerId";
|
||||
|
||||
default int getComputerID( @Nonnull ItemStack stack )
|
||||
{
|
||||
NbtCompound nbt = stack.getNbt();
|
||||
return nbt != null && nbt.contains( NBT_ID ) ? nbt.getInt( NBT_ID ) : -1;
|
||||
}
|
||||
|
||||
default String getLabel( @Nonnull ItemStack stack )
|
||||
{
|
||||
return stack.hasCustomName() ? stack.getName()
|
||||
.getString() : null;
|
||||
}
|
||||
|
||||
ComputerFamily getFamily();
|
||||
|
||||
ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family );
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.items;
|
||||
|
||||
import dan200.computercraft.shared.computer.blocks.BlockComputer;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.LiteralText;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class ItemComputer extends ItemComputerBase
|
||||
{
|
||||
public ItemComputer( BlockComputer block, Settings settings )
|
||||
{
|
||||
super( block, settings );
|
||||
}
|
||||
|
||||
public ItemStack create( int id, String label )
|
||||
{
|
||||
ItemStack result = new ItemStack( this );
|
||||
if( id >= 0 )
|
||||
{
|
||||
result.getOrCreateNbt()
|
||||
.putInt( NBT_ID, id );
|
||||
}
|
||||
if( label != null )
|
||||
{
|
||||
result.setCustomName( new LiteralText( label ) );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack withFamily( @Nonnull ItemStack stack, @Nonnull ComputerFamily family )
|
||||
{
|
||||
ItemStack result = ComputerItemFactory.create( getComputerID( stack ), null, family );
|
||||
if( stack.hasCustomName() )
|
||||
{
|
||||
result.setCustomName( stack.getName() );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.items;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
import dan200.computercraft.api.media.IMedia;
|
||||
import dan200.computercraft.shared.computer.blocks.BlockComputerBase;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.LiteralText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class ItemComputerBase extends BlockItem implements IComputerItem, IMedia
|
||||
{
|
||||
private final ComputerFamily family;
|
||||
|
||||
public ItemComputerBase( BlockComputerBase<?> block, Settings settings )
|
||||
{
|
||||
super( block, settings );
|
||||
family = block.getFamily();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTooltip( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List<Text> list, @Nonnull TooltipContext options )
|
||||
{
|
||||
if( options.isAdvanced() || getLabel( stack ) == null )
|
||||
{
|
||||
int id = getComputerID( stack );
|
||||
if( id >= 0 )
|
||||
{
|
||||
list.add( new TranslatableText( "gui.computercraft.tooltip.computer_id", id ).formatted( Formatting.GRAY ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel( @Nonnull ItemStack stack )
|
||||
{
|
||||
return IComputerItem.super.getLabel( stack );
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ComputerFamily getFamily()
|
||||
{
|
||||
return family;
|
||||
}
|
||||
|
||||
// IMedia implementation
|
||||
|
||||
@Override
|
||||
public boolean setLabel( @Nonnull ItemStack stack, String label )
|
||||
{
|
||||
if( label != null )
|
||||
{
|
||||
stack.setCustomName( new LiteralText( label ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.removeCustomName();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMount createDataMount( @Nonnull ItemStack stack, @Nonnull World world )
|
||||
{
|
||||
ComputerFamily family = getFamily();
|
||||
if( family != ComputerFamily.COMMAND )
|
||||
{
|
||||
int id = getComputerID( stack );
|
||||
if( id >= 0 )
|
||||
{
|
||||
return ComputerCraftAPI.createSaveDirMount( world, "computer/" + id, ComputerCraft.computerSpaceLimit );
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.recipe;
|
||||
|
||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||
import net.minecraft.inventory.CraftingInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.ShapedRecipe;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
/**
|
||||
* Represents a recipe which converts a computer from one form into another.
|
||||
*/
|
||||
public abstract class ComputerConvertRecipe extends ShapedRecipe
|
||||
{
|
||||
private final String group;
|
||||
|
||||
public ComputerConvertRecipe( Identifier identifier, String group, int width, int height, DefaultedList<Ingredient> ingredients, ItemStack result )
|
||||
{
|
||||
super( identifier, group, width, height, ingredients, result );
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getGroup()
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches( @Nonnull CraftingInventory inventory, @Nonnull World world )
|
||||
{
|
||||
if( !super.matches( inventory, world ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for( int i = 0; i < inventory.size(); i++ )
|
||||
{
|
||||
if( inventory.getStack( i )
|
||||
.getItem() instanceof IComputerItem )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack craft( @Nonnull CraftingInventory inventory )
|
||||
{
|
||||
// Find our computer item and convert it.
|
||||
for( int i = 0; i < inventory.size(); i++ )
|
||||
{
|
||||
ItemStack stack = inventory.getStack( i );
|
||||
if( stack.getItem() instanceof IComputerItem )
|
||||
{
|
||||
return convert( (IComputerItem) stack.getItem(), stack );
|
||||
}
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected abstract ItemStack convert( @Nonnull IComputerItem item, @Nonnull ItemStack stack );
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.recipe;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.util.RecipeUtil;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.RecipeSerializer;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.JsonHelper;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public abstract class ComputerFamilyRecipe extends ComputerConvertRecipe
|
||||
{
|
||||
private final ComputerFamily family;
|
||||
|
||||
public ComputerFamilyRecipe( Identifier identifier, String group, int width, int height, DefaultedList<Ingredient> ingredients, ItemStack result,
|
||||
ComputerFamily family )
|
||||
{
|
||||
super( identifier, group, width, height, ingredients, result );
|
||||
this.family = family;
|
||||
}
|
||||
|
||||
public ComputerFamily getFamily()
|
||||
{
|
||||
return family;
|
||||
}
|
||||
|
||||
public abstract static class Serializer<T extends ComputerFamilyRecipe> implements RecipeSerializer<T>
|
||||
{
|
||||
@Nonnull
|
||||
@Override
|
||||
public T read( @Nonnull Identifier identifier, @Nonnull JsonObject json )
|
||||
{
|
||||
String group = JsonHelper.getString( json, "group", "" );
|
||||
ComputerFamily family = RecipeUtil.getFamily( json, "family" );
|
||||
|
||||
RecipeUtil.ShapedTemplate template = RecipeUtil.getTemplate( json );
|
||||
ItemStack result = getItem( JsonHelper.getObject( json, "result" ) );
|
||||
|
||||
return create( identifier, group, template.width, template.height, template.ingredients, result, family );
|
||||
}
|
||||
|
||||
protected abstract T create( Identifier identifier, String group, int width, int height, DefaultedList<Ingredient> ingredients, ItemStack result,
|
||||
ComputerFamily family );
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public T read( @Nonnull Identifier identifier, @Nonnull PacketByteBuf buf )
|
||||
{
|
||||
int width = buf.readVarInt();
|
||||
int height = buf.readVarInt();
|
||||
String group = buf.readString( Short.MAX_VALUE );
|
||||
|
||||
DefaultedList<Ingredient> ingredients = DefaultedList.ofSize( width * height, Ingredient.EMPTY );
|
||||
for( int i = 0; i < ingredients.size(); i++ )
|
||||
{
|
||||
ingredients.set( i, Ingredient.fromPacket( buf ) );
|
||||
}
|
||||
|
||||
ItemStack result = buf.readItemStack();
|
||||
ComputerFamily family = buf.readEnumConstant( ComputerFamily.class );
|
||||
return create( identifier, group, width, height, ingredients, result, family );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write( @Nonnull PacketByteBuf buf, @Nonnull T recipe )
|
||||
{
|
||||
buf.writeVarInt( recipe.getWidth() );
|
||||
buf.writeVarInt( recipe.getHeight() );
|
||||
buf.writeString( recipe.getGroup() );
|
||||
for( Ingredient ingredient : recipe.getIngredients() )
|
||||
{
|
||||
ingredient.write( buf );
|
||||
}
|
||||
buf.writeItemStack( recipe.getOutput() );
|
||||
buf.writeEnumConstant( recipe.getFamily() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.recipe;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.recipe.Ingredient;
|
||||
import net.minecraft.recipe.RecipeSerializer;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public class ComputerUpgradeRecipe extends ComputerFamilyRecipe
|
||||
{
|
||||
public static final RecipeSerializer<ComputerUpgradeRecipe> SERIALIZER =
|
||||
new ComputerFamilyRecipe.Serializer<ComputerUpgradeRecipe>()
|
||||
{
|
||||
@Override
|
||||
protected ComputerUpgradeRecipe create( Identifier identifier, String group, int width, int height, DefaultedList<Ingredient> ingredients,
|
||||
ItemStack result, ComputerFamily family )
|
||||
{
|
||||
return new ComputerUpgradeRecipe( identifier, group, width, height, ingredients, result, family );
|
||||
}
|
||||
};
|
||||
|
||||
public ComputerUpgradeRecipe( Identifier identifier, String group, int width, int height, DefaultedList<Ingredient> ingredients, ItemStack result,
|
||||
ComputerFamily family )
|
||||
{
|
||||
super( identifier, group, width, height, ingredients, result, family );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
protected ItemStack convert( @Nonnull IComputerItem item, @Nonnull ItemStack stack )
|
||||
{
|
||||
return item.withFamily( stack, getFamily() );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public RecipeSerializer<?> getSerializer()
|
||||
{
|
||||
return SERIALIZER;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user