1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-06 22:04:39 +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
end return native.getType(peripheral)
for n = 1, #sides do
local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", name)
then
return native.call(side, "getTypeRemote", name)
end end
for n = 1, #sides do
local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", peripheral)
then
return native.call(side, "getTypeRemote", peripheral)
end
end
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
return nil
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)