1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-10 15:54:00 +00:00

Merge branch 'master' into mc-1.14.x

This commit is contained in:
SquidDev 2020-05-04 09:39:54 +01:00
commit 052cf8ee7d
31 changed files with 314 additions and 96 deletions

View File

@ -17,6 +17,9 @@
{ {
"condition": "computercraft:block_named" "condition": "computercraft:block_named"
}, },
{
"condition": "computercraft:has_id"
},
{ {
"condition": "minecraft:inverted", "condition": "minecraft:inverted",
"term": { "term": {

View File

@ -17,6 +17,9 @@
{ {
"condition": "computercraft:block_named" "condition": "computercraft:block_named"
}, },
{
"condition": "computercraft:has_id"
},
{ {
"condition": "minecraft:inverted", "condition": "minecraft:inverted",
"term": { "term": {

View File

@ -17,6 +17,9 @@
{ {
"condition": "computercraft:block_named" "condition": "computercraft:block_named"
}, },
{
"condition": "computercraft:has_id"
},
{ {
"condition": "minecraft:inverted", "condition": "minecraft:inverted",
"term": { "term": {

View File

@ -17,6 +17,9 @@
{ {
"condition": "computercraft:block_named" "condition": "computercraft:block_named"
}, },
{
"condition": "computercraft:has_id"
},
{ {
"condition": "minecraft:inverted", "condition": "minecraft:inverted",
"term": { "term": {

View File

@ -55,10 +55,9 @@ public final class FixedWidthFontRenderer
return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3); return (float) ((rgb[0] + rgb[1] + rgb[2]) / 3);
} }
private static int getColour( char c ) private static int getColour( char c, Colour def )
{ {
int i = "0123456789abcdef".indexOf( c ); return 15 - Terminal.getColour( c, def );
return i < 0 ? 0 : 15 - i;
} }
private static void drawChar( BufferBuilder buffer, float x, float y, int index, float r, float g, float b ) private static void drawChar( BufferBuilder buffer, float x, float y, int index, float r, float g, float b )
@ -92,7 +91,7 @@ public final class FixedWidthFontRenderer
private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex ) private static void drawQuad( BufferBuilder buffer, float x, float y, float width, float height, Palette palette, boolean greyscale, char colourIndex )
{ {
double[] colour = palette.getColour( getColour( colourIndex ) ); double[] colour = palette.getColour( getColour( colourIndex, Colour.Black ) );
float r, g, b; float r, g, b;
if( greyscale ) if( greyscale )
{ {
@ -160,7 +159,7 @@ public final class FixedWidthFontRenderer
for( int i = 0; i < text.length(); i++ ) for( int i = 0; i < text.length(); i++ )
{ {
double[] colour = palette.getColour( getColour( textColour.charAt( i ) ) ); double[] colour = palette.getColour( getColour( textColour.charAt( i ), Colour.White ) );
float r, g, b; float r, g, b;
if( greyscale ) if( greyscale )
{ {

View File

@ -5,18 +5,20 @@
*/ */
package dan200.computercraft.core.terminal; package dan200.computercraft.core.terminal;
import dan200.computercraft.shared.util.Colour;
import dan200.computercraft.shared.util.Palette; import dan200.computercraft.shared.util.Palette;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
public class Terminal public class Terminal
{ {
private static final String base16 = "0123456789abcdef"; private static final String base16 = "0123456789abcdef";
private int m_cursorX; private int m_cursorX = 0;
private int m_cursorY; private int m_cursorY = 0;
private boolean m_cursorBlink; private boolean m_cursorBlink = false;
private int m_cursorColour; private int m_cursorColour = 0;
private int m_cursorBackgroundColour; private int m_cursorBackgroundColour = 15;
private int m_width; private int m_width;
private int m_height; private int m_height;
@ -25,9 +27,9 @@ public class Terminal
private TextBuffer[] m_textColour; private TextBuffer[] m_textColour;
private TextBuffer[] m_backgroundColour; private TextBuffer[] m_backgroundColour;
private final Palette m_palette; private final Palette m_palette = new Palette();
private boolean m_changed; private boolean m_changed = false;
private final Runnable onChanged; private final Runnable onChanged;
public Terminal( int width, int height ) public Terminal( int width, int height )
@ -41,9 +43,6 @@ public class Terminal
m_height = height; m_height = height;
onChanged = changedCallback; onChanged = changedCallback;
m_cursorColour = 0;
m_cursorBackgroundColour = 15;
m_text = new TextBuffer[m_height]; m_text = new TextBuffer[m_height];
m_textColour = new TextBuffer[m_height]; m_textColour = new TextBuffer[m_height];
m_backgroundColour = new TextBuffer[m_height]; m_backgroundColour = new TextBuffer[m_height];
@ -53,14 +52,6 @@ public class Terminal
m_textColour[i] = new TextBuffer( base16.charAt( m_cursorColour ), m_width ); m_textColour[i] = new TextBuffer( base16.charAt( m_cursorColour ), m_width );
m_backgroundColour[i] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width ); m_backgroundColour[i] = new TextBuffer( base16.charAt( m_cursorBackgroundColour ), m_width );
} }
m_cursorX = 0;
m_cursorY = 0;
m_cursorBlink = false;
m_changed = false;
m_palette = new Palette();
} }
public synchronized void reset() public synchronized void reset()
@ -336,6 +327,62 @@ public class Terminal
m_changed = false; m_changed = false;
} }
public synchronized void write( PacketBuffer buffer )
{
buffer.writeInt( m_cursorX );
buffer.writeInt( m_cursorY );
buffer.writeBoolean( m_cursorBlink );
buffer.writeByte( m_cursorBackgroundColour << 4 | m_cursorColour );
for( int y = 0; y < m_height; y++ )
{
TextBuffer text = m_text[y];
TextBuffer textColour = m_textColour[y];
TextBuffer backColour = m_backgroundColour[y];
for( int x = 0; x < m_width; x++ )
{
buffer.writeByte( text.charAt( x ) & 0xFF );
buffer.writeByte( getColour(
backColour.charAt( x ), Colour.Black ) << 4 |
getColour( textColour.charAt( x ), Colour.White )
);
}
}
m_palette.write( buffer );
}
public synchronized void read( PacketBuffer buffer )
{
m_cursorX = buffer.readInt();
m_cursorY = buffer.readInt();
m_cursorBlink = buffer.readBoolean();
byte cursorColour = buffer.readByte();
m_cursorBackgroundColour = (cursorColour >> 4) & 0xF;
m_cursorColour = cursorColour & 0xF;
for( int y = 0; y < m_height; y++ )
{
TextBuffer text = m_text[y];
TextBuffer textColour = m_textColour[y];
TextBuffer backColour = m_backgroundColour[y];
for( int x = 0; x < m_width; x++ )
{
text.setChar( x, (char) (buffer.readByte() & 0xFF) );
byte colour = buffer.readByte();
backColour.setChar( x, base16.charAt( (colour >> 4) & 0xF ) );
textColour.setChar( x, base16.charAt( colour & 0xF ) );
}
}
m_palette.read( buffer );
setChanged();
}
public synchronized CompoundNBT writeToNBT( CompoundNBT nbt ) public synchronized CompoundNBT writeToNBT( CompoundNBT nbt )
{ {
nbt.putInt( "term_cursorX", m_cursorX ); nbt.putInt( "term_cursorX", m_cursorX );
@ -349,10 +396,8 @@ public class Terminal
nbt.putString( "term_textColour_" + n, m_textColour[n].toString() ); nbt.putString( "term_textColour_" + n, m_textColour[n].toString() );
nbt.putString( "term_textBgColour_" + n, m_backgroundColour[n].toString() ); nbt.putString( "term_textBgColour_" + n, m_backgroundColour[n].toString() );
} }
if( m_palette != null )
{
m_palette.writeToNBT( nbt ); m_palette.writeToNBT( nbt );
}
return nbt; return nbt;
} }
@ -382,10 +427,15 @@ public class Terminal
m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) ); m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) );
} }
} }
if( m_palette != null )
{
m_palette.readFromNBT( nbt ); m_palette.readFromNBT( nbt );
}
setChanged(); setChanged();
} }
public static int getColour( char c, Colour def )
{
if( c >= '0' && c <= '9' ) return c - '0';
if( c >= 'a' && c <= 'f' ) return c - 'a' + 10;
return 15 - def.ordinal();
}
} }

View File

@ -8,6 +8,7 @@ package dan200.computercraft.data;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition;
import dan200.computercraft.shared.data.HasComputerIdLootCondition;
import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.data.DataGenerator; import net.minecraft.data.DataGenerator;
@ -67,6 +68,7 @@ public class LootTables extends LootTableProvider
.addEntry( DynamicLootEntry.func_216162_a( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) ) .addEntry( DynamicLootEntry.func_216162_a( new ResourceLocation( ComputerCraft.MOD_ID, "computer" ) ) )
.acceptCondition( Alternative.builder( .acceptCondition( Alternative.builder(
BlockNamedEntityLootCondition.builder(), BlockNamedEntityLootCondition.builder(),
HasComputerIdLootCondition.builder(),
PlayerCreativeLootCondition.builder().inverted() PlayerCreativeLootCondition.builder().inverted()
) ) ) )
).build() ); ).build() );

View File

@ -6,7 +6,9 @@
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import io.netty.buffer.Unpooled;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
public class ClientTerminal implements ITerminal public class ClientTerminal implements ITerminal
{ {
@ -53,7 +55,7 @@ public class ClientTerminal implements ITerminal
{ {
CompoundNBT terminal = nbt.getCompound( "terminal" ); CompoundNBT terminal = nbt.getCompound( "terminal" );
resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) ); resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) );
m_terminal.readFromNBT( terminal ); m_terminal.read( new PacketBuffer( Unpooled.wrappedBuffer( terminal.getByteArray( "term_contents" ) ) ) );
} }
else else
{ {

View File

@ -5,8 +5,12 @@
*/ */
package dan200.computercraft.shared.common; package dan200.computercraft.shared.common;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.terminal.Terminal;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@ -83,17 +87,28 @@ public class ServerTerminal implements ITerminal
return m_colour; return m_colour;
} }
// Networking stuff
public void writeDescription( CompoundNBT nbt ) public void writeDescription( CompoundNBT nbt )
{ {
nbt.putBoolean( "colour", m_colour ); nbt.putBoolean( "colour", m_colour );
if( m_terminal != null ) if( m_terminal != null )
{ {
// We have a 10 byte header (2 integer positions, then blinking and current colours), followed by the
// contents and palette.
// Yes, this serialisation code is terrible, but we need to serialise to NBT in order to work with monitors
// (or rather tile entity serialisation).
final int length = 10 + (2 * m_terminal.getWidth() * m_terminal.getHeight()) + (16 * 3);
ByteBuf buffer = Unpooled.buffer( length );
m_terminal.write( new PacketBuffer( buffer ) );
if( buffer.writableBytes() != 0 )
{
ComputerCraft.log.warn( "Should have written {} bytes, but have {} ({} remaining).", length, buffer.writerIndex(), buffer.writableBytes() );
}
CompoundNBT terminal = new CompoundNBT(); CompoundNBT terminal = new CompoundNBT();
terminal.putInt( "term_width", m_terminal.getWidth() ); terminal.putInt( "term_width", m_terminal.getWidth() );
terminal.putInt( "term_height", m_terminal.getHeight() ); terminal.putInt( "term_height", m_terminal.getHeight() );
m_terminal.writeToNBT( terminal ); terminal.putByteArray( "term_contents", buffer.array() );
nbt.put( "terminal", terminal ); nbt.put( "terminal", terminal );
} }
} }

View File

@ -19,9 +19,7 @@ public final class ComputerItemFactory
@Nonnull @Nonnull
public static ItemStack create( TileComputer tile ) public static ItemStack create( TileComputer tile )
{ {
String label = tile.getLabel(); return create( tile.getComputerID(), tile.getLabel(), tile.getFamily() );
int id = label != null ? tile.getComputerID() : -1;
return create( id, label, tile.getFamily() );
} }
@Nonnull @Nonnull

View File

@ -37,7 +37,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte
@Override @Override
public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List<ITextComponent> list, @Nonnull ITooltipFlag options ) public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List<ITextComponent> list, @Nonnull ITooltipFlag options )
{ {
if( options.isAdvanced() ) if( options.isAdvanced() || getLabel( stack ) == null )
{ {
int id = getComputerID( stack ); int id = getComputerID( stack );
if( id >= 0 ) if( id >= 0 )

View File

@ -0,0 +1,48 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.data;
import dan200.computercraft.shared.computer.blocks.IComputerTile;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.storage.loot.LootContext;
import net.minecraft.world.storage.loot.LootParameter;
import net.minecraft.world.storage.loot.LootParameters;
import net.minecraft.world.storage.loot.conditions.ILootCondition;
import javax.annotation.Nonnull;
import java.util.Collections;
import java.util.Set;
/**
* A loot condition which checks if the tile entity has has a non-0 ID.
*/
public final class HasComputerIdLootCondition implements ILootCondition
{
public static final HasComputerIdLootCondition INSTANCE = new HasComputerIdLootCondition();
private HasComputerIdLootCondition()
{
}
@Override
public boolean test( LootContext lootContext )
{
TileEntity tile = lootContext.get( LootParameters.BLOCK_ENTITY );
return tile instanceof IComputerTile && ((IComputerTile) tile).getComputerID() >= 0;
}
@Nonnull
@Override
public Set<LootParameter<?>> getRequiredParameters()
{
return Collections.singleton( LootParameters.BLOCK_ENTITY );
}
public static IBuilder builder()
{
return () -> INSTANCE;
}
}

View File

@ -184,7 +184,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I
@Override @Override
public void addInformation( @Nonnull ItemStack stack, @Nullable World world, List<ITextComponent> list, ITooltipFlag flag ) public void addInformation( @Nonnull ItemStack stack, @Nullable World world, List<ITextComponent> list, ITooltipFlag flag )
{ {
if( flag.isAdvanced() ) if( flag.isAdvanced() || getLabel( stack ) == null )
{ {
int id = getComputerID( stack ); int id = getComputerID( stack );
if( id >= 0 ) if( id >= 0 )

View File

@ -20,6 +20,7 @@ import dan200.computercraft.shared.computer.core.IContainerComputer;
import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition;
import dan200.computercraft.shared.data.ConstantLootConditionSerializer; import dan200.computercraft.shared.data.ConstantLootConditionSerializer;
import dan200.computercraft.shared.data.HasComputerIdLootCondition;
import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.media.items.RecordMedia;
import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.NetworkHandler;
@ -72,6 +73,12 @@ public final class ComputerCraftProxyCommon
PlayerCreativeLootCondition.class, PlayerCreativeLootCondition.class,
PlayerCreativeLootCondition.INSTANCE PlayerCreativeLootCondition.INSTANCE
) ); ) );
LootConditionManager.registerCondition( ConstantLootConditionSerializer.of(
new ResourceLocation( ComputerCraft.MOD_ID, "has_id" ),
HasComputerIdLootCondition.class,
HasComputerIdLootCondition.INSTANCE
) );
} }
private static void registerProviders() private static void registerProviders()

View File

@ -6,6 +6,7 @@
package dan200.computercraft.shared.turtle.items; package dan200.computercraft.shared.turtle.items;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.turtle.ITurtleAccess;
import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade;
import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerFamily;
@ -22,18 +23,13 @@ public final class TurtleItemFactory
@Nonnull @Nonnull
public static ItemStack create( ITurtleTile turtle ) public static ItemStack create( ITurtleTile turtle )
{ {
ITurtleUpgrade leftUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Left ); ITurtleAccess access = turtle.getAccess();
ITurtleUpgrade rightUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Right );
String label = turtle.getLabel(); return create(
if( label == null ) turtle.getComputerID(), turtle.getLabel(), turtle.getColour(), turtle.getFamily(),
{ access.getUpgrade( TurtleSide.Left ), access.getUpgrade( TurtleSide.Right ),
return create( -1, null, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, 0, turtle.getOverlay() ); access.getFuelLevel(), turtle.getOverlay()
} );
int id = turtle.getComputerID();
int fuelLevel = turtle.getAccess().getFuelLevel();
return create( id, label, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, fuelLevel, turtle.getOverlay() );
} }
@Nonnull @Nonnull

View File

@ -6,6 +6,7 @@
package dan200.computercraft.shared.util; package dan200.computercraft.shared.util;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.PacketBuffer;
public class Palette public class Palette
{ {
@ -78,6 +79,22 @@ public class Palette
}; };
} }
public void write( PacketBuffer buffer )
{
for( double[] colour : colours )
{
for( double channel : colour ) buffer.writeByte( (int) (channel * 0xFF) & 0xFF );
}
}
public void read( PacketBuffer buffer )
{
for( double[] colour : colours )
{
for( int i = 0; i < colour.length; i++ ) colour[i] = buffer.readByte() * 255;
}
}
public CompoundNBT writeToNBT( CompoundNBT nbt ) public CompoundNBT writeToNBT( CompoundNBT nbt )
{ {
int[] rgb8 = new int[colours.length]; int[] rgb8 = new int[colours.length];

View File

@ -44,5 +44,5 @@ chat.computercraft.wired_modem.peripheral_disconnected=Perifer enhed "%s" koblet
# Misc tooltips # Misc tooltips
gui.computercraft.tooltip.copy=Kopier til udklipsholder gui.computercraft.tooltip.copy=Kopier til udklipsholder
gui.computercraft.tooltip.computer_id=(Computer-ID: %s) gui.computercraft.tooltip.computer_id=Computer-ID: %s
gui.computercraft.tooltip.disk_id=(Disk-ID: %s) gui.computercraft.tooltip.disk_id=Disk-ID: %s

View File

@ -141,8 +141,8 @@
"tracking_field.computercraft.coroutines_dead.name": "Koroutinen gelöscht", "tracking_field.computercraft.coroutines_dead.name": "Koroutinen gelöscht",
"gui.computercraft.tooltip.copy": "In die Zwischenablage kopieren", "gui.computercraft.tooltip.copy": "In die Zwischenablage kopieren",
"gui.computercraft.tooltip.computer_id": "(Computer ID: %s)", "gui.computercraft.tooltip.computer_id": "Computer ID: %s",
"gui.computercraft.tooltip.disk_id": "(Disketten ID: %s)", "gui.computercraft.tooltip.disk_id": "Disketten ID: %s",
"gui.computercraft.config.computer_space_limit": "Speicherplatz von Computern (bytes)", "gui.computercraft.config.computer_space_limit": "Speicherplatz von Computern (bytes)",
"gui.computercraft.config.floppy_space_limit": "Speicherplatz von Disketten (bytes)", "gui.computercraft.config.floppy_space_limit": "Speicherplatz von Disketten (bytes)",

View File

@ -143,8 +143,8 @@
"tracking_field.computercraft.coroutines_dead.name": "Coroutines disposed", "tracking_field.computercraft.coroutines_dead.name": "Coroutines disposed",
"gui.computercraft.tooltip.copy": "Copy to clipboard", "gui.computercraft.tooltip.copy": "Copy to clipboard",
"gui.computercraft.tooltip.computer_id": "(Computer ID: %s)", "gui.computercraft.tooltip.computer_id": "Computer ID: %s",
"gui.computercraft.tooltip.disk_id": "(Disk ID: %s)", "gui.computercraft.tooltip.disk_id": "Disk ID: %s",
"gui.computercraft.config.computer_space_limit": "Computer space limit (bytes)", "gui.computercraft.config.computer_space_limit": "Computer space limit (bytes)",
"gui.computercraft.config.floppy_space_limit": "Floppy Disk space limit (bytes)", "gui.computercraft.config.floppy_space_limit": "Floppy Disk space limit (bytes)",

View File

@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=코루틴 처리됨
# Misc tooltips # Misc tooltips
gui.computercraft.tooltip.copy=클립보드에 복사 gui.computercraft.tooltip.copy=클립보드에 복사
gui.computercraft.tooltip.computer_id=(컴퓨터 ID: %s) gui.computercraft.tooltip.computer_id=컴퓨터 ID: %s
gui.computercraft.tooltip.disk_id=(디스크 ID: %s) gui.computercraft.tooltip.disk_id=디스크 ID: %s
# Config options # Config options
gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (바이트) gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (바이트)

View File

@ -143,8 +143,8 @@
"tracking_field.computercraft.coroutines_dead.name": "协同处理", "tracking_field.computercraft.coroutines_dead.name": "协同处理",
"gui.computercraft.tooltip.copy": "复制到剪贴板", "gui.computercraft.tooltip.copy": "复制到剪贴板",
"gui.computercraft.tooltip.computer_id": "(计算机ID: %s)", "gui.computercraft.tooltip.computer_id": "计算机ID: %s",
"gui.computercraft.tooltip.disk_id": "(磁盘ID: %s)", "gui.computercraft.tooltip.disk_id": "磁盘ID: %s",
"gui.computercraft.config.computer_space_limit": "计算机空间限制(字节)", "gui.computercraft.config.computer_space_limit": "计算机空间限制(字节)",
"gui.computercraft.config.floppy_space_limit": "软盘空间限制(字节)", "gui.computercraft.config.floppy_space_limit": "软盘空间限制(字节)",

View File

@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=协同处理
# Misc tooltips # Misc tooltips
gui.computercraft.tooltip.copy=复制到剪贴板 gui.computercraft.tooltip.copy=复制到剪贴板
gui.computercraft.tooltip.computer_id=(计算机ID: %s) gui.computercraft.tooltip.computer_id=计算机ID: %s
gui.computercraft.tooltip.disk_id=(磁盘ID: %s) gui.computercraft.tooltip.disk_id=磁盘ID: %s
# Config options # Config options
gui.computercraft:config.computer_space_limit=计算机空间限制(字节) gui.computercraft:config.computer_space_limit=计算机空间限制(字节)

View File

@ -64,24 +64,33 @@ function isPresent(name)
return false return false
end end
--- Get the type of the peripheral with the given name. --- Get the type of a wrapped peripheral, or a peripheral with the given name.
-- --
-- @tparam string name The name of the peripheral to find. -- @tparam string|table peripheral The name of the peripheral to find, or a
-- wrapped peripheral instance.
-- @treturn string|nil The peripheral's type, or `nil` if it is not present. -- @treturn string|nil The peripheral's type, or `nil` if it is not present.
function getType(name) function getType(peripheral)
expect(1, name, "string") expect(1, peripheral, "string", "table")
if native.isPresent(name) then if type(peripheral) == "string" then -- Peripheral name passed
return native.getType(name) if native.isPresent(peripheral) then
return native.getType(peripheral)
end end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and if native.getType(side) == "modem" and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", name) native.call(side, "isPresentRemote", peripheral)
then then
return native.call(side, "getTypeRemote", name) return native.call(side, "getTypeRemote", peripheral)
end end
end end
return nil return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.type) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.type
end
end end
--- Get all available methods for the peripheral with the given name. --- Get all available methods for the peripheral with the given name.
@ -105,6 +114,19 @@ function getMethods(name)
return nil return nil
end end
--- Get the name of a peripheral wrapped with @{peripheral.wrap}.
--
-- @tparam table peripheral The peripheral to get the name of.
-- @treturn string The name of the given peripheral.
function getName(peripheral)
expect(1, peripheral, "table")
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.name
end
--- Call a method on the peripheral with the given name. --- Call a method on the peripheral with the given name.
-- --
-- @tparam string name The name of the peripheral to invoke the method on. -- @tparam string name The name of the peripheral to invoke the method on.
@ -148,7 +170,11 @@ function wrap(name)
return nil return nil
end end
local result = {} local result = setmetatable({}, {
__name = "peripheral",
name = name,
type = peripheral.getType(name),
})
for _, method in ipairs(methods) do for _, method in ipairs(methods) do
result[method] = function(...) result[method] = function(...)
return peripheral.call(name, method, ...) return peripheral.call(name, method, ...)

View File

@ -29,7 +29,7 @@ local tReceivedMessageTimeouts = {}
local tHostnames = {} local tHostnames = {}
--- Opens a modem with the given @{peripheral} name, allowing it to send and --- Opens a modem with the given @{peripheral} name, allowing it to send and
--- receive messages over rednet. -- receive messages over rednet.
-- --
-- This will open the modem on two channels: one which has the same -- This will open the modem on two channels: one which has the same
-- @{os.getComputerID|ID} as the computer, and another on -- @{os.getComputerID|ID} as the computer, and another on
@ -246,7 +246,7 @@ function host(sProtocol, sHostname)
end end
--- Stop @{rednet.host|hosting} a specific protocol, meaning it will no longer --- Stop @{rednet.host|hosting} a specific protocol, meaning it will no longer
--- respond to @{rednet.lookup} requests. -- respond to @{rednet.lookup} requests.
-- --
-- @tparam string sProtocol The protocol to unregister your self from. -- @tparam string sProtocol The protocol to unregister your self from.
function unhost(sProtocol) function unhost(sProtocol)

View File

@ -3,6 +3,7 @@ The peripheral API is for interacting with external peripheral devices. Type "he
Functions in the peripheral API: Functions in the peripheral API:
peripheral.getNames() peripheral.getNames()
peripheral.isPresent( name ) peripheral.isPresent( name )
peripheral.getName( peripheral )
peripheral.getType( name ) peripheral.getType( name )
peripheral.getMethods( name ) peripheral.getMethods( name )
peripheral.call( name, methodName, param1, param2, etc ) peripheral.call( name, methodName, param1, param2, etc )

View File

@ -28,7 +28,7 @@ local monitor = peripheral.wrap(sName)
local previousTerm = term.redirect(monitor) local previousTerm = term.redirect(monitor)
local co = coroutine.create(function() local co = coroutine.create(function()
shell.run(sProgram, table.unpack(tArgs, 3)) (shell.execute or shell.run)(sProgram, table.unpack(tArgs, 3))
end) end)
local function resume(...) local function resume(...)

View File

@ -130,8 +130,25 @@ else
bgColour = colours.black bgColour = colours.black
end end
local function run(_sCommand, ...) --- Run a program with the supplied arguments.
local sPath = shell.resolveProgram(_sCommand) --
-- Unlike @{shell.run}, each argument is passed to the program verbatim. While
-- `shell.run("echo", "b c")` runs `echo` with `b` and `c`,
-- `shell.execute("echo", "b c")` runs `echo` with a single argument `b c`.
--
-- @tparam string command The program to execute.
-- @tparam string ... Arguments to this program.
-- @treturn boolean Whether the program exited successfully.
-- @usage Run `paint my-image` from within your program:
--
-- shell.execute("paint", "my-image")
function shell.execute(command, ...)
expect(1, command, "string")
for i = 1, select('#', ...) do
expect(i + 1, select(i, ...), "string")
end
local sPath = shell.resolveProgram(command)
if sPath ~= nil then if sPath ~= nil then
tProgramStack[#tProgramStack + 1] = sPath tProgramStack[#tProgramStack + 1] = sPath
if multishell then if multishell then
@ -144,7 +161,7 @@ local function run(_sCommand, ...)
local sDir = fs.getDir(sPath) local sDir = fs.getDir(sPath)
local env = createShellEnv(sDir) local env = createShellEnv(sDir)
env.arg = { [0] = _sCommand, ... } env.arg = { [0] = command, ... }
local result = os.run(env, sPath, ...) local result = os.run(env, sPath, ...)
tProgramStack[#tProgramStack] = nil tProgramStack[#tProgramStack] = nil
@ -196,11 +213,12 @@ end
-- @usage Run `paint my-image` from within your program: -- @usage Run `paint my-image` from within your program:
-- --
-- shell.run("paint", "my-image") -- shell.run("paint", "my-image")
-- @see shell.execute Run a program directly without parsing the arguments.
function shell.run(...) function shell.run(...)
local tWords = tokenise(...) local tWords = tokenise(...)
local sCommand = tWords[1] local sCommand = tWords[1]
if sCommand then if sCommand then
return run(sCommand, table.unpack(tWords, 2)) return shell.execute(sCommand, table.unpack(tWords, 2))
end end
return false return false
end end

View File

@ -0,0 +1 @@
_G.__arg = _ENV.arg

View File

@ -47,7 +47,7 @@ local function default_stub() end
--- Stub a table entry with a new value. --- Stub a table entry with a new value.
-- --
-- @tparam table -- @tparam table tbl The table whose field should be stubbed.
-- @tparam string key The variable to stub -- @tparam string key The variable to stub
-- @param[opt] value The value to stub it with. If this is a function, one can -- @param[opt] value The value to stub it with. If this is a function, one can
-- use the various stub expectation methods to determine what it was called -- use the various stub expectation methods to determine what it was called

View File

@ -8,10 +8,30 @@ describe("The peripheral library", function()
end) end)
end) end)
describe("peripheral.getName", function()
it("validates arguments", function()
expect.error(peripheral.getName, nil):eq("bad argument #1 (expected table, got nil)")
expect.error(peripheral.getName, {}):eq("bad argument #1 (table is not a peripheral)")
end)
it_modem("can get the name of a wrapped peripheral", function()
expect(peripheral.getName(peripheral.wrap("top"))):eq("top")
end)
end)
describe("peripheral.getType", function() describe("peripheral.getType", function()
it("validates arguments", function() it("validates arguments", function()
peripheral.getType("") peripheral.getType("")
expect.error(peripheral.getType, nil):eq("bad argument #1 (expected string, got nil)") expect.error(peripheral.getType, nil):eq("bad argument #1 (expected string or table, got nil)")
expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)")
end)
it_modem("can get the type of a peripheral by side", function()
expect(peripheral.getType("top")):eq("modem")
end)
it_modem("can get the type of a wrapped peripheral", function()
expect(peripheral.getType(peripheral.wrap("top"))):eq("modem")
end) end)
end) end)

View File

@ -6,19 +6,25 @@ describe("The shell", function()
end) end)
end) end)
describe("shell.run", function() describe("shell.execute", function()
it("sets the arguments", function() it("parses in arguments verbatim", function()
local handle = fs.open("test-files/out.txt", "w") shell.execute("/test-rom/data/dump-args", "arg1", "arg 2")
handle.writeLine("_G.__arg = arg")
handle.close()
shell.run("/test-files/out.txt", "arg1", "arg2")
fs.delete("test-files/out.txt")
local args = _G.__arg local args = _G.__arg
_G.__arg = nil _G.__arg = nil
expect(args):same { [0] = "/test-files/out.txt", "arg1", "arg2" } expect(args):same { [0] = "/test-rom/data/dump-args", "arg1", "arg 2" }
end)
end)
describe("shell.run", function()
it("tokenises the arguments", function()
shell.run("/test-rom/data/dump-args", "arg1", "arg 2")
local args = _G.__arg
_G.__arg = nil
expect(args):same { [0] = "/test-rom/data/dump-args", "arg1", "arg", "2" }
end) end)
end) end)