1
0
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:
Merith
2021-07-11 01:33:21 +00:00
parent cbff505297
commit 9bc4e9530c
435 changed files with 54771 additions and 91 deletions

View File

@@ -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" );
}
}
}

View File

@@ -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;
}
}

View File

@@ -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() );
}
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}

View File

@@ -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 );
}
}
}

View File

@@ -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 );
}
}

View File

@@ -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() );
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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
}

View File

@@ -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 );
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}

View File

@@ -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 );
}
}

View File

@@ -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 } );
}
}

View File

@@ -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;
}
}

View File

@@ -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 );
}
}

View File

@@ -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;
}
}

View File

@@ -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 );
}
}

View File

@@ -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 );
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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 );
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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 );
}

View File

@@ -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() );
}
}
}

View File

@@ -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;
}
}