mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 13:42:59 +00:00 
			
		
		
		
	Merge branch 'mc-1.15.x' into mc-1.16.x
This commit is contained in:
		
							
								
								
									
										1
									
								
								.github/workflows/main-ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/main-ci.yml
									
									
									
									
										vendored
									
									
								
							| @@ -34,6 +34,7 @@ jobs: | ||||
|  | ||||
|     - name: Upload Coverage | ||||
|       run: bash <(curl -s https://codecov.io/bash) | ||||
|       continue-on-error: true | ||||
|  | ||||
|     - name: Generate Java documentation stubs | ||||
|       run: ./gradlew luaJavadoc --no-daemon | ||||
|   | ||||
							
								
								
									
										2
									
								
								.github/workflows/make-doc.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/make-doc.sh
									
									
									
									
										vendored
									
									
								
							| @@ -12,5 +12,5 @@ chmod 600 "$HOME/.ssh/key" | ||||
|  | ||||
| # And upload | ||||
| rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \ | ||||
|       "$GITHUB_WORKSPACE/doc/" \ | ||||
|       "$GITHUB_WORKSPACE/doc/out/" \ | ||||
|       "$SSH_USER@$SSH_HOST:/var/www/tweaked.cc/$DEST" | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -3,9 +3,8 @@ | ||||
| /logs | ||||
| /build | ||||
| /out | ||||
| /doc/**/*.html | ||||
| /doc/out/ | ||||
| /doc/javadoc/ | ||||
| /doc/index.json | ||||
|  | ||||
| # Runtime directories | ||||
| /run | ||||
|   | ||||
| @@ -9,7 +9,7 @@ buildscript { | ||||
|     } | ||||
|     dependencies { | ||||
|         classpath 'com.google.code.gson:gson:2.8.1' | ||||
|         classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.181' | ||||
|         classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.187' | ||||
|         classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2' | ||||
|         classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0' | ||||
|     } | ||||
| @@ -122,7 +122,7 @@ dependencies { | ||||
|  | ||||
|     deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0" | ||||
|  | ||||
|     cctJavadoc 'cc.tweaked:cct-javadoc:1.1.0' | ||||
|     cctJavadoc 'cc.tweaked:cct-javadoc:1.2.1' | ||||
| } | ||||
|  | ||||
| // Compile tasks | ||||
|   | ||||
| @@ -1,8 +1,6 @@ | ||||
| --- The http library allows communicating with web servers, sending and | ||||
| -- receiving data from them. | ||||
| -- | ||||
| -- #### `http_check` event | ||||
| -- | ||||
| -- @module http | ||||
|  | ||||
| --- Asynchronously make a HTTP request to the given url. | ||||
|   | ||||
							
								
								
									
										214
									
								
								doc/styles.css
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								doc/styles.css
									
									
									
									
									
								
							| @@ -1,141 +1,9 @@ | ||||
| /* Basic reset on elements */ | ||||
| h1, h2, h3, h4, p, table, div, body { | ||||
|     margin: 0; | ||||
|     padding: 0; | ||||
|     border: 0; | ||||
|     font-size: 100%; | ||||
|     font: inherit; | ||||
|     vertical-align: baseline; | ||||
| } | ||||
| /* Make the page a little more airy */ | ||||
| body { | ||||
|     margin: 20px auto; | ||||
|     max-width: 1200px; | ||||
|     padding: 0 10px; | ||||
|     line-height: 1.6; | ||||
|     color: #222; | ||||
|     background: #fff; | ||||
| } | ||||
|  | ||||
| /* Try to use system default fonts. */ | ||||
| body { | ||||
|     font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", | ||||
|                  "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; | ||||
| } | ||||
|  | ||||
| code, pre, kbd, .parameter, .type, .definition-name, .reference-code { | ||||
|     font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; | ||||
| } | ||||
|  | ||||
| /* Some definitions of basic tags */ | ||||
| code { | ||||
|     color: #c7254e; | ||||
|     background-color: #f9f2f4; | ||||
| } | ||||
|  | ||||
| p { | ||||
|     margin: 0.9em 0; | ||||
| } | ||||
|  | ||||
| h1 { | ||||
|     font-size: 1.5em; | ||||
|     font-weight: lighter; | ||||
|     border-bottom: solid 1px #aaa; | ||||
| } | ||||
|  | ||||
| h2, h3, h4 { margin: 1.4em 0 0.3em;} | ||||
| h2 { font-size: 1.25em; } | ||||
| h3 { font-size: 1.15em; font-weight: bold; } | ||||
| h4 { font-size: 1.06em; } | ||||
|  | ||||
| a, a:visited, a:active { font-weight: bold; color: #004080; text-decoration: none; } | ||||
| a:hover { text-decoration: underline; } | ||||
|  | ||||
| blockquote { | ||||
|     padding: 0.3em; | ||||
|     margin: 1em 0; | ||||
|     background: #f0f0f0; | ||||
|     border-left: solid 0.5em #ccc; | ||||
| } | ||||
|  | ||||
| /* Stop sublists from having initial vertical space */ | ||||
| ul ul { margin-top: 0px; } | ||||
| ol ul { margin-top: 0px; } | ||||
| ol ol { margin-top: 0px; } | ||||
| ul ol { margin-top: 0px; } | ||||
|  | ||||
| /* Make the target distinct; helps when we're navigating to a function */ | ||||
| a:target + * { background-color: #FFFF99; } | ||||
|  | ||||
| /* Allow linking to any subsection */ | ||||
| a[name]::before { content: "#"; } | ||||
|  | ||||
| /* Layout */ | ||||
| #main { | ||||
|     display: flex; | ||||
|     flex-wrap: nowrap; | ||||
|     justify-content: space-between; | ||||
|     min-height: calc(100vh - 100px); | ||||
| } | ||||
|  | ||||
| #main > nav { | ||||
|     flex-basis: 30%; | ||||
|     min-width: 150px; | ||||
|     max-width: 250px; | ||||
|     background-color: #f0f0f0; | ||||
| } | ||||
|  | ||||
| nav h1, nav ul { padding: 0em 10px; } | ||||
|  | ||||
| nav h2 { | ||||
|     background-color:#e7e7e7; | ||||
|     font-size: 1.1em; | ||||
|     color:#000000; | ||||
|     padding: 5px 10px; | ||||
| } | ||||
|  | ||||
| nav ul { | ||||
|     list-style-type: none; | ||||
|     margin: 0; | ||||
| } | ||||
|  | ||||
| #content { | ||||
|     flex-shrink: 1; | ||||
|     flex-basis: 80%; | ||||
|     padding: 0px 10px; | ||||
| } | ||||
|  | ||||
| footer { | ||||
|     text-align: right; | ||||
|     font-size: 0.8em; | ||||
| } | ||||
|  | ||||
| /* The definition lists at the top of each page */ | ||||
| table.definition-list, table.pretty-table { | ||||
| /* Pretty tables, mostly inherited from table.definition-list */ | ||||
| table.pretty-table { | ||||
|     border-collapse: collapse; | ||||
|     width: 100%; | ||||
| } | ||||
|  | ||||
| table.definition-list td, table.definition-list th { | ||||
|     border: 1px solid #cccccc; | ||||
|     padding: 5px; | ||||
| } | ||||
|  | ||||
| table.definition-list th { | ||||
|     background-color: #f0f0f0; | ||||
|     min-width: 200px; | ||||
|     white-space: nowrap; | ||||
|     text-align: right; | ||||
| } | ||||
|  | ||||
| /* Deprecated definitions */ | ||||
| table.definition-list tr.definition-deprecated th { | ||||
|     text-decoration: line-through; | ||||
| } | ||||
|  | ||||
| table.definition-list td { width: 100%; } | ||||
|  | ||||
| /* Pretty tables, mostly inherited from table.definition-list */ | ||||
| table.pretty-table td, table.pretty-table th { | ||||
|     border: 1px solid #cccccc; | ||||
|     padding: 2px 4px; | ||||
| @@ -144,81 +12,3 @@ table.pretty-table td, table.pretty-table th { | ||||
| table.pretty-table th { | ||||
|     background-color: #f0f0f0; | ||||
| } | ||||
|  | ||||
| dl.definition dt { | ||||
|     border-top: 1px solid #ccc; | ||||
|     padding-top: 1em; | ||||
|     display: flex; | ||||
| } | ||||
|  | ||||
| dl.definition dt .definition-name { | ||||
|     padding: 0 0.1em; | ||||
|     margin: 0 0.1em; | ||||
|     flex-grow: 1; | ||||
| } | ||||
|  | ||||
| /* Deprecated definitions */ | ||||
| dl.definition dt .definition-name.definition-deprecated { | ||||
|     text-decoration: line-through; | ||||
| } | ||||
|  | ||||
| dl.definition dd { | ||||
|     padding-bottom: 1em; | ||||
|     margin: 10px 0 0 20px; | ||||
| } | ||||
|  | ||||
| dl.definition h3 { | ||||
|     font-size: .95em; | ||||
| } | ||||
|  | ||||
| /* Links to source-code */ | ||||
| .source-link { font-size: 0.8em; } | ||||
| .source-link::before { content: '[' } | ||||
| .source-link::after  { content: ']' } | ||||
| a.source-link, a.source-link:visited, a.source-link:active { color: #505050; } | ||||
|  | ||||
| /* Method definitions */ | ||||
| span.parameter:after { content:":"; padding-left: 0.3em; } | ||||
| .optional { text-decoration: underline dotted; } | ||||
|  | ||||
| /** Fancy colour display. */ | ||||
| .colour-ref { | ||||
|     display: inline-block; | ||||
|     width: 0.8em; | ||||
|     height: 0.8em; | ||||
|     margin: 0.1em 0.1em 0.3em 0.1em; /* Terrrible hack to force vertical alignment. */ | ||||
|     border: solid 1px black; | ||||
|     box-sizing: border-box; | ||||
|     vertical-align: middle; | ||||
| } | ||||
|  | ||||
| /** Fancy keyboard shortcut styling, inspired by GitHub markdown. */ | ||||
| kbd { | ||||
|     display: inline-block; | ||||
|     padding: 4px 5px; | ||||
|     font-size: 0.8em; | ||||
|     line-height: 10px; | ||||
|     color: #444d56; | ||||
|     vertical-align: middle; | ||||
|     background-color: #fafbfc; | ||||
|     border: 1px solid #d1d5da; | ||||
|     border-radius: 3px; | ||||
|     box-shadow: inset 0 -1px 0 #d1d5da; | ||||
| } | ||||
|  | ||||
| /* styles for prettification of source */ | ||||
| .highlight .comment { color: #558817; } | ||||
| .highlight .constant { color: #a8660d; } | ||||
| .highlight .escape { color: #844631; } | ||||
| .highlight .keyword { color: #aa5050; font-weight: bold; } | ||||
| .highlight .library { color: #0e7c6b; } | ||||
| .highlight .marker { color: #512b1e; background: #fedc56; font-weight: bold; } | ||||
| .highlight .string { color: #8080ff; } | ||||
| .highlight .literal-kw { color: #8080ff; } | ||||
| .highlight .number { color: #f8660d; } | ||||
| .highlight .operator { color: #2239a8; font-weight: bold; } | ||||
| .highlight .preprocessor, pre .prepro { color: #a33243; } | ||||
| .highlight .global { color: #800080; } | ||||
| .highlight .user-keyword { color: #800080; } | ||||
| .highlight .prompt { color: #558817; } | ||||
| .highlight .url { color: #272fc2; text-decoration: underline; } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| # Mod properties | ||||
| mod_version=1.93.1 | ||||
| mod_version=1.94.0 | ||||
|  | ||||
| # Minecraft properties (update mods.toml when changing) | ||||
| mc_version=1.16.4 | ||||
|   | ||||
| @@ -10,7 +10,10 @@ | ||||
|  | ||||
| (doc | ||||
|   (title "CC: Tweaked") | ||||
|   (destination doc/out) | ||||
|   (logo src/main/resources/pack.png) | ||||
|   (index doc/index.md) | ||||
|   (styles doc/styles.css) | ||||
|   (source-link https://github.com/SquidDev-CC/CC-Tweaked/blob/${commit}/${path}#L${line}) | ||||
|  | ||||
|   (module-kinds | ||||
|   | ||||
| @@ -90,8 +90,6 @@ public final class ComputerCraft | ||||
|     public static boolean turtlesCanPush = true; | ||||
|     public static EnumSet<TurtleAction> turtleDisabledActions = EnumSet.noneOf( TurtleAction.class ); | ||||
|  | ||||
|     public static boolean genericPeripheral = false; | ||||
|  | ||||
|     public static int computerTermWidth = 51; | ||||
|     public static int computerTermHeight = 19; | ||||
|  | ||||
|   | ||||
| @@ -139,7 +139,7 @@ public interface ITurtleAccess | ||||
|      * | ||||
|      * @return This turtle's owner. | ||||
|      */ | ||||
|     @Nonnull | ||||
|     @Nullable | ||||
|     GameProfile getOwningPlayer(); | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -119,6 +119,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer | ||||
|  | ||||
|     private static void renderFrame( Matrix4f transform, ComputerFamily family, int colour, int width, int height ) | ||||
|     { | ||||
|         RenderSystem.enableBlend(); | ||||
|         Minecraft.getInstance().getTextureManager() | ||||
|             .bindTexture( colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture( family ) ); | ||||
|  | ||||
| @@ -137,7 +138,6 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer | ||||
|  | ||||
|     private static void renderLight( Matrix4f transform, int colour, int width, int height ) | ||||
|     { | ||||
|         RenderSystem.enableBlend(); | ||||
|         RenderSystem.disableTexture(); | ||||
|  | ||||
|         float r = ((colour >>> 16) & 0xFF) / 255.0f; | ||||
|   | ||||
| @@ -82,8 +82,6 @@ public final class Config | ||||
|     private static final ConfigValue<Integer> monitorWidth; | ||||
|     private static final ConfigValue<Integer> monitorHeight; | ||||
|  | ||||
|     private static final ConfigValue<Boolean> genericPeripheral; | ||||
|  | ||||
|     private static final ConfigValue<MonitorRenderer> monitorRenderer; | ||||
|     private static final ConfigValue<Integer> monitorDistance; | ||||
|  | ||||
| @@ -294,17 +292,6 @@ public final class Config | ||||
|             builder.pop(); | ||||
|         } | ||||
|  | ||||
|         { | ||||
|             builder.comment( "Options for various experimental features. These are not guaranteed to be stable, and may change or be removed across versions." ); | ||||
|             builder.push( "experimental" ); | ||||
|  | ||||
|             genericPeripheral = builder | ||||
|                 .comment( "Attempt to make any existing block (or tile entity) a peripheral.\n" + | ||||
|                     "This provides peripheral methods for any inventory, fluid tank or energy storage block. It will" + | ||||
|                     "_not_ provide methods which have an existing peripheral provider." ) | ||||
|                 .define( "generic_peripherals", false ); | ||||
|         } | ||||
|  | ||||
|         serverSpec = builder.build(); | ||||
|  | ||||
|         Builder clientBuilder = new Builder(); | ||||
| @@ -379,9 +366,6 @@ public final class Config | ||||
|         ComputerCraft.monitorWidth = monitorWidth.get(); | ||||
|         ComputerCraft.monitorHeight = monitorHeight.get(); | ||||
|  | ||||
|         // Experimental | ||||
|         ComputerCraft.genericPeripheral = genericPeripheral.get(); | ||||
|  | ||||
|         // Client | ||||
|         ComputerCraft.monitorRenderer = monitorRenderer.get(); | ||||
|         ComputerCraft.monitorDistanceSq = monitorDistance.get() * monitorDistance.get(); | ||||
|   | ||||
| @@ -116,7 +116,6 @@ public class CommandAPI implements ILuaAPI | ||||
|      * @param command The command to execute. | ||||
|      * @return The "task id". When this command has been executed, it will queue a `task_complete` event with a matching id. | ||||
|      * @throws LuaException (hidden) If the task cannot be created. | ||||
|      * @cc.tparam string command The command to execute. | ||||
|      * @cc.usage Asynchronously sets the block above the computer to stone. | ||||
|      * <pre> | ||||
|      * commands.execAsync("~ ~1 ~ minecraft:stone") | ||||
|   | ||||
| @@ -140,7 +140,8 @@ public class DiskDrivePeripheral implements IPeripheral | ||||
|     /** | ||||
|      * Returns the title of the inserted audio disk. | ||||
|      * | ||||
|      * @return The title of the audio, or {@code nil} if no audio disk is inserted. | ||||
|      * @return The title of the audio, or {@code false} if no audio disk is inserted. | ||||
|      * @cc.treturn string|nil|false The title of the audio, {@code false} if no disk is inserted, or {@code nil} if the disk has no audio. | ||||
|      */ | ||||
|     @LuaFunction | ||||
|     @Nullable | ||||
|   | ||||
| @@ -6,7 +6,6 @@ | ||||
|  | ||||
| package dan200.computercraft.shared.peripheral.generic; | ||||
|  | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.api.peripheral.IPeripheral; | ||||
| import dan200.computercraft.core.asm.NamedMethod; | ||||
| import dan200.computercraft.core.asm.PeripheralMethod; | ||||
| @@ -35,8 +34,6 @@ public class GenericPeripheralProvider | ||||
|     @Nonnull | ||||
|     public static LazyOptional<IPeripheral> getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side ) | ||||
|     { | ||||
|         if( !ComputerCraft.genericPeripheral ) return LazyOptional.empty(); | ||||
|  | ||||
|         TileEntity tile = world.getTileEntity( pos ); | ||||
|         if( tile == null ) return LazyOptional.empty(); | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,6 @@ | ||||
| package dan200.computercraft.shared.peripheral.generic.data; | ||||
|  | ||||
| import com.google.gson.JsonParseException; | ||||
| import dan200.computercraft.ComputerCraft; | ||||
| import dan200.computercraft.shared.util.NBTUtil; | ||||
| import net.minecraft.enchantment.Enchantment; | ||||
| import net.minecraft.enchantment.EnchantmentHelper; | ||||
| @@ -26,9 +25,6 @@ import java.util.stream.Collectors; | ||||
|  | ||||
| /** | ||||
|  * Data providers for items. | ||||
|  * | ||||
|  * We guard using {@link ComputerCraft#genericPeripheral} in several places, as advanced functionality should not be | ||||
|  * exposed for {@code turtle.getItemDetail} when generic peripehrals are disabled. | ||||
|  */ | ||||
| public class ItemData | ||||
| { | ||||
| @@ -73,8 +69,6 @@ public class ItemData | ||||
|  | ||||
|         data.put( "tags", DataHelpers.getTags( stack.getItem().getTags() ) ); | ||||
|  | ||||
|         if( !ComputerCraft.genericPeripheral ) return data; | ||||
|  | ||||
|         CompoundNBT tag = stack.getTag(); | ||||
|         if( tag != null && tag.contains( "display", Constants.NBT.TAG_COMPOUND ) ) | ||||
|         { | ||||
|   | ||||
| @@ -45,6 +45,7 @@ import net.minecraftforge.items.IItemHandlerModifiable; | ||||
| import net.minecraftforge.items.wrapper.InvWrapper; | ||||
|  | ||||
| import javax.annotation.Nonnull; | ||||
| import javax.annotation.Nullable; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.TimeUnit; | ||||
|  | ||||
| @@ -598,7 +599,7 @@ public class TurtleBrain implements ITurtleAccess | ||||
|         m_owningPlayer = profile; | ||||
|     } | ||||
|  | ||||
|     @Nonnull | ||||
|     @Nullable | ||||
|     @Override | ||||
|     public GameProfile getOwningPlayer() | ||||
|     { | ||||
|   | ||||
| @@ -17,6 +17,7 @@ import net.minecraft.entity.EntitySize; | ||||
| import net.minecraft.entity.EntityType; | ||||
| import net.minecraft.entity.Pose; | ||||
| import net.minecraft.entity.passive.horse.AbstractHorseEntity; | ||||
| import net.minecraft.entity.player.ServerPlayerEntity; | ||||
| import net.minecraft.inventory.IInventory; | ||||
| import net.minecraft.inventory.container.INamedContainerProvider; | ||||
| import net.minecraft.item.ItemStack; | ||||
| @@ -41,11 +42,30 @@ public final class TurtlePlayer extends FakePlayer | ||||
|         "[ComputerCraft]" | ||||
|     ); | ||||
|  | ||||
|     private TurtlePlayer( ITurtleAccess turtle ) | ||||
|     private TurtlePlayer( ServerWorld world, GameProfile name ) | ||||
|     { | ||||
|         super( (ServerWorld) turtle.getWorld(), getProfile( turtle.getOwningPlayer() ) ); | ||||
|         this.connection = new FakeNetHandler( this ); | ||||
|         setState( turtle ); | ||||
|         super( world, name ); | ||||
|     } | ||||
|  | ||||
|     private static TurtlePlayer create( ITurtleAccess turtle ) | ||||
|     { | ||||
|         ServerWorld world = (ServerWorld) turtle.getWorld(); | ||||
|         GameProfile profile = turtle.getOwningPlayer(); | ||||
|  | ||||
|         TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) ); | ||||
|         player.connection = new FakeNetHandler( player ); | ||||
|         player.setState( turtle ); | ||||
|  | ||||
|         if( profile != null && profile.getId() != null ) | ||||
|         { | ||||
|             // Constructing a player overrides the "active player" variable in advancements. As fake players cannot | ||||
|             // get advancements, this prevents a normal player who has placed a turtle from getting advancements. | ||||
|             // We try to locate the "actual" player and restore them. | ||||
|             ServerPlayerEntity actualPlayer = world.getServer().getPlayerList().getPlayerByUUID( profile.getId() ); | ||||
|             if( actualPlayer != null ) player.getAdvancements().setPlayer( actualPlayer ); | ||||
|         } | ||||
|  | ||||
|         return player; | ||||
|     } | ||||
|  | ||||
|     private static GameProfile getProfile( @Nullable GameProfile profile ) | ||||
| @@ -72,14 +92,14 @@ public final class TurtlePlayer extends FakePlayer | ||||
|  | ||||
|     public static TurtlePlayer get( ITurtleAccess access ) | ||||
|     { | ||||
|         if( !(access instanceof TurtleBrain) ) return new TurtlePlayer( access ); | ||||
|         if( !(access instanceof TurtleBrain) ) return create( access ); | ||||
|  | ||||
|         TurtleBrain brain = (TurtleBrain) access; | ||||
|         TurtlePlayer player = brain.m_cachedPlayer; | ||||
|         if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) | ||||
|             || player.getEntityWorld() != access.getWorld() ) | ||||
|         { | ||||
|             player = brain.m_cachedPlayer = new TurtlePlayer( brain ); | ||||
|             player = brain.m_cachedPlayer = create( brain ); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|   | ||||
| @@ -332,3 +332,21 @@ function rgb8(r, g, b) | ||||
|         return packRGB(r, g, b) | ||||
|     end | ||||
| end | ||||
|  | ||||
| -- Colour to hex lookup table for toBlit | ||||
| local color_hex_lookup = {} | ||||
| for i = 0, 15 do | ||||
|     color_hex_lookup[2 ^ i] = string.format("%x", i) | ||||
| end | ||||
|  | ||||
| --- Converts the given color to a paint/blit hex character (0-9a-f). | ||||
| -- | ||||
| -- This is equivalent to converting floor(log_2(color)) to hexadecimal. | ||||
| -- | ||||
| -- @tparam number color The color to convert. | ||||
| -- @treturn string The blit hex code of the color. | ||||
| function toBlit(color) | ||||
|     expect(1, color, "number") | ||||
|     return color_hex_lookup[color] or | ||||
|         string.format("%x", math.floor(math.log(color) / math.log(2))) | ||||
| end | ||||
|   | ||||
| @@ -23,6 +23,25 @@ local function parseLine(tImageArg, sLine) | ||||
|     table.insert(tImageArg, tLine) | ||||
| end | ||||
|  | ||||
| -- Sorts pairs of startX/startY/endX/endY such that the start is always the min | ||||
| local function sortCoords(startX, startY, endX, endY) | ||||
|     local minX, maxX, minY, maxY | ||||
|  | ||||
|     if startX <= endX then | ||||
|         minX, maxX = startX, endX | ||||
|     else | ||||
|         minX, maxX = endX, startX | ||||
|     end | ||||
|  | ||||
|     if startY <= endY then | ||||
|         minY, maxY = startY, endY | ||||
|     else | ||||
|         minY, maxY = endY, startY | ||||
|     end | ||||
|  | ||||
|     return minX, maxX, minY, maxY | ||||
| end | ||||
|  | ||||
| --- Parses an image from a multi-line string | ||||
| -- | ||||
| -- @tparam string image The string containing the raw-image data. | ||||
| @@ -71,9 +90,6 @@ function drawPixel(xPos, yPos, colour) | ||||
|     expect(2, yPos, "number") | ||||
|     expect(3, colour, "number", "nil") | ||||
|  | ||||
|     if type(xPos) ~= "number" then error("bad argument #1 (expected number, got " .. type(xPos) .. ")", 2) end | ||||
|     if type(yPos) ~= "number" then error("bad argument #2 (expected number, got " .. type(yPos) .. ")", 2) end | ||||
|     if colour ~= nil and type(colour) ~= "number" then error("bad argument #3 (expected number, got " .. type(colour) .. ")", 2) end | ||||
|     if colour then | ||||
|         term.setBackgroundColor(colour) | ||||
|     end | ||||
| @@ -111,17 +127,7 @@ function drawLine(startX, startY, endX, endY, colour) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local minX = math.min(startX, endX) | ||||
|     local maxX, minY, maxY | ||||
|     if minX == startX then | ||||
|         minY = startY | ||||
|         maxX = endX | ||||
|         maxY = endY | ||||
|     else | ||||
|         minY = endY | ||||
|         maxX = startX | ||||
|         maxY = startY | ||||
|     end | ||||
|     local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY) | ||||
|  | ||||
|     -- TODO: clip to screen rectangle? | ||||
|  | ||||
| @@ -177,37 +183,33 @@ function drawBox(startX, startY, endX, endY, nColour) | ||||
|     endY = math.floor(endY) | ||||
|  | ||||
|     if nColour then | ||||
|         term.setBackgroundColor(nColour) | ||||
|         term.setBackgroundColor(nColour) -- Maintain legacy behaviour | ||||
|     else | ||||
|         nColour = term.getBackgroundColour() | ||||
|     end | ||||
|     local colourHex = colours.toBlit(nColour) | ||||
|  | ||||
|     if startX == endX and startY == endY then | ||||
|         drawPixelInternal(startX, startY) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local minX = math.min(startX, endX) | ||||
|     local maxX, minY, maxY | ||||
|     if minX == startX then | ||||
|         minY = startY | ||||
|         maxX = endX | ||||
|         maxY = endY | ||||
|     local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY) | ||||
|     local width = maxX - minX + 1 | ||||
|  | ||||
|     for y = minY, maxY do | ||||
|         if y == minY or y == maxY then | ||||
|             term.setCursorPos(minX, y) | ||||
|             term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width)) | ||||
|         else | ||||
|         minY = endY | ||||
|         maxX = startX | ||||
|         maxY = startY | ||||
|     end | ||||
|  | ||||
|     for x = minX, maxX do | ||||
|         drawPixelInternal(x, minY) | ||||
|         drawPixelInternal(x, maxY) | ||||
|     end | ||||
|  | ||||
|     if maxY - minY >= 2 then | ||||
|         for y = minY + 1, maxY - 1 do | ||||
|             drawPixelInternal(minX, y) | ||||
|             drawPixelInternal(maxX, y) | ||||
|             term.setCursorPos(minX, y) | ||||
|             term.blit(" ", colourHex, colourHex) | ||||
|             term.setCursorPos(maxX, y) | ||||
|             term.blit(" ", colourHex, colourHex) | ||||
|         end | ||||
|     end | ||||
| end | ||||
|  | ||||
| --- Draws a filled box on the current term from the specified start position to | ||||
| -- the specified end position. | ||||
| -- | ||||
| @@ -233,29 +235,23 @@ function drawFilledBox(startX, startY, endX, endY, nColour) | ||||
|     endY = math.floor(endY) | ||||
|  | ||||
|     if nColour then | ||||
|         term.setBackgroundColor(nColour) | ||||
|         term.setBackgroundColor(nColour) -- Maintain legacy behaviour | ||||
|     else | ||||
|         nColour = term.getBackgroundColour() | ||||
|     end | ||||
|     local colourHex = colours.toBlit(nColour) | ||||
|  | ||||
|     if startX == endX and startY == endY then | ||||
|         drawPixelInternal(startX, startY) | ||||
|         return | ||||
|     end | ||||
|  | ||||
|     local minX = math.min(startX, endX) | ||||
|     local maxX, minY, maxY | ||||
|     if minX == startX then | ||||
|         minY = startY | ||||
|         maxX = endX | ||||
|         maxY = endY | ||||
|     else | ||||
|         minY = endY | ||||
|         maxX = startX | ||||
|         maxY = startY | ||||
|     end | ||||
|     local minX, maxX, minY, maxY = sortCoords(startX, startY, endX, endY) | ||||
|     local width = maxX - minX + 1 | ||||
|  | ||||
|     for x = minX, maxX do | ||||
|     for y = minY, maxY do | ||||
|             drawPixelInternal(x, y) | ||||
|         end | ||||
|         term.setCursorPos(minX, y) | ||||
|         term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width)) | ||||
|     end | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -453,13 +453,13 @@ do | ||||
|         error_at(pos, "Unexpected %s, expected %s.", actual, exp) | ||||
|     end | ||||
|  | ||||
|     local function parse_string(str, pos) | ||||
|     local function parse_string(str, pos, terminate) | ||||
|         local buf, n = {}, 1 | ||||
|  | ||||
|         while true do | ||||
|             local c = sub(str, pos, pos) | ||||
|             if c == "" then error_at(pos, "Unexpected end of input, expected '\"'.") end | ||||
|             if c == '"' then break end | ||||
|             if c == terminate then break end | ||||
|  | ||||
|             if c == '\\' then | ||||
|                 -- Handle the various escapes | ||||
| @@ -485,13 +485,13 @@ do | ||||
|         return concat(buf, "", 1, n - 1), pos + 1 | ||||
|     end | ||||
|  | ||||
|     local valid = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true } | ||||
|     local num_types = { b = true, B = true, s = true, S = true, l = true, L = true, f = true, F = true, d = true, D = true } | ||||
|     local function parse_number(str, pos, opts) | ||||
|         local _, last, num_str = find(str, '^(-?%d+%.?%d*[eE]?[+-]?%d*)', pos) | ||||
|         local val = tonumber(num_str) | ||||
|         if not val then error_at(pos, "Malformed number %q.", num_str) end | ||||
|  | ||||
|         if opts.nbt_style and valid[sub(str, pos + 1, pos + 1)] then return val, last + 2 end | ||||
|         if opts.nbt_style and num_types[sub(str, last + 1, last + 1)] then return val, last + 2 end | ||||
|  | ||||
|         return val, last + 1 | ||||
|     end | ||||
| @@ -501,9 +501,11 @@ do | ||||
|         return val, last + 1 | ||||
|     end | ||||
|  | ||||
|     local arr_types = { I = true, L = true, B = true } | ||||
|     local function decode_impl(str, pos, opts) | ||||
|         local c = sub(str, pos, pos) | ||||
|         if c == '"' then return parse_string(str, pos + 1) | ||||
|         if c == '"' then return parse_string(str, pos + 1, '"') | ||||
|         elseif c == "'" and opts.nbt_style then return parse_string(str, pos + 1, "\'") | ||||
|         elseif c == "-" or c >= "0" and c <= "9" then return parse_number(str, pos, opts) | ||||
|         elseif c == "t" then | ||||
|             if sub(str, pos + 1, pos + 3) == "rue" then return true, pos + 4 end | ||||
| @@ -528,7 +530,7 @@ do | ||||
|  | ||||
|             while true do | ||||
|                 local key, value | ||||
|                 if c == "\"" then key, pos = parse_string(str, pos + 1) | ||||
|                 if c == "\"" then key, pos = parse_string(str, pos + 1, "\"") | ||||
|                 elseif opts.nbt_style then key, pos = parse_ident(str, pos) | ||||
|                 else return expected(pos, c, "object key") | ||||
|                 end | ||||
| @@ -560,6 +562,11 @@ do | ||||
|             pos = skip(str, pos + 1) | ||||
|             c = sub(str, pos, pos) | ||||
|  | ||||
|             if arr_types[c] and sub(str, pos + 1, pos + 1) == ";" and opts.nbt_style then | ||||
|                 pos = skip(str, pos + 2) | ||||
|                 c = sub(str, pos, pos) | ||||
|             end | ||||
|  | ||||
|             if c == "" then return expected(pos, c, "']'") end | ||||
|             if c == "]" then return empty_json_array, pos + 1 end | ||||
|  | ||||
|   | ||||
| @@ -474,6 +474,14 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     --- Get whether this window is visible. Invisible windows will not be | ||||
|     -- drawn to the screen until they are made visible again. | ||||
|     -- | ||||
|     -- @treturn boolean Whether this window is visible. | ||||
|     -- @see Window:setVisible | ||||
|     function window.isVisible() | ||||
|         return bVisible | ||||
|     end | ||||
|     --- Draw this window. This does nothing if the window is not visible. | ||||
|     -- | ||||
|     -- @see Window:setVisible | ||||
|   | ||||
| @@ -1,3 +1,15 @@ | ||||
| # New features in CC: Tweaked 1.94.0 | ||||
|  | ||||
| * Add getter for window visibility (devomaa) | ||||
| * Generic peripherals are no longer experimental, and on by default. | ||||
| * Use term.blit to draw boxes in paintutils (Lemmmy). | ||||
|  | ||||
| And several bug fixes: | ||||
| * Fix turtles not getting advancements when turtles are on. | ||||
| * Draw in-hand pocket computers with the correct transparent flags enabled. | ||||
| * Several bug fixes to SNBT parsing. | ||||
| * Fix several programs using their original name instead of aliases in usage hints (Lupus590). | ||||
|  | ||||
| # New features in CC: Tweaked 1.93.1 | ||||
|  | ||||
| * Various documentation improvements (Lemmmy). | ||||
| @@ -74,8 +86,6 @@ And several bug fixes: | ||||
| * Fix deadlock when mistakenly "watching" an unloaded chunk. | ||||
| * Fix full path of files being leaked in some errors. | ||||
|  | ||||
| Type "help changelog" to see the full version history. | ||||
|  | ||||
| # New features in CC: Tweaked 1.89.1 | ||||
|  | ||||
| * Fix crashes when rendering monitors of varying sizes. | ||||
|   | ||||
| @@ -1,6 +1,13 @@ | ||||
| New features in CC: Tweaked 1.93.1 | ||||
| New features in CC: Tweaked 1.94.0 | ||||
|  | ||||
| * Various documentation improvements (Lemmmy). | ||||
| * Fix TBO monitor renderer on some older graphics cards (Lemmmy). | ||||
| * Add getter for window visibility (devomaa) | ||||
| * Generic peripherals are no longer experimental, and on by default. | ||||
| * Use term.blit to draw boxes in paintutils (Lemmmy). | ||||
|  | ||||
| And several bug fixes: | ||||
| * Fix turtles not getting advancements when turtles are on. | ||||
| * Draw in-hand pocket computers with the correct transparent flags enabled. | ||||
| * Several bug fixes to SNBT parsing. | ||||
| * Fix several programs using their original name instead of aliases in usage hints (Lupus590). | ||||
|  | ||||
| Type "help changelog" to see the full version history. | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| local tArgs = { ... } | ||||
| if #tArgs > 2 then | ||||
|     print("Usage: alias <alias> <program>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <alias> <program>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| local tArgs = { ... } | ||||
| if #tArgs < 1 then | ||||
|     print("Usage: cd <path>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <path>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -4,7 +4,8 @@ if not commands then | ||||
|     return | ||||
| end | ||||
| if #tArgs == 0 then | ||||
|     printError("Usage: exec <command>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     printError("Usage: " .. programName .. " <command>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| local tArgs = { ... } | ||||
| if #tArgs < 2 then | ||||
|     print("Usage: cp <source> <destination>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <source> <destination>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| local args = table.pack(...) | ||||
|  | ||||
| if args.n < 1 then | ||||
|     print("Usage: rm <paths>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <paths>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| -- Get file to edit | ||||
| local tArgs = { ... } | ||||
| if #tArgs == 0 then | ||||
|     print("Usage: edit <path>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <path>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| -- Get arguments | ||||
| local tArgs = { ... } | ||||
| if #tArgs == 0 then | ||||
|     print("Usage: eject <drive>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <drive>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -34,7 +34,8 @@ end | ||||
| -- Determines if the file exists, and can be edited on this computer | ||||
| local tArgs = { ... } | ||||
| if #tArgs == 0 then | ||||
|     print("Usage: paint <path>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <path>") | ||||
|     return | ||||
| end | ||||
| local sPath = shell.resolve(tArgs[1]) | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| local tArgs = { ... } | ||||
|  | ||||
| local function printUsage() | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usages:") | ||||
|     print("dj play") | ||||
|     print("dj play <drive>") | ||||
|     print("dj stop") | ||||
|     print(programName .. " play") | ||||
|     print(programName .. " play <drive>") | ||||
|     print(programName .. " stop") | ||||
| end | ||||
|  | ||||
| if #tArgs > 2 then | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| local function printUsage() | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usages:") | ||||
|     print("gps host") | ||||
|     print("gps host <x> <y> <z>") | ||||
|     print("gps locate") | ||||
|     print(programName .. " host") | ||||
|     print(programName .. " host <x> <y> <z>") | ||||
|     print(programName .. " locate") | ||||
| end | ||||
|  | ||||
| local tArgs = { ... } | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| local function printUsage() | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usages:") | ||||
|     print("pastebin put <filename>") | ||||
|     print("pastebin get <code> <filename>") | ||||
|     print("pastebin run <code> <arguments>") | ||||
|     print(programName .. " put <filename>") | ||||
|     print(programName .. " get <code> <filename>") | ||||
|     print(programName .. " run <code> <arguments>") | ||||
| end | ||||
|  | ||||
| local tArgs = { ... } | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| local function printUsage() | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage:") | ||||
|     print("wget <url> [filename]") | ||||
|     print("wget run <url>") | ||||
|     print(programName .. " <url> [filename]") | ||||
|     print(programName .. " run <url>") | ||||
| end | ||||
|  | ||||
| local tArgs = { ... } | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| local function printUsage() | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usages:") | ||||
|     print("label get") | ||||
|     print("label get <drive>") | ||||
|     print("label set <text>") | ||||
|     print("label set <drive> <text>") | ||||
|     print("label clear") | ||||
|     print("label clear <drive>") | ||||
|     print(programName .. " get") | ||||
|     print(programName .. " get <drive>") | ||||
|     print(programName .. " set <text>") | ||||
|     print(programName .. " set <drive> <text>") | ||||
|     print(programName .. " clear") | ||||
|     print(programName .. " clear <drive>") | ||||
| end | ||||
|  | ||||
| local function checkDrive(sDrive) | ||||
|   | ||||
| @@ -1,7 +1,8 @@ | ||||
| local tArgs = { ... } | ||||
|  | ||||
| if #tArgs < 1 then | ||||
|     print("Usage: mkdir <paths>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <paths>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| local function printUsage() | ||||
|     print("Usage: monitor <name> <program> <arguments>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <name> <program> <arguments>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| local tArgs = { ... } | ||||
| if #tArgs < 2 then | ||||
|     print("Usage: mv <source> <destination>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <source> <destination>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,10 @@ | ||||
| local tArgs = { ... } | ||||
|  | ||||
| local function printUsage() | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usages:") | ||||
|     print("chat host <hostname>") | ||||
|     print("chat join <hostname> <nickname>") | ||||
|     print(programName .. " host <hostname>") | ||||
|     print(programName .. " join <hostname> <nickname>") | ||||
| end | ||||
|  | ||||
| local sOpenedModem = nil | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| local tArgs = { ... } | ||||
|  | ||||
| local function printUsage() | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usages:") | ||||
|     print("redstone probe") | ||||
|     print("redstone set <side> <value>") | ||||
|     print("redstone set <side> <color> <value>") | ||||
|     print("redstone pulse <side> <count> <period>") | ||||
|     print(programName .. " probe") | ||||
|     print(programName .. " set <side> <value>") | ||||
|     print(programName .. " set <side> <color> <value>") | ||||
|     print(programName .. " pulse <side> <count> <period>") | ||||
| end | ||||
|  | ||||
| local sCommand = tArgs[1] | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| local tArgs = { ... } | ||||
| if #tArgs < 2 then | ||||
|     print("Usage: rename <source> <destination>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <source> <destination>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,8 @@ end | ||||
| local tArgs = { ... } | ||||
| local nLimit = nil | ||||
| if #tArgs < 1 then | ||||
|     print("Usage: craft [number]") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " [number]") | ||||
|     return | ||||
| else | ||||
|     nLimit = tonumber(tArgs[1]) | ||||
|   | ||||
| @@ -5,7 +5,8 @@ end | ||||
|  | ||||
| local tArgs = { ... } | ||||
| local function printUsage() | ||||
|     print("Usage: equip <slot> <side>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <slot> <side>") | ||||
| end | ||||
|  | ||||
| if #tArgs ~= 2 then | ||||
|   | ||||
| @@ -5,7 +5,8 @@ end | ||||
|  | ||||
| local tArgs = { ... } | ||||
| if #tArgs ~= 1 then | ||||
|     print("Usage: excavate <diameter>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <diameter>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,8 @@ end | ||||
|  | ||||
| local tArgs = { ... } | ||||
| if #tArgs < 1 then | ||||
|     print("Usage: go <direction> <distance>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <direction> <distance>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,8 @@ end | ||||
| local tArgs = { ... } | ||||
| local nLimit = 1 | ||||
| if #tArgs > 1 then | ||||
|     print("Usage: refuel [number]") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " [number]") | ||||
|     return | ||||
| elseif #tArgs > 0 then | ||||
|     if tArgs[1] == "all" then | ||||
|   | ||||
| @@ -5,7 +5,8 @@ end | ||||
|  | ||||
| local tArgs = { ... } | ||||
| if #tArgs ~= 1 then | ||||
|     print("Usage: tunnel <length>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <length>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,8 @@ end | ||||
|  | ||||
| local tArgs = { ... } | ||||
| if #tArgs < 1 then | ||||
|     print("Usage: turn <direction> <turns>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <direction> <turns>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,8 @@ end | ||||
|  | ||||
| local tArgs = { ... } | ||||
| local function printUsage() | ||||
|     print("Usage: unequip <side>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <side>") | ||||
| end | ||||
|  | ||||
| if #tArgs ~= 1 then | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| local tArgs = { ... } | ||||
| if #tArgs < 1 then | ||||
|     print("Usage: type <path>") | ||||
|     local programName = arg[0] or fs.getName(shell.getRunningProgram()) | ||||
|     print("Usage: " .. programName .. " <path>") | ||||
|     return | ||||
| end | ||||
|  | ||||
|   | ||||
| @@ -73,4 +73,20 @@ describe("The colors library", function() | ||||
|         expect(colors.rgb8(0.3, 0.5, 0.6)):equals(0x4c7f99) | ||||
|         expect({ colors.rgb8(0x4c7f99) }):same { 0x4c / 0xFF, 0x7f / 0xFF, 0.6 } | ||||
|     end) | ||||
|  | ||||
|     describe("colors.toBlit", function() | ||||
|         it("validates arguments", function() | ||||
|             expect.error(colors.toBlit, nil):eq("bad argument #1 (expected number, got nil)") | ||||
|         end) | ||||
|  | ||||
|         it("converts all colors", function() | ||||
|             for i = 0, 15 do | ||||
|                 expect(colors.toBlit(2 ^ i)):eq(string.format("%x", i)) | ||||
|             end | ||||
|         end) | ||||
|  | ||||
|         it("floors colors", function() | ||||
|             expect(colors.toBlit(16385)):eq("e") | ||||
|         end) | ||||
|     end) | ||||
| end) | ||||
|   | ||||
| @@ -1,4 +1,19 @@ | ||||
| local with_window = require "test_helpers".with_window | ||||
|  | ||||
| describe("The paintutils library", function() | ||||
|     -- Verifies that a window's lines are equal to the given table of blit | ||||
|     -- strings ({{"text", "fg", "bg"}, {"text", "fg", "bg"}...}) | ||||
|     local function window_eq(w, state) | ||||
|         -- Verification of the size isn't really important in the tests, but | ||||
|         -- better safe than sorry. | ||||
|         local _, height = w.getSize() | ||||
|         expect(#state):eq(height) | ||||
|  | ||||
|         for line = 1, height do | ||||
|             expect({ w.getLine(line) }):same(state[line]) | ||||
|         end | ||||
|     end | ||||
|  | ||||
|     describe("paintutils.parseImage", function() | ||||
|         it("validates arguments", function() | ||||
|             paintutils.parseImage("") | ||||
| @@ -28,6 +43,30 @@ describe("The paintutils library", function() | ||||
|             expect.error(paintutils.drawLine, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") | ||||
|             expect.error(paintutils.drawLine, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") | ||||
|         end) | ||||
|  | ||||
|         it("draws a line going across with custom colour", function() | ||||
|             local w = with_window(3, 2, function() | ||||
|                 paintutils.drawLine(1, 1, 3, 1, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "000", "eee" }, | ||||
|                 { "   ", "000", "fff" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a line going diagonally with term colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setBackgroundColour(colours.red) | ||||
|                 paintutils.drawLine(1, 1, 3, 3) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "000", "eff" }, | ||||
|                 { "   ", "000", "fef" }, | ||||
|                 { "   ", "000", "ffe" }, | ||||
|             }) | ||||
|         end) | ||||
|     end) | ||||
|  | ||||
|     describe("paintutils.drawBox", function() | ||||
| @@ -38,6 +77,45 @@ describe("The paintutils library", function() | ||||
|             expect.error(paintutils.drawBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") | ||||
|             expect.error(paintutils.drawBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") | ||||
|         end) | ||||
|  | ||||
|         it("draws a box with term colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setBackgroundColour(colours.red) | ||||
|                 paintutils.drawBox(1, 1, 3, 3) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "e0e", "efe" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a box with custom colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 paintutils.drawBox(1, 1, 3, 3, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "e0e", "efe" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a box without overwriting existing content", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setCursorPos(2, 2) | ||||
|                 term.write("a") | ||||
|                 paintutils.drawBox(1, 1, 3, 3, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { " a ", "e0e", "efe" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|     end) | ||||
|  | ||||
|     describe("paintutils.drawFilledBox", function() | ||||
| @@ -48,6 +126,31 @@ describe("The paintutils library", function() | ||||
|             expect.error(paintutils.drawFilledBox, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)") | ||||
|             expect.error(paintutils.drawFilledBox, 1, 1, 1, 1, false):eq("bad argument #5 (expected number, got boolean)") | ||||
|         end) | ||||
|  | ||||
|         it("draws a filled box with term colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 term.setBackgroundColour(colours.red) | ||||
|                 paintutils.drawFilledBox(1, 1, 3, 3) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|  | ||||
|         it("draws a filled box with custom colour", function() | ||||
|             local w = with_window(3, 3, function() | ||||
|                 paintutils.drawFilledBox(1, 1, 3, 3, colours.red) | ||||
|             end) | ||||
|  | ||||
|             window_eq(w, { | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|                 { "   ", "eee", "eee" }, | ||||
|             }) | ||||
|         end) | ||||
|     end) | ||||
|  | ||||
|     describe("paintutils.drawImage", function() | ||||
|   | ||||
| @@ -126,12 +126,28 @@ describe("The textutils library", function() | ||||
|         end) | ||||
|  | ||||
|         describe("parses using NBT-style syntax", function() | ||||
|             local function exp(x) | ||||
|                 local res, err = textutils.unserializeJSON(x, { nbt_style = true }) | ||||
|                 if not res then error(err, 2) end | ||||
|                 return expect(res) | ||||
|             end | ||||
|             it("basic objects", function() | ||||
|                 expect(textutils.unserializeJSON([[{ a: 1, b:2 }]], { nbt_style = true })):same { a = 1, b = 2 } | ||||
|                 exp([[{ a: 1, b:2 }]]):same { a = 1, b = 2 } | ||||
|             end) | ||||
|  | ||||
|             it("suffixed numbers", function() | ||||
|                 expect(textutils.unserializeJSON("1b", { nbt_style = true })):eq(1) | ||||
|                 exp("1b"):eq(1) | ||||
|                 exp("1.1d"):eq(1.1) | ||||
|             end) | ||||
|  | ||||
|             it("strings", function() | ||||
|                 exp("'123'"):eq("123") | ||||
|                 exp("\"123\""):eq("123") | ||||
|             end) | ||||
|  | ||||
|             it("typed arrays", function() | ||||
|                 exp("[B; 1, 2, 3]"):same { 1, 2, 3 } | ||||
|                 exp("[B;]"):same {} | ||||
|             end) | ||||
|         end) | ||||
|  | ||||
|   | ||||
| @@ -157,4 +157,17 @@ describe("The window library", function() | ||||
|             expect({ w.getLine(1) }):same { "test ", "aaaa0", "4444f" } | ||||
|         end) | ||||
|     end) | ||||
|     describe("Window.setVisible", function() | ||||
|         it("validates arguments", function() | ||||
|             local w = mk() | ||||
|             expect.error(w.setVisible, nil):eq("bad argument #1 (expected boolean, got nil)") | ||||
|         end) | ||||
|     end) | ||||
|     describe("Window.isVisible", function() | ||||
|          it("gets window visibility", function() | ||||
|            local w = mk() | ||||
|            w.setVisible(false) | ||||
|            expect(w.isVisible()):same(false) | ||||
|          end) | ||||
|     end) | ||||
| end) | ||||
|   | ||||
| @@ -10,7 +10,7 @@ describe("The exec program", function() | ||||
|     it("displays its usage when given no argument", function() | ||||
|         stub(_G, "commands", {}) | ||||
|         expect(capture(stub, "/rom/programs/command/exec.lua")) | ||||
|             :matches { ok = true, output = "", error = "Usage: exec <command>\n" } | ||||
|             :matches { ok = true, output = "", error = "Usage: /rom/programs/command/exec.lua <command>\n" } | ||||
|     end) | ||||
|  | ||||
|     it("runs a command", function() | ||||
|   | ||||
| @@ -35,6 +35,6 @@ describe("The copy program", function() | ||||
|  | ||||
|     it("displays the usage when given no arguments", function() | ||||
|         expect(capture(stub, "copy")) | ||||
|             :matches { ok = true, output = "Usage: cp <source> <destination>\n", error = "" } | ||||
|             :matches { ok = true, output = "Usage: copy <source> <destination>\n", error = "" } | ||||
|     end) | ||||
| end) | ||||
|   | ||||
| @@ -69,6 +69,6 @@ describe("The move program", function() | ||||
|  | ||||
|     it("displays the usage with no arguments", function() | ||||
|         expect(capture(stub, "move")) | ||||
|             :matches { ok = true, output = "Usage: mv <source> <destination>\n", error = "" } | ||||
|             :matches { ok = true, output = "Usage: move <source> <destination>\n", error = "" } | ||||
|     end) | ||||
| end) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ describe("The craft program", function() | ||||
|         stub(_G, "turtle", { craft = function() end }) | ||||
|  | ||||
|         expect(capture(stub, "/rom/programs/turtle/craft.lua")) | ||||
|             :matches { ok = true, output = "Usage: craft [number]\n", error = "" } | ||||
|             :matches { ok = true, output = "Usage: /rom/programs/turtle/craft.lua [number]\n", error = "" } | ||||
|     end) | ||||
|  | ||||
|     it("crafts multiple items", function() | ||||
|   | ||||
| @@ -13,7 +13,7 @@ describe("The turtle equip program", function() | ||||
|         stub(_G, "turtle", {}) | ||||
|  | ||||
|         expect(capture(stub, "/rom/programs/turtle/equip.lua")) | ||||
|             :matches { ok = true, output = "Usage: equip <slot> <side>\n", error = "" } | ||||
|             :matches { ok = true, output = "Usage: /rom/programs/turtle/equip.lua <slot> <side>\n", error = "" } | ||||
|     end) | ||||
|  | ||||
|     it("equip nothing", function() | ||||
|   | ||||
| @@ -32,7 +32,7 @@ describe("The refuel program", function() | ||||
|     it("displays its usage when given too many argument", function() | ||||
|         setup_turtle(0, 5, 0) | ||||
|         expect(capture(stub, "/rom/programs/turtle/refuel.lua a b")) | ||||
|             :matches { ok = true, output = "Usage: refuel [number]\n", error = "" } | ||||
|             :matches { ok = true, output = "Usage: /rom/programs/turtle/refuel.lua [number]\n", error = "" } | ||||
|     end) | ||||
|  | ||||
|     it("requires a numeric argument", function() | ||||
|   | ||||
| @@ -13,7 +13,7 @@ describe("The turtle unequip program", function() | ||||
|         stub(_G, "turtle", {}) | ||||
|  | ||||
|         expect(capture(stub, "/rom/programs/turtle/unequip.lua")) | ||||
|             :matches { ok = true, output = "Usage: unequip <side>\n", error = "" } | ||||
|             :matches { ok = true, output = "Usage: /rom/programs/turtle/unequip.lua <side>\n", error = "" } | ||||
|     end) | ||||
|  | ||||
|     it("says when nothing was unequipped", function() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 SquidDev
					SquidDev