diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json index 74fb9c725..6ca0e4761 100644 --- a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_advanced.json @@ -17,6 +17,9 @@ { "condition": "computercraft:block_named" }, + { + "condition": "computercraft:has_id" + }, { "condition": "minecraft:inverted", "term": { diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json index 74fb9c725..6ca0e4761 100644 --- a/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/computer_normal.json @@ -17,6 +17,9 @@ { "condition": "computercraft:block_named" }, + { + "condition": "computercraft:has_id" + }, { "condition": "minecraft:inverted", "term": { diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json index 74fb9c725..6ca0e4761 100644 --- a/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_advanced.json @@ -17,6 +17,9 @@ { "condition": "computercraft:block_named" }, + { + "condition": "computercraft:has_id" + }, { "condition": "minecraft:inverted", "term": { diff --git a/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json index 74fb9c725..6ca0e4761 100644 --- a/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json +++ b/src/generated/resources/data/computercraft/loot_tables/blocks/turtle_normal.json @@ -17,6 +17,9 @@ { "condition": "computercraft:block_named" }, + { + "condition": "computercraft:has_id" + }, { "condition": "minecraft:inverted", "term": { diff --git a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java index 8b7234283..0b9491b53 100644 --- a/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java +++ b/src/main/java/dan200/computercraft/client/gui/FixedWidthFontRenderer.java @@ -55,10 +55,9 @@ public final class FixedWidthFontRenderer 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 i < 0 ? 0 : 15 - i; + return 15 - Terminal.getColour( c, def ); } 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 ) { - double[] colour = palette.getColour( getColour( colourIndex ) ); + double[] colour = palette.getColour( getColour( colourIndex, Colour.Black ) ); float r, g, b; if( greyscale ) { @@ -160,7 +159,7 @@ public final class FixedWidthFontRenderer 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; if( greyscale ) { diff --git a/src/main/java/dan200/computercraft/core/terminal/Terminal.java b/src/main/java/dan200/computercraft/core/terminal/Terminal.java index f58af1a1c..638e02951 100644 --- a/src/main/java/dan200/computercraft/core/terminal/Terminal.java +++ b/src/main/java/dan200/computercraft/core/terminal/Terminal.java @@ -5,18 +5,20 @@ */ package dan200.computercraft.core.terminal; +import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Palette; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; public class Terminal { private static final String base16 = "0123456789abcdef"; - private int m_cursorX; - private int m_cursorY; - private boolean m_cursorBlink; - private int m_cursorColour; - private int m_cursorBackgroundColour; + private int m_cursorX = 0; + private int m_cursorY = 0; + private boolean m_cursorBlink = false; + private int m_cursorColour = 0; + private int m_cursorBackgroundColour = 15; private int m_width; private int m_height; @@ -25,9 +27,9 @@ public class Terminal private TextBuffer[] m_textColour; 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; public Terminal( int width, int height ) @@ -41,9 +43,6 @@ public class Terminal m_height = height; onChanged = changedCallback; - m_cursorColour = 0; - m_cursorBackgroundColour = 15; - m_text = new TextBuffer[m_height]; m_textColour = 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_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() @@ -336,6 +327,62 @@ public class Terminal 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 ) { 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_textBgColour_" + n, m_backgroundColour[n].toString() ); } - if( m_palette != null ) - { - m_palette.writeToNBT( nbt ); - } + + m_palette.writeToNBT( nbt ); return nbt; } @@ -382,10 +427,15 @@ public class Terminal m_backgroundColour[n].write( nbt.getString( "term_textBgColour_" + n ) ); } } - if( m_palette != null ) - { - m_palette.readFromNBT( nbt ); - } + + m_palette.readFromNBT( nbt ); 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(); + } } diff --git a/src/main/java/dan200/computercraft/data/LootTables.java b/src/main/java/dan200/computercraft/data/LootTables.java index 02db8551e..00c34402e 100644 --- a/src/main/java/dan200/computercraft/data/LootTables.java +++ b/src/main/java/dan200/computercraft/data/LootTables.java @@ -8,6 +8,7 @@ package dan200.computercraft.data; import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; +import dan200.computercraft.shared.data.HasComputerIdLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import net.minecraft.block.Block; 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" ) ) ) .acceptCondition( Alternative.builder( BlockNamedEntityLootCondition.builder(), + HasComputerIdLootCondition.builder(), PlayerCreativeLootCondition.builder().inverted() ) ) ).build() ); diff --git a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java index 6d8007820..2ce762435 100644 --- a/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ClientTerminal.java @@ -6,7 +6,9 @@ package dan200.computercraft.shared.common; import dan200.computercraft.core.terminal.Terminal; +import io.netty.buffer.Unpooled; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; public class ClientTerminal implements ITerminal { @@ -53,7 +55,7 @@ public class ClientTerminal implements ITerminal { CompoundNBT terminal = nbt.getCompound( "terminal" ); 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 { diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index 3766bedf5..2b7d153a6 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -5,8 +5,12 @@ */ package dan200.computercraft.shared.common; +import dan200.computercraft.ComputerCraft; import dan200.computercraft.core.terminal.Terminal; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; import java.util.concurrent.atomic.AtomicBoolean; @@ -83,17 +87,28 @@ public class ServerTerminal implements ITerminal return m_colour; } - // Networking stuff - public void writeDescription( CompoundNBT nbt ) { nbt.putBoolean( "colour", m_colour ); 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(); terminal.putInt( "term_width", m_terminal.getWidth() ); terminal.putInt( "term_height", m_terminal.getHeight() ); - m_terminal.writeToNBT( terminal ); + terminal.putByteArray( "term_contents", buffer.array() ); nbt.put( "terminal", terminal ); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java index aa690a58b..92ac7f52f 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ComputerItemFactory.java @@ -19,9 +19,7 @@ public final class ComputerItemFactory @Nonnull public static ItemStack create( TileComputer tile ) { - String label = tile.getLabel(); - int id = label != null ? tile.getComputerID() : -1; - return create( id, label, tile.getFamily() ); + return create( tile.getComputerID(), tile.getLabel(), tile.getFamily() ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java index 94d539175..0540aeb5b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/items/ItemComputerBase.java @@ -37,7 +37,7 @@ public abstract class ItemComputerBase extends BlockItem implements IComputerIte @Override public void addInformation( @Nonnull ItemStack stack, @Nullable World world, @Nonnull List list, @Nonnull ITooltipFlag options ) { - if( options.isAdvanced() ) + if( options.isAdvanced() || getLabel( stack ) == null ) { int id = getComputerID( stack ); if( id >= 0 ) diff --git a/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java new file mode 100644 index 000000000..4da10a15c --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/data/HasComputerIdLootCondition.java @@ -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> getRequiredParameters() + { + return Collections.singleton( LootParameters.BLOCK_ENTITY ); + } + + public static IBuilder builder() + { + return () -> INSTANCE; + } +} diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 19562fb6e..bdc5318ed 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -184,7 +184,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I @Override public void addInformation( @Nonnull ItemStack stack, @Nullable World world, List list, ITooltipFlag flag ) { - if( flag.isAdvanced() ) + if( flag.isAdvanced() || getLabel( stack ) == null ) { int id = getComputerID( stack ); if( id >= 0 ) diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 70ddeca32..2a54cab57 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -20,6 +20,7 @@ import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.data.BlockNamedEntityLootCondition; import dan200.computercraft.shared.data.ConstantLootConditionSerializer; +import dan200.computercraft.shared.data.HasComputerIdLootCondition; import dan200.computercraft.shared.data.PlayerCreativeLootCondition; import dan200.computercraft.shared.media.items.RecordMedia; import dan200.computercraft.shared.network.NetworkHandler; @@ -72,6 +73,12 @@ public final class ComputerCraftProxyCommon PlayerCreativeLootCondition.class, PlayerCreativeLootCondition.INSTANCE ) ); + + LootConditionManager.registerCondition( ConstantLootConditionSerializer.of( + new ResourceLocation( ComputerCraft.MOD_ID, "has_id" ), + HasComputerIdLootCondition.class, + HasComputerIdLootCondition.INSTANCE + ) ); } private static void registerProviders() diff --git a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java index 3212a14f8..a9b76a66a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java +++ b/src/main/java/dan200/computercraft/shared/turtle/items/TurtleItemFactory.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.turtle.items; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.computer.core.ComputerFamily; @@ -22,18 +23,13 @@ public final class TurtleItemFactory @Nonnull public static ItemStack create( ITurtleTile turtle ) { - ITurtleUpgrade leftUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Left ); - ITurtleUpgrade rightUpgrade = turtle.getAccess().getUpgrade( TurtleSide.Right ); + ITurtleAccess access = turtle.getAccess(); - String label = turtle.getLabel(); - if( label == null ) - { - return create( -1, null, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, 0, turtle.getOverlay() ); - } - - int id = turtle.getComputerID(); - int fuelLevel = turtle.getAccess().getFuelLevel(); - return create( id, label, turtle.getColour(), turtle.getFamily(), leftUpgrade, rightUpgrade, fuelLevel, turtle.getOverlay() ); + return create( + turtle.getComputerID(), turtle.getLabel(), turtle.getColour(), turtle.getFamily(), + access.getUpgrade( TurtleSide.Left ), access.getUpgrade( TurtleSide.Right ), + access.getFuelLevel(), turtle.getOverlay() + ); } @Nonnull diff --git a/src/main/java/dan200/computercraft/shared/util/Palette.java b/src/main/java/dan200/computercraft/shared/util/Palette.java index 2758a6d11..bf4fc89f4 100644 --- a/src/main/java/dan200/computercraft/shared/util/Palette.java +++ b/src/main/java/dan200/computercraft/shared/util/Palette.java @@ -6,6 +6,7 @@ package dan200.computercraft.shared.util; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; 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 ) { int[] rgb8 = new int[colours.length]; diff --git a/src/main/resources/assets/computercraft/lang/da_dk.lang b/src/main/resources/assets/computercraft/lang/da_dk.lang index 3da64d2a4..a54df9dee 100644 --- a/src/main/resources/assets/computercraft/lang/da_dk.lang +++ b/src/main/resources/assets/computercraft/lang/da_dk.lang @@ -44,5 +44,5 @@ chat.computercraft.wired_modem.peripheral_disconnected=Perifer enhed "%s" koblet # Misc tooltips gui.computercraft.tooltip.copy=Kopier til udklipsholder -gui.computercraft.tooltip.computer_id=(Computer-ID: %s) -gui.computercraft.tooltip.disk_id=(Disk-ID: %s) +gui.computercraft.tooltip.computer_id=Computer-ID: %s +gui.computercraft.tooltip.disk_id=Disk-ID: %s diff --git a/src/main/resources/assets/computercraft/lang/de_de.json b/src/main/resources/assets/computercraft/lang/de_de.json index 14a8ae879..596438a14 100644 --- a/src/main/resources/assets/computercraft/lang/de_de.json +++ b/src/main/resources/assets/computercraft/lang/de_de.json @@ -141,8 +141,8 @@ "tracking_field.computercraft.coroutines_dead.name": "Koroutinen gelöscht", "gui.computercraft.tooltip.copy": "In die Zwischenablage kopieren", - "gui.computercraft.tooltip.computer_id": "(Computer ID: %s)", - "gui.computercraft.tooltip.disk_id": "(Disketten ID: %s)", + "gui.computercraft.tooltip.computer_id": "Computer ID: %s", + "gui.computercraft.tooltip.disk_id": "Disketten ID: %s", "gui.computercraft.config.computer_space_limit": "Speicherplatz von Computern (bytes)", "gui.computercraft.config.floppy_space_limit": "Speicherplatz von Disketten (bytes)", diff --git a/src/main/resources/assets/computercraft/lang/en_us.json b/src/main/resources/assets/computercraft/lang/en_us.json index 22a5d1167..53514aa93 100644 --- a/src/main/resources/assets/computercraft/lang/en_us.json +++ b/src/main/resources/assets/computercraft/lang/en_us.json @@ -143,8 +143,8 @@ "tracking_field.computercraft.coroutines_dead.name": "Coroutines disposed", "gui.computercraft.tooltip.copy": "Copy to clipboard", - "gui.computercraft.tooltip.computer_id": "(Computer ID: %s)", - "gui.computercraft.tooltip.disk_id": "(Disk ID: %s)", + "gui.computercraft.tooltip.computer_id": "Computer ID: %s", + "gui.computercraft.tooltip.disk_id": "Disk ID: %s", "gui.computercraft.config.computer_space_limit": "Computer space limit (bytes)", "gui.computercraft.config.floppy_space_limit": "Floppy Disk space limit (bytes)", diff --git a/src/main/resources/assets/computercraft/lang/ko_kr.lang b/src/main/resources/assets/computercraft/lang/ko_kr.lang index 784bb4b31..24c220059 100644 --- a/src/main/resources/assets/computercraft/lang/ko_kr.lang +++ b/src/main/resources/assets/computercraft/lang/ko_kr.lang @@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=코루틴 처리됨 # Misc tooltips gui.computercraft.tooltip.copy=클립보드에 복사 -gui.computercraft.tooltip.computer_id=(컴퓨터 ID: %s) -gui.computercraft.tooltip.disk_id=(디스크 ID: %s) +gui.computercraft.tooltip.computer_id=컴퓨터 ID: %s +gui.computercraft.tooltip.disk_id=디스크 ID: %s # Config options gui.computercraft:config.computer_space_limit=컴퓨터 공간 제한 (바이트) diff --git a/src/main/resources/assets/computercraft/lang/zh_cn.json b/src/main/resources/assets/computercraft/lang/zh_cn.json index f96ffb713..7df723d40 100644 --- a/src/main/resources/assets/computercraft/lang/zh_cn.json +++ b/src/main/resources/assets/computercraft/lang/zh_cn.json @@ -143,8 +143,8 @@ "tracking_field.computercraft.coroutines_dead.name": "协同处理", "gui.computercraft.tooltip.copy": "复制到剪贴板", - "gui.computercraft.tooltip.computer_id": "(计算机ID: %s)", - "gui.computercraft.tooltip.disk_id": "(磁盘ID: %s)", + "gui.computercraft.tooltip.computer_id": "计算机ID: %s", + "gui.computercraft.tooltip.disk_id": "磁盘ID: %s", "gui.computercraft.config.computer_space_limit": "计算机空间限制(字节)", "gui.computercraft.config.floppy_space_limit": "软盘空间限制(字节)", diff --git a/src/main/resources/assets/computercraft/lang/zh_cn.lang b/src/main/resources/assets/computercraft/lang/zh_cn.lang index 56b9aa106..ab29adfc6 100644 --- a/src/main/resources/assets/computercraft/lang/zh_cn.lang +++ b/src/main/resources/assets/computercraft/lang/zh_cn.lang @@ -148,8 +148,8 @@ tracking_field.computercraft.coroutines_dead.name=协同处理 # Misc tooltips gui.computercraft.tooltip.copy=复制到剪贴板 -gui.computercraft.tooltip.computer_id=(计算机ID: %s) -gui.computercraft.tooltip.disk_id=(磁盘ID: %s) +gui.computercraft.tooltip.computer_id=计算机ID: %s +gui.computercraft.tooltip.disk_id=磁盘ID: %s # Config options gui.computercraft:config.computer_space_limit=计算机空间限制(字节) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua index 53b849adc..c737a915a 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua @@ -64,24 +64,33 @@ function isPresent(name) return false 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. -function getType(name) - expect(1, name, "string") - if native.isPresent(name) then - return native.getType(name) - 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", name) - then - return native.call(side, "getTypeRemote", name) +function getType(peripheral) + expect(1, peripheral, "string", "table") + if type(peripheral) == "string" then -- Peripheral name passed + if native.isPresent(peripheral) then + return native.getType(peripheral) 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 - return nil end --- Get all available methods for the peripheral with the given name. @@ -105,6 +114,19 @@ function getMethods(name) return nil 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. -- -- @tparam string name The name of the peripheral to invoke the method on. @@ -148,7 +170,11 @@ function wrap(name) return nil end - local result = {} + local result = setmetatable({}, { + __name = "peripheral", + name = name, + type = peripheral.getType(name), + }) for _, method in ipairs(methods) do result[method] = function(...) return peripheral.call(name, method, ...) diff --git a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua index 358c62bd5..3a8f3a5c0 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua @@ -29,7 +29,7 @@ local tReceivedMessageTimeouts = {} local tHostnames = {} --- 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 -- @{os.getComputerID|ID} as the computer, and another on @@ -246,7 +246,7 @@ function host(sProtocol, sHostname) end --- 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. function unhost(sProtocol) diff --git a/src/main/resources/data/computercraft/lua/rom/help/peripheral.txt b/src/main/resources/data/computercraft/lua/rom/help/peripheral.txt index 2b02b0a90..333f52f51 100644 --- a/src/main/resources/data/computercraft/lua/rom/help/peripheral.txt +++ b/src/main/resources/data/computercraft/lua/rom/help/peripheral.txt @@ -3,6 +3,7 @@ The peripheral API is for interacting with external peripheral devices. Type "he Functions in the peripheral API: peripheral.getNames() peripheral.isPresent( name ) +peripheral.getName( peripheral ) peripheral.getType( name ) peripheral.getMethods( name ) peripheral.call( name, methodName, param1, param2, etc ) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua b/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua index e6daed9e8..01c9d7949 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/monitor.lua @@ -28,7 +28,7 @@ local monitor = peripheral.wrap(sName) local previousTerm = term.redirect(monitor) local co = coroutine.create(function() - shell.run(sProgram, table.unpack(tArgs, 3)) + (shell.execute or shell.run)(sProgram, table.unpack(tArgs, 3)) end) local function resume(...) diff --git a/src/main/resources/data/computercraft/lua/rom/programs/shell.lua b/src/main/resources/data/computercraft/lua/rom/programs/shell.lua index 474d3ecfd..843e28e71 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/shell.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/shell.lua @@ -130,8 +130,25 @@ else bgColour = colours.black end -local function run(_sCommand, ...) - local sPath = shell.resolveProgram(_sCommand) +--- Run a program with the supplied arguments. +-- +-- 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 tProgramStack[#tProgramStack + 1] = sPath if multishell then @@ -144,7 +161,7 @@ local function run(_sCommand, ...) local sDir = fs.getDir(sPath) local env = createShellEnv(sDir) - env.arg = { [0] = _sCommand, ... } + env.arg = { [0] = command, ... } local result = os.run(env, sPath, ...) tProgramStack[#tProgramStack] = nil @@ -196,11 +213,12 @@ end -- @usage Run `paint my-image` from within your program: -- -- shell.run("paint", "my-image") +-- @see shell.execute Run a program directly without parsing the arguments. function shell.run(...) local tWords = tokenise(...) local sCommand = tWords[1] if sCommand then - return run(sCommand, table.unpack(tWords, 2)) + return shell.execute(sCommand, table.unpack(tWords, 2)) end return false end diff --git a/src/test/resources/test-rom/data/dump-args.lua b/src/test/resources/test-rom/data/dump-args.lua new file mode 100644 index 000000000..3772a43ec --- /dev/null +++ b/src/test/resources/test-rom/data/dump-args.lua @@ -0,0 +1 @@ +_G.__arg = _ENV.arg diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index 81e5afb3c..5081447a6 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -47,7 +47,7 @@ local function default_stub() end --- 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 -- @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 diff --git a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua index c3fb5675f..1b11c6552 100644 --- a/src/test/resources/test-rom/spec/apis/peripheral_spec.lua +++ b/src/test/resources/test-rom/spec/apis/peripheral_spec.lua @@ -8,10 +8,30 @@ describe("The peripheral library", function() 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() it("validates arguments", function() 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) diff --git a/src/test/resources/test-rom/spec/programs/shell_spec.lua b/src/test/resources/test-rom/spec/programs/shell_spec.lua index cb35d70f6..fae7b85d1 100644 --- a/src/test/resources/test-rom/spec/programs/shell_spec.lua +++ b/src/test/resources/test-rom/spec/programs/shell_spec.lua @@ -6,19 +6,25 @@ describe("The shell", function() end) end) - describe("shell.run", function() - it("sets the arguments", function() - local handle = fs.open("test-files/out.txt", "w") - handle.writeLine("_G.__arg = arg") - handle.close() - - shell.run("/test-files/out.txt", "arg1", "arg2") - fs.delete("test-files/out.txt") + describe("shell.execute", function() + it("parses in arguments verbatim", function() + shell.execute("/test-rom/data/dump-args", "arg1", "arg 2") local args = _G.__arg _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)