mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-23 09:57:39 +00:00
Compare commits
28 Commits
v1.93.0
...
v1.94.1-be
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d8b0037cfa | ||
![]() |
91a9e7fdf7 | ||
![]() |
2c3573719b | ||
![]() |
46bc42d5a7 | ||
![]() |
1b9e93a80f | ||
![]() |
7b93f91ffa | ||
![]() |
31a1027401 | ||
![]() |
e0fc994819 | ||
![]() |
43408bf085 | ||
![]() |
d28f42e8b7 | ||
![]() |
ac452582c1 | ||
![]() |
7e65c6b25c | ||
![]() |
457a863842 | ||
![]() |
eef36e1358 | ||
![]() |
feda08b915 | ||
![]() |
0240ce50ce | ||
![]() |
592b83e784 | ||
![]() |
5d91491ec7 | ||
![]() |
7326d1110d | ||
![]() |
0aa6ac05a0 | ||
![]() |
27a2c063b9 | ||
![]() |
89a195ec06 | ||
![]() |
0e5fd4e8e0 | ||
![]() |
aa4ec53bb6 | ||
![]() |
6b49327462 | ||
![]() |
74ad934889 | ||
![]() |
08b3dbbad5 | ||
![]() |
00b458c39a |
50
.github/workflows/main-ci.yml
vendored
Normal file
50
.github/workflows/main-ci.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Build
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Java 8
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 8
|
||||
|
||||
- name: Cache gradle dependencies
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.gradle/caches
|
||||
key: ${{ runner.os }}-gradle-${{ hashFiles('gradle.properties') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-gradle-
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build --no-daemon || ./gradlew build --no-daemon
|
||||
|
||||
- name: Upload Jar
|
||||
uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: cc-restiched
|
||||
path: build/libs
|
||||
|
||||
- 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
|
||||
|
||||
- name: Lint Lua code
|
||||
run: |
|
||||
test -d bin || mkdir bin
|
||||
test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
|
||||
chmod +x bin/illuaminate
|
||||
bin/illuaminate lint
|
||||
|
||||
- name: Check whitespace
|
||||
run: python3 tools/check-lines.py
|
5
.gitignore
vendored
5
.gitignore
vendored
@@ -9,6 +9,11 @@
|
||||
/run-*
|
||||
/test-files
|
||||
|
||||
# Autogenerated by IDE
|
||||
/bin
|
||||
/.settings
|
||||
.classpath
|
||||
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
|
@@ -2,8 +2,4 @@
|
||||
# This is a Work In Progress Port
|
||||
*it runs and works-ish*
|
||||
|
||||
## Reached Parity with CC:T 1.93.0
|
||||
|
||||
THis is just a quick patchwork of my attempts at getting CC:R up to date with CC:T
|
||||
|
||||
The changelog is located at [PatchWork.md](patchwork.md)
|
||||
PRs welcome
|
||||
|
@@ -9,7 +9,7 @@ targetCompatibility = JavaVersion.VERSION_1_8
|
||||
version = mod_version
|
||||
|
||||
group = "dan200.computercraft"
|
||||
archivesBaseName = "cc-tweaked-fabric-${mc_version}"
|
||||
archivesBaseName = "cc-restiched"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@@ -29,6 +29,8 @@ dependencies {
|
||||
modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
|
||||
|
||||
compile 'com.electronwill.night-config:json:3.6.0'
|
||||
|
||||
modImplementation "me.shedaniel.cloth:config-2:${cloth_config_version}"
|
||||
modImplementation "io.github.prospector:modmenu:${modmenu_version}"
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Mod properties
|
||||
mod_version=1.93.0
|
||||
mod_version=1.94.1-beta
|
||||
|
||||
# Minecraft properties
|
||||
mc_version=1.16.2
|
||||
|
189
patchwork.md
189
patchwork.md
@@ -11,6 +11,8 @@ SubScript // Desc of commit
|
||||
If a edit that is present in CC:T is not needed, I will skip over it.
|
||||
Any and all references to an issue number, are to be found on CC:T's repo.
|
||||
|
||||
Any commit that starts with `[Patchwork]` are purely edits made by my hand, and not based on other commits from CC:T, this is to help differentiate my changes from the official changes
|
||||
|
||||
Lines that are found above a commit in this log like this one, (excluding this one) are comments about how i had to implement things that are not a simple 1:1 (excluding fabric/forge differences) conversion
|
||||
|
||||
```md
|
||||
@@ -122,3 +124,190 @@ same way transparent blocks like glass do.
|
||||
|
||||
Closes #548.
|
||||
```
|
||||
|
||||
```
|
||||
30d35883b83831900b34040f0131c7e06f5c3e52
|
||||
Fix my docs
|
||||
|
||||
Thanks @plt-hokusai. Kinda embarrassing this slipped through - I
|
||||
evidently need to lint examples too.
|
||||
```
|
||||
|
||||
```
|
||||
34a2c835d412c0d9e1fb20a42b7f2cd2738289c7
|
||||
Add color table to docs (#553)
|
||||
```
|
||||
|
||||
All API Documentation updates,
|
||||
`Not Needed` for this repo.
|
||||
```
|
||||
93068402a2ffec00eedb8fe2d859ebdc005a1989
|
||||
Document remaining OS functions (#554)
|
||||
|
||||
01d81cb91da938836f953b290ad6b8fc87cb7e35
|
||||
Update illuaminate CSS for deprecation (#556)
|
||||
```
|
||||
|
||||
```
|
||||
Not Needed
|
||||
4766833cf2d041ed179529eecb9402ad09b2b79b
|
||||
Bump JEI/crafttweaker versions
|
||||
|
||||
In my defence, they weren't out when I started the 1.15 update.
|
||||
```
|
||||
|
||||
```
|
||||
bf6053906dc6a3c7b0d40d5b097e745dce1f33bc
|
||||
Fix TBO norm issues on old GPUs
|
||||
```
|
||||
|
||||
```
|
||||
Not Needed
|
||||
113b560a201dbdea9de2a2ef536bcce1d6e51978
|
||||
Update configuration to match latest illuaminate
|
||||
|
||||
Ooooooh, it's all fancy now. Well, that or horrifically broken.
|
||||
```
|
||||
|
||||
```
|
||||
c334423d42ba3b653ac3a8c27bce7970457f8f96
|
||||
Add function to get window visibility
|
||||
|
||||
Closes #562
|
||||
|
||||
Co-authored-by: devomaa <lmao@distruzione.org>
|
||||
```
|
||||
|
||||
[WARN] Could not implement changes to the following files
|
||||
* `src/main/java/dan200/computercraft/ComputerCraft.java` < Structure too different, cannot find equivalent to alter
|
||||
* `src/main/java/dan200/computercraft/shared/Config.java` < Files Does not exist in this repo
|
||||
```
|
||||
84a6bb1cf3b0668ddc7d8c409a2477a42390e3f7
|
||||
Make generic peripherals on by default
|
||||
|
||||
This is a long way away from "feature complete" as it were. However,
|
||||
it's definitely at a point where it's suitable for general usage - I'm
|
||||
happy with the API, and don't think I'm going to be breaking things any
|
||||
time soon.
|
||||
|
||||
That said, things aren't exposed yet for Java-side public consumption. I
|
||||
was kinda waiting until working on Plethora to actually do that, but not
|
||||
sure if/when that'll happen.
|
||||
|
||||
If someone else wants to work on an integration mod (or just adding
|
||||
integrations for their own mod), do get in touch and I can work out how
|
||||
to expose this.
|
||||
|
||||
Closes #452
|
||||
```
|
||||
|
||||
```
|
||||
Not Needed
|
||||
6aae4e576621090840724e094aa25e51696530fc
|
||||
Remove superfluous imports
|
||||
|
||||
Hah, this is embarassing
|
||||
```
|
||||
|
||||
[TODO] [M3R1-01] Code has been applied, players still dont get achievments
|
||||
```
|
||||
f6160bdc57b3d9850607c2c7c2ce9734b4963478
|
||||
Fix players not getting advancements when they own turtles
|
||||
|
||||
When we construct a new ServerPlayerEntity (and thus TurtlePlayer), we
|
||||
get the current (global) advancement state and call .setPlayer() on it.
|
||||
|
||||
As grantCriterion blocks FakePlayers from getting advancements, this
|
||||
means a player will no longer receive any advancements, as the "wrong"
|
||||
player object is being consulted.
|
||||
|
||||
As a temporary work around, we attempt to restore the previous player to
|
||||
the advancement store. I'll try to upstream something into Forge to
|
||||
resolve this properly.
|
||||
|
||||
Fixes #564
|
||||
```
|
||||
|
||||
```
|
||||
17a932920711a5c0361a5048c9e0a5e7a58e6364
|
||||
Bump cct-javadoc version
|
||||
|
||||
Documentation will now be sorted (somewhat) correctly!
|
||||
```
|
||||
|
||||
```
|
||||
a6fcfb6af2fc1bef8ca3a19122c9267549202424
|
||||
Draw in-hand pocket computers with blending
|
||||
|
||||
It might be worth switching to RenderTypes here, rather than a pure
|
||||
Tesselator, but this'll do for now.
|
||||
|
||||
Fixes Zundrel/cc-tweaked-fabric#20.
|
||||
```
|
||||
|
||||
```
|
||||
c58441b29c3715f092e7f3747bb3ec65ae5a3d29
|
||||
Various SNBT parsing improvements
|
||||
|
||||
Correctly handle:
|
||||
- Typed arrays ([I; 1, 2, 3])
|
||||
- All suffixed numbers (1.2d)
|
||||
- Single-quoted strings
|
||||
|
||||
Fixes #559
|
||||
```
|
||||
|
||||
```
|
||||
e2a635b6e5f5942f999213434054e06833c5cb06
|
||||
Dont fail when codecov is being finicky
|
||||
```
|
||||
|
||||
```
|
||||
666e83cf4fd0eb327f465d5b919a708790f99b00
|
||||
Fix JSON objects failing to pass
|
||||
|
||||
Maybe I should run the whole test suite, not just the things I think
|
||||
matter? Nah....
|
||||
```
|
||||
|
||||
```
|
||||
741adfa7bb2b950d2851c3f0072d6a4769f22773
|
||||
|
||||
Use blit to draw boxes, add colors.toBlit (#570)
|
||||
```
|
||||
|
||||
```
|
||||
d13bd2cce8d102ad7f61f557e707d6fe3731bc37
|
||||
|
||||
use arg[0] in all usage printouts (#571)
|
||||
```
|
||||
|
||||
```
|
||||
74ac5bb3d17e5bee30643a5d6702696600c06229
|
||||
|
||||
Bump to 1.94.0
|
||||
```
|
||||
|
||||
[TODO] [M3R1-02] Zero Clue how to reimplement this in fabric.
|
||||
```
|
||||
c8aeddedd4ed430f9cb6428676ebb4fa39834182
|
||||
|
||||
Auto-generate monitor models
|
||||
|
||||
I didn't think it was worth it, and then I found myself needing to
|
||||
update a dozen of them. The code isn't especially pretty, but it works,
|
||||
so that's fine.
|
||||
|
||||
Also fixes several issues with us using the wrong texture (closes #572).
|
||||
I've put together a wiki page[1] which describes each texture in a
|
||||
little more detail.
|
||||
|
||||
[1] https://github.com/SquidDev-CC/CC-Tweaked/wiki/Monitor-texture-reference
|
||||
```
|
||||
|
||||
7f90f2f7cadce0d5b9177b16626979591bce8137
|
||||
```
|
||||
Clean up some examples a little bit
|
||||
|
||||
Would be good if they didn't crash and burn on entry :).
|
||||
```
|
||||
|
@@ -9,4 +9,4 @@ pluginManagement {
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "cc-tweaked-fabric-${mc_version}"
|
||||
rootProject.name = "cc-restiched"
|
||||
|
@@ -135,7 +135,7 @@ public interface ITurtleAccess {
|
||||
*
|
||||
* @return This turtle's owner.
|
||||
*/
|
||||
@Nonnull
|
||||
@Nullable
|
||||
GameProfile getOwningPlayer();
|
||||
|
||||
/**
|
||||
|
@@ -95,6 +95,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer {
|
||||
}
|
||||
|
||||
private static void renderFrame(Matrix4f transform, ComputerFamily family, int colour, int width, int height) {
|
||||
RenderSystem.enableBlend();
|
||||
MinecraftClient.getInstance()
|
||||
.getTextureManager()
|
||||
.bindTexture(colour != -1 ? ComputerBorderRenderer.BACKGROUND_COLOUR : ComputerBorderRenderer.getTexture(family));
|
||||
@@ -113,7 +114,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;
|
||||
|
@@ -6,120 +6,129 @@
|
||||
|
||||
package dan200.computercraft.core.apis.http.options;
|
||||
|
||||
|
||||
import com.electronwill.nightconfig.core.CommentedConfig;
|
||||
import com.electronwill.nightconfig.core.Config;
|
||||
import com.electronwill.nightconfig.core.InMemoryCommentedFormat;
|
||||
import com.electronwill.nightconfig.core.UnmodifiableConfig;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
public class AddressRuleConfig {
|
||||
// TODO haha config is gone, do fix
|
||||
|
||||
// TODO FIGURE OUT WHY THE HELL THE PREVIOUS GUY HAD TO COMMENT THIS OUT
|
||||
public static UnmodifiableConfig makeRule( String host, Action action )
|
||||
{
|
||||
CommentedConfig config = InMemoryCommentedFormat.defaultInstance().createConfig( ConcurrentHashMap::new );
|
||||
config.add( "host", host );
|
||||
config.add( "action", action.name().toLowerCase( Locale.ROOT ) );
|
||||
|
||||
// public static UnmodifiableConfig makeRule( String host, Action action )
|
||||
// {
|
||||
// CommentedConfig config = InMemoryCommentedFormat.defaultInstance().createConfig( ConcurrentHashMap::new );
|
||||
// config.add( "host", host );
|
||||
// config.add( "action", action.name().toLowerCase( Locale.ROOT ) );
|
||||
//
|
||||
// if( host.equals( "*" ) && action == Action.ALLOW )
|
||||
// {
|
||||
// config.setComment( "timeout", "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." );
|
||||
// config.add( "timeout", AddressRule.TIMEOUT );
|
||||
//
|
||||
// config.setComment( "max_download", "The maximum size (in bytes) that a computer can download in a single request. Note that responses
|
||||
// may receive more data than allowed, but this data will not be returned to the client." );
|
||||
// config.set( "max_download", AddressRule.MAX_DOWNLOAD );
|
||||
//
|
||||
// config.setComment( "max_upload", "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and
|
||||
// POST text." );
|
||||
// config.set( "max_upload", AddressRule.MAX_UPLOAD );
|
||||
//
|
||||
// config.setComment( "max_websocket_message", "The maximum size (in bytes) that a computer can send or receive in one websocket packet." );
|
||||
// config.set( "max_websocket_message", AddressRule.WEBSOCKET_MESSAGE );
|
||||
// }
|
||||
//
|
||||
// return config;
|
||||
// }
|
||||
//
|
||||
// public static boolean checkRule( UnmodifiableConfig builder )
|
||||
// {
|
||||
// String hostObj = get( builder, "host", String.class ).orElse( null );
|
||||
// return hostObj != null && checkEnum( builder, "action", Action.class )
|
||||
// && check( builder, "port", Number.class )
|
||||
// && check( builder, "timeout", Number.class )
|
||||
// && check( builder, "max_upload", Number.class )
|
||||
// && check( builder, "max_download", Number.class )
|
||||
// && check( builder, "websocket_message", Number.class )
|
||||
// && AddressRule.parse( hostObj, port, PartialOptions.DEFAULT ) != null;
|
||||
// }
|
||||
//
|
||||
// @Nullable
|
||||
// public static AddressRule parseRule( UnmodifiableConfig builder )
|
||||
// {
|
||||
// String hostObj = get( builder, "host", String.class ).orElse( null );
|
||||
// Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null );
|
||||
// if( hostObj == null ) return null;
|
||||
//
|
||||
// Action action = getEnum( builder, "action", Action.class ).orElse( null );
|
||||
// Integer timeout = get( builder, "timeout", Number.class ).map( Number::intValue ).orElse( null );
|
||||
// Long maxUpload = get( builder, "max_upload", Number.class ).map( Number::longValue ).orElse( null );
|
||||
// Long maxDownload = get( builder, "max_download", Number.class ).map( Number::longValue ).orElse( null );
|
||||
// Integer websocketMessage = get( builder, "websocket_message", Number.class ).map( Number::intValue ).orElse( null );
|
||||
//
|
||||
// PartialOptions options = new PartialOptions(
|
||||
// action,
|
||||
// maxUpload,
|
||||
// maxDownload,
|
||||
// timeout,
|
||||
// websocketMessage
|
||||
// );
|
||||
//
|
||||
// return AddressRule.parse( hostObj, port, options );
|
||||
// }
|
||||
//
|
||||
// private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
// {
|
||||
// Object value = config.get( field );
|
||||
// if( value == null || klass.isInstance( value ) ) return true;
|
||||
//
|
||||
// ComputerCraft.log.warn( "HTTP rule's {} is not a {}.", field, klass.getSimpleName() );
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// private static <T extends Enum<T>> boolean checkEnum( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
// {
|
||||
// Object value = config.get( field );
|
||||
// if( value == null ) return true;
|
||||
//
|
||||
// if( !(value instanceof String) )
|
||||
// {
|
||||
// ComputerCraft.log.warn( "HTTP rule's {} is not a string", field );
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// if( parseEnum( klass, (String) value ) == null )
|
||||
// {
|
||||
// ComputerCraft.log.warn( "HTTP rule's {} is not a known option", field );
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// private static <T> Optional<T> get( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
// {
|
||||
// Object value = config.get( field );
|
||||
// return klass.isInstance( value ) ? Optional.of( klass.cast( value ) ) : Optional.empty();
|
||||
// }
|
||||
//
|
||||
// private static <T extends Enum<T>> Optional<T> getEnum( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
// {
|
||||
// return get( config, field, String.class ).map( x -> parseEnum( klass, x ) );
|
||||
// }
|
||||
//
|
||||
// @Nullable
|
||||
// private static <T extends Enum<T>> T parseEnum( Class<T> klass, String x )
|
||||
// {
|
||||
// for( T value : klass.getEnumConstants() )
|
||||
// {
|
||||
// if( value.name().equalsIgnoreCase( x ) ) return value;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
if( host.equals( "*" ) && action == Action.ALLOW )
|
||||
{
|
||||
config.setComment( "timeout", "The period of time (in milliseconds) to wait before a HTTP request times out. Set to 0 for unlimited." );
|
||||
config.add( "timeout", AddressRule.TIMEOUT );
|
||||
|
||||
config.setComment( "max_download", "The maximum size (in bytes) that a computer can download in a single request. Note that responses may receive more data than allowed, but this data will not be returned to the client." );
|
||||
config.set( "max_download", AddressRule.MAX_DOWNLOAD );
|
||||
|
||||
config.setComment( "max_upload", "The maximum size (in bytes) that a computer can upload in a single request. This includes headers and POST text." );
|
||||
config.set( "max_upload", AddressRule.MAX_UPLOAD );
|
||||
|
||||
config.setComment( "max_websocket_message", "The maximum size (in bytes) that a computer can send or receive in one websocket packet." );
|
||||
config.set( "max_websocket_message", AddressRule.WEBSOCKET_MESSAGE );
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
public static boolean checkRule( UnmodifiableConfig builder )
|
||||
{
|
||||
String hostObj = get( builder, "host", String.class ).orElse( null );
|
||||
Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null );
|
||||
return hostObj != null && checkEnum( builder, "action", Action.class )
|
||||
&& check( builder, "port", Number.class )
|
||||
&& check( builder, "timeout", Number.class )
|
||||
&& check( builder, "max_upload", Number.class )
|
||||
&& check( builder, "max_download", Number.class )
|
||||
&& check( builder, "websocket_message", Number.class )
|
||||
&& AddressRule.parse( hostObj, port, PartialOptions.DEFAULT ) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AddressRule parseRule( UnmodifiableConfig builder )
|
||||
{
|
||||
String hostObj = get( builder, "host", String.class ).orElse( null );
|
||||
Integer port = get( builder, "port", Number.class ).map( Number::intValue ).orElse( null );
|
||||
if( hostObj == null ) return null;
|
||||
|
||||
Action action = getEnum( builder, "action", Action.class ).orElse( null );
|
||||
Integer timeout = get( builder, "timeout", Number.class ).map( Number::intValue ).orElse( null );
|
||||
Long maxUpload = get( builder, "max_upload", Number.class ).map( Number::longValue ).orElse( null );
|
||||
Long maxDownload = get( builder, "max_download", Number.class ).map( Number::longValue ).orElse( null );
|
||||
Integer websocketMessage = get( builder, "websocket_message", Number.class ).map( Number::intValue ).orElse( null );
|
||||
|
||||
PartialOptions options = new PartialOptions(
|
||||
action,
|
||||
maxUpload,
|
||||
maxDownload,
|
||||
timeout,
|
||||
websocketMessage
|
||||
);
|
||||
|
||||
return AddressRule.parse( hostObj, port, options );
|
||||
}
|
||||
|
||||
private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
{
|
||||
Object value = config.get( field );
|
||||
if( value == null || klass.isInstance( value ) ) return true;
|
||||
|
||||
ComputerCraft.log.warn( "HTTP rule's {} is not a {}.", field, klass.getSimpleName() );
|
||||
return false;
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> boolean checkEnum( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
{
|
||||
Object value = config.get( field );
|
||||
if( value == null ) return true;
|
||||
|
||||
if( !(value instanceof String) )
|
||||
{
|
||||
ComputerCraft.log.warn( "HTTP rule's {} is not a string", field );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( parseEnum( klass, (String) value ) == null )
|
||||
{
|
||||
ComputerCraft.log.warn( "HTTP rule's {} is not a known option", field );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static <T> Optional<T> get( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
{
|
||||
Object value = config.get( field );
|
||||
return klass.isInstance( value ) ? Optional.of( klass.cast( value ) ) : Optional.empty();
|
||||
}
|
||||
|
||||
private static <T extends Enum<T>> Optional<T> getEnum( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
{
|
||||
return get( config, field, String.class ).map( x -> parseEnum( klass, x ) );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T extends Enum<T>> T parseEnum( Class<T> klass, String x )
|
||||
{
|
||||
for( T value : klass.getEnumConstants() )
|
||||
{
|
||||
if( value.name().equalsIgnoreCase( x ) ) return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -117,7 +117,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")
|
||||
|
@@ -155,7 +155,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
|
||||
|
@@ -181,19 +181,17 @@ public class BlockCable extends BlockGeneric implements Waterloggable {
|
||||
// : new ItemStack( ComputerCraftRegistry.ModItems.CABLE.get() );
|
||||
// }
|
||||
|
||||
// Commenting override to allow cable modems to be placed on chests, so that chests can be generic inventory peripherals.
|
||||
// TODO Perhaps there is a more selective way to achieve this?
|
||||
// @Override
|
||||
// @Deprecated
|
||||
// public boolean canPlaceAt(BlockState state, @Nonnull WorldView world, @Nonnull BlockPos pos) {
|
||||
// Direction facing = state.get(MODEM)
|
||||
// .getFacing();
|
||||
// if (facing == null) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return sideCoversSmallSquare(world, pos.offset(facing), facing.getOpposite());
|
||||
// }
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean canPlaceAt(BlockState state, @Nonnull WorldView world, @Nonnull BlockPos pos) {
|
||||
Direction facing = state.get(MODEM)
|
||||
.getFacing();
|
||||
if (facing == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sideCoversSmallSquare(world, pos.offset(facing), facing.getOpposite());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
|
@@ -80,7 +80,7 @@ public final class ClientMonitor extends ClientTerminal {
|
||||
GL15.glBufferData(GL31.GL_TEXTURE_BUFFER, 0, GL15.GL_STATIC_DRAW);
|
||||
this.tboTexture = GlStateManager.genTextures();
|
||||
GL11.glBindTexture(GL31.GL_TEXTURE_BUFFER, this.tboTexture);
|
||||
GL31.glTexBuffer(GL31.GL_TEXTURE_BUFFER, GL30.GL_R8, this.tboBuffer);
|
||||
GL31.glTexBuffer(GL31.GL_TEXTURE_BUFFER, GL30.GL_R8UI, this.tboBuffer);
|
||||
GL11.glBindTexture(GL31.GL_TEXTURE_BUFFER, 0);
|
||||
|
||||
GlStateManager.bindBuffers(GL31.GL_TEXTURE_BUFFER, 0);
|
||||
|
@@ -19,6 +19,7 @@ import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
@@ -341,7 +342,7 @@ public class TurtleBrain implements ITurtleAccess {
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Nullable
|
||||
@Override
|
||||
public GameProfile getOwningPlayer() {
|
||||
return this.m_owningPlayer;
|
||||
|
@@ -33,6 +33,7 @@ import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.NamedScreenHandlerFactory;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -42,13 +43,33 @@ import net.minecraft.util.math.Vec3d;
|
||||
@SuppressWarnings ("EntityConstructor")
|
||||
public final class TurtlePlayer extends FakePlayer {
|
||||
private static final GameProfile DEFAULT_PROFILE = new GameProfile(UUID.fromString("0d0c4ca0-4ff1-11e4-916c-0800200c9a66"), "[ComputerCraft]");
|
||||
|
||||
private TurtlePlayer(ITurtleAccess turtle) {
|
||||
super((ServerWorld) turtle.getWorld(), getProfile(turtle.getOwningPlayer()));
|
||||
this.networkHandler = new FakeNetHandler(this);
|
||||
this.setState(turtle);
|
||||
// TODO [M3R1-01] Fix Turtle not giving player achievement for actions
|
||||
private TurtlePlayer( ServerWorld world, GameProfile name )
|
||||
{
|
||||
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.networkHandler = 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().getPlayerManager().getPlayer(player.getUuid());
|
||||
if( actualPlayer != null ) player.getAdvancementTracker().setOwner(actualPlayer);
|
||||
}
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
private static GameProfile getProfile(@Nullable GameProfile profile) {
|
||||
return profile != null && profile.isComplete() ? profile : DEFAULT_PROFILE;
|
||||
}
|
||||
@@ -70,14 +91,17 @@ public final class TurtlePlayer extends FakePlayer {
|
||||
}
|
||||
|
||||
public static TurtlePlayer get(ITurtleAccess access) {
|
||||
if (!(access instanceof TurtleBrain)) {
|
||||
return new TurtlePlayer(access);
|
||||
}
|
||||
ServerWorld world = (ServerWorld) access.getWorld();
|
||||
if( !(access instanceof TurtleBrain) ) return create( access );
|
||||
|
||||
/*if (!(access instanceof TurtleBrain)) {
|
||||
return new TurtlePlayer(world, access.getOwningPlayer());
|
||||
}*/
|
||||
|
||||
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 {
|
||||
player.setState(access);
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
View the source code at https://github.com/mystiacraft/cc-tweaked-fabric
|
||||
View the source code at https://github.com/Merith-TK/cc-restiched
|
||||
View the documentation at https://wiki.computercraft.cc
|
||||
Visit the forum at https://forums.computercraft.cc
|
||||
You can disable these messages by running "set motd.enable false"
|
||||
|
@@ -6,7 +6,7 @@
|
||||
uniform sampler2D u_font;
|
||||
uniform int u_width;
|
||||
uniform int u_height;
|
||||
uniform samplerBuffer u_tbo;
|
||||
uniform usamplerBuffer u_tbo;
|
||||
uniform vec3 u_palette[16];
|
||||
|
||||
in vec2 f_pos;
|
||||
@@ -30,9 +30,9 @@ void main() {
|
||||
vec2 outside = step(vec2(0.0, 0.0), vec2(cell)) * step(vec2(cell), vec2(float(u_width) - 1.0, float(u_height) - 1.0));
|
||||
float mult = outside.x * outside.y;
|
||||
|
||||
int character = int(texelFetch(u_tbo, index).r * 255.0);
|
||||
int fg = int(texelFetch(u_tbo, index + 1).r * 255.0);
|
||||
int bg = int(texelFetch(u_tbo, index + 2).r * 255.0);
|
||||
int character = int(texelFetch(u_tbo, index).r);
|
||||
int fg = int(texelFetch(u_tbo, index + 1).r);
|
||||
int bg = int(texelFetch(u_tbo, index + 2).r);
|
||||
|
||||
vec2 pos = (term_pos - corner) * vec2(FONT_WIDTH, FONT_HEIGHT);
|
||||
vec4 img = texture(u_font, (texture_corner(character) + pos) / 256.0);
|
||||
|
@@ -1,15 +1,137 @@
|
||||
--- The Colors API allows you to manipulate sets of colors.
|
||||
--
|
||||
-- This is useful in conjunction with Bundled Cables from the RedPower mod,
|
||||
-- RedNet Cables from the MineFactory Reloaded mod, and colors on Advanced
|
||||
-- Computers and Advanced Monitors.
|
||||
--
|
||||
-- For the non-American English version just replace @{colors} with @{colours}
|
||||
-- and it will use the other API, colours which is exactly the same, except in
|
||||
-- British English (e.g. @{colors.gray} is spelt @{colours.grey}).
|
||||
--
|
||||
-- @see colours
|
||||
-- @module colors
|
||||
--[[- The Colors API allows you to manipulate sets of colors.
|
||||
|
||||
This is useful in conjunction with Bundled Cables from the RedPower mod, RedNet
|
||||
Cables from the MineFactory Reloaded mod, and colors on Advanced Computers and
|
||||
Advanced Monitors.
|
||||
|
||||
For the non-American English version just replace @{colors} with @{colours} and
|
||||
it will use the other API, colours which is exactly the same, except in British
|
||||
English (e.g. @{colors.gray} is spelt @{colours.grey}).
|
||||
|
||||
On basic terminals (such as the Computer and Monitor), all the colors are
|
||||
converted to grayscale. This means you can still use all 16 colors on the
|
||||
screen, but they will appear as the nearest tint of gray. You can check if a
|
||||
terminal supports color by using the function @{term.isColor}.
|
||||
|
||||
Grayscale colors are calculated by taking the average of the three components,
|
||||
i.e. `(red + green + blue) / 3`.
|
||||
|
||||
<table class="pretty-table">
|
||||
<thead>
|
||||
<tr><th colspan="8" align="center">Default Colors</th></tr>
|
||||
<tr>
|
||||
<th rowspan="2" align="center">Color</th>
|
||||
<th colspan="3" align="center">Value</th>
|
||||
<th colspan="4" align="center">Default Palette Color</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Dec</th><th>Hex</th><th>Paint/Blit</th>
|
||||
<th>Preview</th><th>Hex</th><th>RGB</th><th>Grayscale</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>colors.white</code></td>
|
||||
<td align="right">1</td><td align="right">0x1</td><td align="right">0</td>
|
||||
<td style="background:#F0F0F0"></td><td>#F0F0F0</td><td>240, 240, 240</td>
|
||||
<td style="background:#F0F0F0"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.orange</code></td>
|
||||
<td align="right">2</td><td align="right">0x2</td><td align="right">1</td>
|
||||
<td style="background:#F2B233"></td><td>#F2B233</td><td>242, 178, 51</td>
|
||||
<td style="background:#9D9D9D"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.magenta</code></td>
|
||||
<td align="right">4</td><td align="right">0x4</td><td align="right">2</td>
|
||||
<td style="background:#E57FD8"></td><td>#E57FD8</td><td>229, 127, 216</td>
|
||||
<td style="background:#BEBEBE"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.lightBlue</code></td>
|
||||
<td align="right">8</td><td align="right">0x8</td><td align="right">3</td>
|
||||
<td style="background:#99B2F2"></td><td>#99B2F2</td><td>153, 178, 242</td>
|
||||
<td style="background:#BFBFBF"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.yellow</code></td>
|
||||
<td align="right">16</td><td align="right">0x10</td><td align="right">4</td>
|
||||
<td style="background:#DEDE6C"></td><td>#DEDE6C</td><td>222, 222, 108</td>
|
||||
<td style="background:#B8B8B8"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.lime</code></td>
|
||||
<td align="right">32</td><td align="right">0x20</td><td align="right">5</td>
|
||||
<td style="background:#7FCC19"></td><td>#7FCC19</td><td>127, 204, 25</td>
|
||||
<td style="background:#767676"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.pink</code></td>
|
||||
<td align="right">64</td><td align="right">0x40</td><td align="right">6</td>
|
||||
<td style="background:#F2B2CC"></td><td>#F2B2CC</td><td>242, 178, 204</td>
|
||||
<td style="background:#D0D0D0"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.gray</code></td>
|
||||
<td align="right">128</td><td align="right">0x80</td><td align="right">7</td>
|
||||
<td style="background:#4C4C4C"></td><td>#4C4C4C</td><td>76, 76, 76</td>
|
||||
<td style="background:#4C4C4C"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.lightGray</code></td>
|
||||
<td align="right">256</td><td align="right">0x100</td><td align="right">8</td>
|
||||
<td style="background:#999999"></td><td>#999999</td><td>153, 153, 153</td>
|
||||
<td style="background:#999999"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.cyan</code></td>
|
||||
<td align="right">512</td><td align="right">0x200</td><td align="right">9</td>
|
||||
<td style="background:#4C99B2"></td><td>#4C99B2</td><td>76, 153, 178</td>
|
||||
<td style="background:#878787"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.purple</code></td>
|
||||
<td align="right">1024</td><td align="right">0x400</td><td align="right">a</td>
|
||||
<td style="background:#B266E5"></td><td>#B266E5</td><td>178, 102, 229</td>
|
||||
<td style="background:#A9A9A9"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.blue</code></td>
|
||||
<td align="right">2048</td><td align="right">0x800</td><td align="right">b</td>
|
||||
<td style="background:#3366CC"></td><td>#3366CC</td><td>51, 102, 204</td>
|
||||
<td style="background:#777777"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.brown</code></td>
|
||||
<td align="right">4096</td><td align="right">0x1000</td><td align="right">c</td>
|
||||
<td style="background:#7F664C"></td><td>#7F664C</td><td>127, 102, 76</td>
|
||||
<td style="background:#656565"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.green</code></td>
|
||||
<td align="right">8192</td><td align="right">0x2000</td><td align="right">d</td>
|
||||
<td style="background:#57A64E"></td><td>#57A64E</td><td>87, 166, 78</td>
|
||||
<td style="background:#6E6E6E"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.red</code></td>
|
||||
<td align="right">16384</td><td align="right">0x4000</td><td align="right">e</td>
|
||||
<td style="background:#CC4C4C"></td><td>#CC4C4C</td><td>204, 76, 76</td>
|
||||
<td style="background:#767676"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>colors.black</code></td>
|
||||
<td align="right">32768</td><td align="right">0x8000</td><td align="right">f</td>
|
||||
<td style="background:#111111"></td><td>#111111</td><td>17, 17, 17</td>
|
||||
<td style="background:#111111"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@see colours
|
||||
@module colors
|
||||
]]
|
||||
|
||||
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
||||
|
||||
@@ -37,7 +159,7 @@ yellow = 0x10
|
||||
-- terminal colour of #7FCC19.
|
||||
lime = 0x20
|
||||
|
||||
--- Pink. Written as `6` in paint files and @{term.blit}, has a default
|
||||
--- Pink: Written as `6` in paint files and @{term.blit}, has a default
|
||||
-- terminal colour of #F2B2CC.
|
||||
pink = 0x40
|
||||
|
||||
@@ -74,10 +196,11 @@ green = 0x2000
|
||||
red = 0x4000
|
||||
|
||||
--- Black: Written as `f` in paint files and @{term.blit}, has a default
|
||||
-- terminal colour of #191919.
|
||||
-- terminal colour of #111111.
|
||||
black = 0x8000
|
||||
|
||||
--- Combines a set of colors (or sets of colors) into a larger set.
|
||||
--- Combines a set of colors (or sets of colors) into a larger set. Useful for
|
||||
-- Bundled Cables.
|
||||
--
|
||||
-- @tparam number ... The colors to combine.
|
||||
-- @treturn number The union of the color sets given in `...`
|
||||
@@ -96,7 +219,8 @@ function combine(...)
|
||||
return r
|
||||
end
|
||||
|
||||
--- Removes one or more colors (or sets of colors) from an initial set.
|
||||
--- Removes one or more colors (or sets of colors) from an initial set. Useful
|
||||
-- for Bundled Cables.
|
||||
--
|
||||
-- Each parameter beyond the first may be a single color or may be a set of
|
||||
-- colors (in the latter case, all colors in the set are removed from the
|
||||
@@ -121,7 +245,8 @@ function subtract(colors, ...)
|
||||
return r
|
||||
end
|
||||
|
||||
--- Tests whether `color` is contained within `colors`.
|
||||
--- Tests whether `color` is contained within `colors`. Useful for Bundled
|
||||
-- Cables.
|
||||
--
|
||||
-- @tparam number colors A color, or color set
|
||||
-- @tparam number color A color or set of colors that `colors` should contain.
|
||||
@@ -145,7 +270,7 @@ end
|
||||
-- @treturn number The combined hexadecimal colour.
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0.7, 0.2, 0.6)
|
||||
-- colors.unpackRGB(0.7, 0.2, 0.6)
|
||||
-- -- => 0xb23399
|
||||
-- ```
|
||||
function packRGB(r, g, b)
|
||||
@@ -153,7 +278,7 @@ function packRGB(r, g, b)
|
||||
expect(2, g, "number")
|
||||
expect(3, b, "number")
|
||||
return
|
||||
bit32.band(r * 255, 0xFF) * 2 ^ 16 +
|
||||
bit32.band(r * 255, 0xFF) * 2 ^ 16 +
|
||||
bit32.band(g * 255, 0xFF) * 2 ^ 8 +
|
||||
bit32.band(b * 255, 0xFF)
|
||||
end
|
||||
@@ -166,16 +291,16 @@ end
|
||||
-- @treturn number The blue channel, will be between 0 and 1.
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0xb23399)
|
||||
-- colors.unpackRGB(0xb23399)
|
||||
-- -- => 0.7, 0.2, 0.6
|
||||
-- ```
|
||||
-- @see colors.packRGB
|
||||
function unpackRGB(rgb)
|
||||
expect(1, rgb, "number")
|
||||
return
|
||||
bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255,
|
||||
bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255,
|
||||
bit32.band(rgb, 0xFF) / 255
|
||||
bit32.band(bit32.rshift(rgb, 16), 0xFF) / 255,
|
||||
bit32.band(bit32.rshift(rgb, 8), 0xFF) / 255,
|
||||
bit32.band(rgb, 0xFF) / 255
|
||||
end
|
||||
|
||||
--- Either calls @{colors.packRGB} or @{colors.unpackRGB}, depending on how many
|
||||
@@ -192,12 +317,12 @@ end
|
||||
-- @deprecated Use @{packRGB} or @{unpackRGB} directly.
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0xb23399)
|
||||
-- colors.unpackRGB(0xb23399)
|
||||
-- -- => 0.7, 0.2, 0.6
|
||||
-- ```
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0.7, 0.2, 0.6)
|
||||
-- colors.unpackRGB(0.7, 0.2, 0.6)
|
||||
-- -- => 0xb23399
|
||||
-- ```
|
||||
function rgb8(r, g, b)
|
||||
@@ -207,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
|
||||
|
@@ -22,7 +22,7 @@ end
|
||||
--
|
||||
-- @tparam string name The name of the disk drive.
|
||||
-- @treturn boolean If something is in the disk drive.
|
||||
-- @usage disk.isPresent(false)
|
||||
-- @usage disk.isPresent("top")
|
||||
function isPresent(name)
|
||||
if isDrive(name) then
|
||||
return peripheral.call(name, "isDiskPresent")
|
||||
|
@@ -32,7 +32,7 @@ end
|
||||
-- @tparam string topic The topic to find
|
||||
-- @treturn string|nil The path to the given topic's help file, or `nil` if it
|
||||
-- cannot be found.
|
||||
-- @usage print(help.lookup("disk"))
|
||||
-- @usage help.lookup("disk")
|
||||
function lookup(_sTopic)
|
||||
expect(1, _sTopic, "string")
|
||||
-- Look on the path variable
|
||||
|
@@ -145,6 +145,7 @@ keys.cimcumflex = keys.circumflex --- @local
|
||||
--
|
||||
-- @tparam number code The key code to look up.
|
||||
-- @treturn string|nil The name of the key, or `nil` if not a valid key code.
|
||||
-- @usage keys.getName(keys.enter)
|
||||
function getName(_nKey)
|
||||
expect(1, _nKey, "number")
|
||||
return tKeys[_nKey]
|
||||
|
@@ -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
|
||||
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
|
||||
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)
|
||||
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
|
||||
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
|
||||
for y = minY, maxY do
|
||||
term.setCursorPos(minX, y)
|
||||
term.blit((" "):rep(width), colourHex:rep(width), colourHex:rep(width))
|
||||
end
|
||||
end
|
||||
|
||||
|
@@ -191,7 +191,7 @@ end
|
||||
-- filter function, which takes the peripheral's name and wrapped table
|
||||
-- and returns if it should be included in the result.
|
||||
-- @treturn table... 0 or more wrapped peripherals matching the given filters.
|
||||
-- @usage local monitors = { peripheral.find("monitor") }
|
||||
-- @usage { peripheral.find("monitor") }
|
||||
-- @usage peripheral.find("modem", rednet.open)
|
||||
function find(ty, filter)
|
||||
expect(1, ty, "string")
|
||||
|
@@ -9,7 +9,7 @@ local expect, field = expect.expect, expect.field
|
||||
--- Slowly writes string text at current cursor position,
|
||||
-- character-by-character.
|
||||
--
|
||||
-- Like @{write}, this does not insert a newline at the end.
|
||||
-- Like @{_G.write}, this does not insert a newline at the end.
|
||||
--
|
||||
-- @tparam string sText The the text to write to the screen
|
||||
-- @tparam[opt] number nRate The number of characters to write each second,
|
||||
@@ -119,8 +119,8 @@ end
|
||||
-- displayed before prompting.
|
||||
-- @treturn number The number of lines printed.
|
||||
-- @usage
|
||||
-- local width, height = term.getSize()
|
||||
-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2)
|
||||
-- local width, height = term.getSize()
|
||||
-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2)
|
||||
function pagedPrint(_sText, _nFreeLines)
|
||||
expect(2, _nFreeLines, "number", "nil")
|
||||
-- Setup a redirector
|
||||
@@ -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
|
||||
|
||||
@@ -699,7 +706,7 @@ unserialiseJSON = unserialise_json
|
||||
--
|
||||
-- @tparam string str The string to encode
|
||||
-- @treturn string The encoded string.
|
||||
-- @usage print("https://example.com/?view=" .. textutils.urlEncode(read()))
|
||||
-- @usage print("https://example.com/?view=" .. textutils.urlEncode("some text&things"))
|
||||
function urlEncode(str)
|
||||
expect(1, str, "string")
|
||||
if str then
|
||||
@@ -712,7 +719,7 @@ function urlEncode(str)
|
||||
else
|
||||
-- Non-ASCII (encode as UTF-8)
|
||||
return
|
||||
string.format("%%%02X", 192 + bit32.band(bit32.arshift(n, 6), 31)) ..
|
||||
string.format("%%%02X", 192 + bit32.band(bit32.arshift(n, 6), 31)) ..
|
||||
string.format("%%%02X", 128 + bit32.band(n, 63))
|
||||
end
|
||||
end)
|
||||
@@ -737,8 +744,8 @@ local tEmpty = {}
|
||||
--
|
||||
-- @treturn { string... } The (possibly empty) list of completions.
|
||||
-- @see shell.setCompletionFunction
|
||||
-- @see read
|
||||
-- @usage textutils.complete( "pa", getfenv() )
|
||||
-- @see _G.read
|
||||
-- @usage textutils.complete( "pa", _ENV )
|
||||
function complete(sSearchText, tSearchTable)
|
||||
expect(1, sSearchText, "string")
|
||||
expect(2, tSearchTable, "table", "nil")
|
||||
|
@@ -125,7 +125,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
||||
-- Helper functions
|
||||
local function updateCursorPos()
|
||||
if nCursorX >= 1 and nCursorY >= 1 and
|
||||
nCursorX <= nWidth and nCursorY <= nHeight then
|
||||
nCursorX <= nWidth and nCursorY <= nHeight then
|
||||
parent.setCursorPos(nX + nCursorX - 1, nY + nCursorY - 1)
|
||||
else
|
||||
parent.setCursorPos(0, 0)
|
||||
@@ -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,5 +1,5 @@
|
||||
--- A collection of helper methods for working with input completion, such
|
||||
-- as that require by @{read}.
|
||||
-- as that require by @{_G.read}.
|
||||
--
|
||||
-- @module cc.completion
|
||||
-- @see cc.shell.completion For additional helpers to use with
|
||||
@@ -29,7 +29,7 @@ end
|
||||
-- @tparam { string... } choices The list of choices to complete from.
|
||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed item.
|
||||
-- @treturn { string... } A list of suffixes of matching strings.
|
||||
-- @usage Call @{read}, completing the names of various animals.
|
||||
-- @usage Call @{_G.read}, completing the names of various animals.
|
||||
--
|
||||
-- local animals = { "dog", "cat", "lion", "unicorn" }
|
||||
-- read(nil, nil, function(text) return choice(text, animals) end)
|
||||
|
@@ -13,11 +13,11 @@
|
||||
-- @module cc.pretty
|
||||
-- @usage Print a table to the terminal
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- pretty.write(pretty.dump({ 1, 2, 3 }))
|
||||
-- pretty.print(pretty.pretty({ 1, 2, 3 }))
|
||||
--
|
||||
-- @usage Build a custom document and display it
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
|
||||
-- pretty.print(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
|
||||
|
||||
local expect = require "cc.expect"
|
||||
local expect, field = expect.expect, expect.field
|
||||
|
@@ -8,7 +8,7 @@
|
||||
-- wrap them using @{build}, or your own custom function.
|
||||
--
|
||||
-- @module cc.shell.completion
|
||||
-- @see cc.completion For more general helpers, suitable for use with @{read}.
|
||||
-- @see cc.completion For more general helpers, suitable for use with @{_G.read}.
|
||||
-- @see shell.setCompletionFunction
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
|
@@ -1,5 +1,5 @@
|
||||
Please report bugs at https://github.com/Zundrel/cc-tweaked-fabric. Thanks!
|
||||
View the documentation at https://wiki.computercraft.cc
|
||||
Please report bugs at https://github.com/Merith-TK/cc-restiched. Thanks!
|
||||
View the documentation at https://tweaked.cc
|
||||
Show off your programs or ask for help at our forum: https://forums.computercraft.cc
|
||||
You can disable these messages by running "set motd.enable false".
|
||||
Use "pastebin put" to upload a program to pastebin.
|
||||
|
@@ -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,13 +1,15 @@
|
||||
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)
|
||||
if peripheral.getType(sDrive) == "drive" then
|
||||
-- Check the disk exists
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -383,7 +383,7 @@ end
|
||||
--
|
||||
-- @tparam string sLine The input to complete.
|
||||
-- @treturn { string }|nil The list of possible completions.
|
||||
-- @see read For more information about completion.
|
||||
-- @see _G.read For more information about completion.
|
||||
-- @see shell.completeProgram
|
||||
-- @see shell.setCompletionFunction
|
||||
-- @see shell.getCompletionInfo
|
||||
@@ -461,7 +461,7 @@ end
|
||||
-- The completion function.
|
||||
-- @see cc.shell.completion Various utilities to help with writing completion functions.
|
||||
-- @see shell.complete
|
||||
-- @see read For more information about completion.
|
||||
-- @see _G.read For more information about completion.
|
||||
function shell.setCompletionFunction(program, complete)
|
||||
expect(1, program, "string")
|
||||
expect(2, complete, "function")
|
||||
|
@@ -1,5 +1,6 @@
|
||||
if not turtle then
|
||||
printError("Requires a Turtle")
|
||||
local programName = arg[0] or fs.getName(shell.getRunningProgram())
|
||||
print("Usage: " .. programName .. " [number]")
|
||||
return
|
||||
end
|
||||
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -1,20 +1,21 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "computercraft",
|
||||
"name": "CC:T for Fabric",
|
||||
"name": "CC:Restitched",
|
||||
"version": "${version}",
|
||||
"description": "A fork of CC: Tweaked for use with the latest Fabric.",
|
||||
"description": "CC: Tweaked for Fabric.",
|
||||
"license": "ComputerCraft Public License",
|
||||
"icon": "assets/computercraft/pack.png",
|
||||
"contact": {
|
||||
"homepage": "https://github.com/mystiacraft/cc-tweaked-fabric",
|
||||
"issues": "https://github.com/mystiacraft/cc-tweaked-fabric/issues"
|
||||
"homepage": "https://github.com/Merith-TK/cc-restiched",
|
||||
"issues": "https://github.com/Merith-TK/cc-restiched/issues"
|
||||
},
|
||||
"authors": [
|
||||
"Daniel Ratcliffe",
|
||||
"Aaron Mills",
|
||||
"SquidDev",
|
||||
"parly"
|
||||
"parly",
|
||||
"Merith.TK"
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0",
|
||||
|
@@ -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()
|
||||
|
@@ -118,6 +118,56 @@ describe("The window library", function()
|
||||
expect.error(w.reposition, 1, 1, false, 1):eq("bad argument #3 (expected number, got boolean)")
|
||||
expect.error(w.reposition, 1, 1, nil, 1):eq("bad argument #3 (expected number, got nil)")
|
||||
expect.error(w.reposition, 1, 1, 1, nil):eq("bad argument #4 (expected number, got nil)")
|
||||
expect.error(w.reposition, 1, 1, 1, 1, true):eq("bad argument #5 (expected table, got boolean)")
|
||||
end)
|
||||
|
||||
it("can change the buffer", function()
|
||||
local a, b = mk(), mk()
|
||||
local target = window.create(a, 1, 1, a.getSize())
|
||||
|
||||
target.write("Test")
|
||||
expect((a.getLine(1))):equal("Test ")
|
||||
expect({ a.getCursorPos() }):same { 5, 1 }
|
||||
|
||||
target.reposition(1, 1, nil, nil, b)
|
||||
|
||||
target.redraw()
|
||||
expect((a.getLine(1))):equal("Test ")
|
||||
expect({ a.getCursorPos() }):same { 5, 1 }
|
||||
|
||||
target.setCursorPos(1, 1) target.write("More")
|
||||
expect((a.getLine(1))):equal("Test ")
|
||||
expect((b.getLine(1))):equal("More ")
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("Window.getLine", function()
|
||||
it("validates arguments", function()
|
||||
local w = mk()
|
||||
w.getLine(1)
|
||||
local _, y = w.getSize()
|
||||
expect.error(w.getLine, nil):eq("bad argument #1 (expected number, got nil)")
|
||||
expect.error(w.getLine, 0):eq("Line is out of range.")
|
||||
expect.error(w.getLine, y + 1):eq("Line is out of range.")
|
||||
end)
|
||||
|
||||
it("provides a line's contents", function()
|
||||
local w = mk()
|
||||
w.blit("test", "aaaa", "4444")
|
||||
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)
|
||||
|
@@ -0,0 +1,33 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The exec program", function()
|
||||
it("displays an error without the commands api", function()
|
||||
stub(_G, "commands", nil)
|
||||
expect(capture(stub, "/rom/programs/command/exec.lua"))
|
||||
:matches { ok = true, output = "", error = "Requires a Command Computer.\n" }
|
||||
end)
|
||||
|
||||
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: /rom/programs/command/exec.lua <command>\n" }
|
||||
end)
|
||||
|
||||
it("runs a command", function()
|
||||
stub(_G, "commands", {
|
||||
exec = function() return true, { "Hello World!" } end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/command/exec.lua computercraft"))
|
||||
:matches { ok = true, output = "Success\nHello World!\n", error = "" }
|
||||
end)
|
||||
|
||||
it("reports command failures", function()
|
||||
stub(_G, "commands", {
|
||||
exec = function() return false, { "Hello World!" } end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/command/exec.lua computercraft"))
|
||||
:matches { ok = true, output = "Hello World!\n", error = "Failed\n" }
|
||||
end)
|
||||
end)
|
40
src/test/resources/test-rom/spec/programs/copy_spec.lua
Normal file
40
src/test/resources/test-rom/spec/programs/copy_spec.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The copy program", function()
|
||||
local function touch(file)
|
||||
io.open(file, "w"):close()
|
||||
end
|
||||
|
||||
it("copies a file", function()
|
||||
touch("/test-files/copy/a.txt")
|
||||
|
||||
shell.run("copy /test-files/copy/a.txt /test-files/copy/b.txt")
|
||||
|
||||
expect(fs.exists("/test-files/copy/a.txt")):eq(true)
|
||||
expect(fs.exists("/test-files/copy/b.txt")):eq(true)
|
||||
end)
|
||||
|
||||
it("fails when copying a non-existent file", function()
|
||||
expect(capture(stub, "copy nothing destination"))
|
||||
:matches { ok = true, output = "", error = "No matching files\n" }
|
||||
end)
|
||||
|
||||
it("fails when overwriting an existing file", function()
|
||||
touch("/test-files/copy/c.txt")
|
||||
|
||||
expect(capture(stub, "copy /test-files/copy/c.txt /test-files/copy/c.txt"))
|
||||
:matches { ok = true, output = "", error = "Destination exists\n" }
|
||||
end)
|
||||
|
||||
it("fails when copying into read-only locations", function()
|
||||
touch("/test-files/copy/d.txt")
|
||||
|
||||
expect(capture(stub, "copy /test-files/copy/d.txt /rom/test.txt"))
|
||||
:matches { ok = true, output = "", error = "Destination is read-only\n" }
|
||||
end)
|
||||
|
||||
it("displays the usage when given no arguments", function()
|
||||
expect(capture(stub, "copy"))
|
||||
:matches { ok = true, output = "Usage: copy <source> <destination>\n", error = "" }
|
||||
end)
|
||||
end)
|
74
src/test/resources/test-rom/spec/programs/move_spec.lua
Normal file
74
src/test/resources/test-rom/spec/programs/move_spec.lua
Normal file
@@ -0,0 +1,74 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The move program", function()
|
||||
local function cleanup() fs.delete("/test-files/move") end
|
||||
local function touch(file)
|
||||
io.open(file, "w"):close()
|
||||
end
|
||||
|
||||
it("move a file", function()
|
||||
cleanup()
|
||||
touch("/test-files/move/a.txt")
|
||||
|
||||
shell.run("move /test-files/move/a.txt /test-files/move/b.txt")
|
||||
|
||||
expect(fs.exists("/test-files/move/a.txt")):eq(false)
|
||||
expect(fs.exists("/test-files/move/b.txt")):eq(true)
|
||||
end)
|
||||
|
||||
it("moves a file to a directory", function()
|
||||
cleanup()
|
||||
touch("/test-files/move/a.txt")
|
||||
fs.makeDir("/test-files/move/a")
|
||||
|
||||
expect(capture(stub, "move /test-files/move/a.txt /test-files/move/a"))
|
||||
:matches { ok = true }
|
||||
|
||||
expect(fs.exists("/test-files/move/a.txt")):eq(false)
|
||||
expect(fs.exists("/test-files/move/a/a.txt")):eq(true)
|
||||
end)
|
||||
|
||||
it("fails when moving a file which doesn't exist", function()
|
||||
expect(capture(stub, "move nothing destination"))
|
||||
:matches { ok = true, output = "", error = "No matching files\n" }
|
||||
end)
|
||||
|
||||
it("fails when overwriting an existing file", function()
|
||||
cleanup()
|
||||
touch("/test-files/move/a.txt")
|
||||
|
||||
expect(capture(stub, "move /test-files/move/a.txt /test-files/move/a.txt"))
|
||||
:matches { ok = true, output = "", error = "Destination exists\n" }
|
||||
end)
|
||||
|
||||
it("fails when moving to read-only locations", function()
|
||||
cleanup()
|
||||
touch("/test-files/move/a.txt")
|
||||
|
||||
expect(capture(stub, "move /test-files/move/a.txt /rom/test.txt"))
|
||||
:matches { ok = true, output = "", error = "Destination is read-only\n" }
|
||||
end)
|
||||
|
||||
it("fails when moving from read-only locations", function()
|
||||
expect(capture(stub, "move /rom/startup.lua /test-files/move/not-exist.txt"))
|
||||
:matches { ok = true, output = "", error = "Cannot move read-only file /rom/startup.lua\n" }
|
||||
end)
|
||||
|
||||
it("fails when moving mounts", function()
|
||||
expect(capture(stub, "move /rom /test-files/move/rom"))
|
||||
:matches { ok = true, output = "", error = "Cannot move mount /rom\n" }
|
||||
end)
|
||||
|
||||
it("fails when moving a file multiple times", function()
|
||||
cleanup()
|
||||
touch("/test-files/move/a.txt")
|
||||
touch("/test-files/move/b.txt")
|
||||
expect(capture(stub, "move /test-files/move/*.txt /test-files/move/c.txt"))
|
||||
:matches { ok = true, output = "", error = "Cannot overwrite file multiple times\n" }
|
||||
end)
|
||||
|
||||
it("displays the usage with no arguments", function()
|
||||
expect(capture(stub, "move"))
|
||||
:matches { ok = true, output = "Usage: move <source> <destination>\n", error = "" }
|
||||
end)
|
||||
end)
|
@@ -0,0 +1,69 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The craft program", function()
|
||||
it("errors when not a turtle", function()
|
||||
stub(_G, "turtle", nil)
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/craft.lua"))
|
||||
:matches { ok = true, output = "", error = "Requires a Turtle\n" }
|
||||
end)
|
||||
|
||||
it("fails when turtle.craft() is unavailable", function()
|
||||
stub(_G, "turtle", {})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/craft.lua"))
|
||||
:matches { ok = true, output = "Requires a Crafty Turtle\n", error = "" }
|
||||
end)
|
||||
|
||||
it("displays its usage when given no arguments", function()
|
||||
stub(_G, "turtle", { craft = function() end })
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/craft.lua"))
|
||||
:matches { ok = true, output = "Usage: /rom/programs/turtle/craft.lua [number]\n", error = "" }
|
||||
end)
|
||||
|
||||
it("crafts multiple items", function()
|
||||
local item_count = 3
|
||||
stub(_G, "turtle", {
|
||||
craft = function()
|
||||
item_count = 1
|
||||
return true
|
||||
end,
|
||||
getItemCount = function() return item_count end,
|
||||
getSelectedSlot = function() return 1 end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/craft.lua 2"))
|
||||
:matches { ok = true, output = "2 items crafted\n", error = "" }
|
||||
end)
|
||||
|
||||
it("craft a single item", function()
|
||||
local item_count = 2
|
||||
stub(_G, "turtle", {
|
||||
craft = function()
|
||||
item_count = 1
|
||||
return true
|
||||
end,
|
||||
getItemCount = function() return item_count end,
|
||||
getSelectedSlot = function() return 1 end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/craft.lua 1"))
|
||||
:matches { ok = true, output = "1 item crafted\n", error = "" }
|
||||
end)
|
||||
|
||||
it("crafts no items", function()
|
||||
local item_count = 2
|
||||
stub(_G, "turtle", {
|
||||
craft = function()
|
||||
item_count = 1
|
||||
return false
|
||||
end,
|
||||
getItemCount = function() return item_count end,
|
||||
getSelectedSlot = function() return 1 end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/craft.lua 1"))
|
||||
:matches { ok = true, output = "No items crafted\n", error = "" }
|
||||
end)
|
||||
end)
|
@@ -0,0 +1,89 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The turtle equip program", function()
|
||||
it("errors when not a turtle", function()
|
||||
stub(_G, "turtle", nil)
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua"))
|
||||
:matches { ok = true, output = "", error = "Requires a Turtle\n" }
|
||||
end)
|
||||
|
||||
|
||||
it("displays its usage when given no arguments", function()
|
||||
stub(_G, "turtle", {})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua"))
|
||||
:matches { ok = true, output = "Usage: /rom/programs/turtle/equip.lua <slot> <side>\n", error = "" }
|
||||
end)
|
||||
|
||||
it("equip nothing", function()
|
||||
stub(_G, "turtle", {
|
||||
select = function() end,
|
||||
getItemCount = function() return 0 end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left"))
|
||||
:matches { ok = true, output = "Nothing to equip\n", error = "" }
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right"))
|
||||
:matches { ok = true, output = "Nothing to equip\n", error = "" }
|
||||
end)
|
||||
|
||||
it("swaps existing upgrades", function()
|
||||
stub(_G, "turtle", {
|
||||
select = function() end,
|
||||
getItemCount = function() return 1 end,
|
||||
equipLeft = function() return true end,
|
||||
equipRight = function() return true end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left"))
|
||||
:matches { ok = true, output = "Items swapped\n", error = "" }
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right"))
|
||||
:matches { ok = true, output = "Items swapped\n", error = "" }
|
||||
end)
|
||||
|
||||
describe("equips a new upgrade", function()
|
||||
local function setup()
|
||||
local item_count = 1
|
||||
stub(_G, "turtle", {
|
||||
select = function() end,
|
||||
getItemCount = function() return item_count end,
|
||||
equipLeft = function()
|
||||
item_count = 0
|
||||
return true
|
||||
end,
|
||||
equipRight = function()
|
||||
item_count = 0
|
||||
return true
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
it("on the left", function()
|
||||
setup()
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left"))
|
||||
:matches { ok = true, output = "Item equipped\n", error = "" }
|
||||
end)
|
||||
|
||||
it("on the right", function()
|
||||
setup()
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right"))
|
||||
:matches { ok = true, output = "Item equipped\n", error = "" }
|
||||
end)
|
||||
end)
|
||||
|
||||
it("handles when an upgrade cannot be equipped", function()
|
||||
stub(_G, "turtle", {
|
||||
select = function() end,
|
||||
getItemCount = function() return 1 end,
|
||||
equipLeft = function() return false end,
|
||||
equipRight = function() return false end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 left"))
|
||||
:matches { ok = true, output = "Item not equippable\n", error = "" }
|
||||
expect(capture(stub, "/rom/programs/turtle/equip.lua 1 right"))
|
||||
:matches { ok = true, output = "Item not equippable\n", error = "" }
|
||||
end)
|
||||
|
||||
end)
|
@@ -0,0 +1,62 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The refuel program", function()
|
||||
local function setup_turtle(fuel_level, fuel_limit, item_count)
|
||||
stub(_G, "turtle", {
|
||||
getFuelLevel = function()
|
||||
return fuel_level
|
||||
end,
|
||||
getItemCount = function()
|
||||
return item_count
|
||||
end,
|
||||
refuel = function(nLimit)
|
||||
item_count = item_count - nLimit
|
||||
fuel_level = fuel_level + nLimit
|
||||
end,
|
||||
select = function()
|
||||
end,
|
||||
getFuelLimit = function()
|
||||
return fuel_limit
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
it("errors when not a turtle", function()
|
||||
stub(_G, "turtle", nil)
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/refuel.lua"))
|
||||
:matches { ok = true, output = "", error = "Requires a Turtle\n" }
|
||||
end)
|
||||
|
||||
|
||||
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: /rom/programs/turtle/refuel.lua [number]\n", error = "" }
|
||||
end)
|
||||
|
||||
it("requires a numeric argument", function()
|
||||
setup_turtle(0, 0, 0)
|
||||
expect(capture(stub, "/rom/programs/turtle/refuel.lua nothing"))
|
||||
:matches { ok = true, output = "Invalid limit, expected a number or \"all\"\n", error = "" }
|
||||
end)
|
||||
|
||||
it("refuels the turtle", function()
|
||||
setup_turtle(0, 10, 5)
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/refuel.lua 5"))
|
||||
:matches { ok = true, output = "Fuel level is 5\n", error = "" }
|
||||
end)
|
||||
|
||||
it("reports when the fuel limit is reached", function()
|
||||
setup_turtle(0, 5, 5)
|
||||
expect(capture(stub, "/rom/programs/turtle/refuel.lua 5"))
|
||||
:matches { ok = true, output = "Fuel level is 5\nFuel limit reached\n", error = "" }
|
||||
end)
|
||||
|
||||
it("reports when the fuel level is unlimited", function()
|
||||
setup_turtle("unlimited", 5, 5)
|
||||
expect(capture(stub, "/rom/programs/turtle/refuel.lua 5"))
|
||||
:matches { ok = true, output = "Fuel level is unlimited\n", error = "" }
|
||||
end)
|
||||
end)
|
@@ -0,0 +1,69 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The turtle unequip program", function()
|
||||
it("errors when not a turtle", function()
|
||||
stub(_G, "turtle", nil)
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua"))
|
||||
:matches { ok = true, output = "", error = "Requires a Turtle\n" }
|
||||
end)
|
||||
|
||||
|
||||
it("displays its usage when given no arguments", function()
|
||||
stub(_G, "turtle", {})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua"))
|
||||
:matches { ok = true, output = "Usage: /rom/programs/turtle/unequip.lua <side>\n", error = "" }
|
||||
end)
|
||||
|
||||
it("says when nothing was unequipped", function()
|
||||
stub(_G, "turtle", {
|
||||
select = function() end,
|
||||
getItemCount = function() return 0 end,
|
||||
equipRight = function() return true end,
|
||||
equipLeft = function() return true end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua left"))
|
||||
:matches { ok = true, output = "Nothing to unequip\n", error = "" }
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua right"))
|
||||
:matches { ok = true, output = "Nothing to unequip\n", error = "" }
|
||||
end)
|
||||
|
||||
it("unequips a upgrade", function()
|
||||
local item_count = 0
|
||||
stub(_G, "turtle", {
|
||||
select = function() end,
|
||||
getItemCount = function() return item_count end,
|
||||
equipRight = function()
|
||||
item_count = 1
|
||||
return true
|
||||
end,
|
||||
equipLeft = function()
|
||||
item_count = 1
|
||||
return true
|
||||
end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua left"))
|
||||
:matches { ok = true, output = "Item unequipped\n", error = "" }
|
||||
item_count = 0
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua right"))
|
||||
:matches { ok = true, output = "Item unequipped\n", error = "" }
|
||||
end)
|
||||
|
||||
it("fails when the turtle is full", function()
|
||||
stub(_G, "turtle", {
|
||||
select = function() end,
|
||||
getItemCount = function() return 1 end,
|
||||
equipRight = function() return true end,
|
||||
equipLeft = function() return true end,
|
||||
})
|
||||
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua left"))
|
||||
:matches { ok = true, output = "No space to unequip item\n", error = "" }
|
||||
expect(capture(stub, "/rom/programs/turtle/unequip.lua right"))
|
||||
:matches { ok = true, output = "No space to unequip item\n", error = "" }
|
||||
end)
|
||||
|
||||
end)
|
Reference in New Issue
Block a user