mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-26 23:42:18 +00:00
Merge pull request #36 from Merith-TK/fabric
Update to Match CC:T version
This commit is contained in:
commit
7b93f91ffa
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-Tweaked
|
||||
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
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -15,3 +15,4 @@
|
||||
.idea
|
||||
.gradle
|
||||
*.DS_Store
|
||||
.project
|
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.configuration.updateBuildConfiguration": "automatic"
|
||||
}
|
13
README.md
13
README.md
@ -1,4 +1,9 @@
|
||||
# CC:T for Fabric
|
||||
# This is a 'complete' port
|
||||
*complete as in it runs and works-ish*
|
||||
I'm busy with other projects and so if anyone else wants to maintain this be my guest
|
||||
# CC:Restitched Patchwork
|
||||
# This is a Work In Progress Port
|
||||
*it runs and works-ish*
|
||||
|
||||
## Reached Parity with CC:T 1.94.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)
|
||||
|
@ -2,7 +2,7 @@
|
||||
org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Mod properties
|
||||
mod_version=1.91.2
|
||||
mod_version=1.94.0
|
||||
|
||||
# Minecraft properties
|
||||
mc_version=1.16.2
|
||||
|
313
patchwork.md
Normal file
313
patchwork.md
Normal file
@ -0,0 +1,313 @@
|
||||
# Just my list of things I have ported over
|
||||
|
||||
Format for the changelog of ported stuff
|
||||
```
|
||||
commit // Shows commit from CC:T
|
||||
commit2 // Shows a commit that is the same thing, just a clean up, only if right after
|
||||
Title // Commit Title
|
||||
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
|
||||
5155e18de279a193c558aa029963486fd1294769
|
||||
Added translation for Vietnamese
|
||||
Co-authored-by: Boom <boom@flyingpackets.net>
|
||||
```
|
||||
|
||||
```
|
||||
7e121ff72f2b1504cd6af47b57500876682bac45
|
||||
ae6124d1f477487abab1858abde8c4ec49dfee3c
|
||||
Translations for Vienamese
|
||||
Co-authored-by: Boom <boom@flyingpackets.net>
|
||||
```
|
||||
|
||||
```
|
||||
59de21eae29849988e77fad6bc335f5ce78dfec7
|
||||
Handle tabs when parsing JSON
|
||||
Fixes #539
|
||||
```
|
||||
|
||||
```
|
||||
748ebbe66bf0a4239bde34f557e4b4b75d61d990
|
||||
Bump to 1.92.0
|
||||
A tiny release, but there's new features so it's technically a minor
|
||||
bump.
|
||||
```
|
||||
|
||||
Cherry Picked because this update was partially related to forge updates rather than mod updates
|
||||
```
|
||||
8b4a01df27ff7f6fa9ffd9c2188c6e3166edd515
|
||||
Update to Minecraft 1.16.3
|
||||
|
||||
I hope the Fabric folks now realise this is gonna be a race of who can
|
||||
update first :p. Either way, this was a very easy update - only changes
|
||||
were due to unrelated Forge changes.
|
||||
```
|
||||
|
||||
```
|
||||
87393e8aef9ddfaca465d626ee7cff5ff499a7e8
|
||||
Fix additional `-` in docs
|
||||
|
||||
Why isn't this automatically stripped! Bad squid.
|
||||
```
|
||||
|
||||
```
|
||||
275ca58a82c627128a145a8754cbe32568536bd9
|
||||
HTTP rules now allow filtering by port
|
||||
|
||||
The HTTP filtering system becomes even more complex! Though in this
|
||||
case, it's pretty minimal, and definitely worth doing.
|
||||
|
||||
For instance, the following rule will allow connecting to localhost on
|
||||
port :8080.
|
||||
|
||||
[[http.rules]]
|
||||
host = "127.0.0.1"
|
||||
port = 8080
|
||||
action = "allow"
|
||||
|
||||
# Other rules as before.
|
||||
|
||||
Closes #540
|
||||
```
|
||||
|
||||
The alterations in ColourUtils.java were not needed so they were not ported over
|
||||
```
|
||||
6f868849ab2f264508e12c184cc56f2632aaf5bc
|
||||
Use tags to check if something is a dye
|
||||
|
||||
We half did this already, just needed to change a couple of checks.
|
||||
Closes #541.
|
||||
```
|
||||
|
||||
```
|
||||
6cee4efcd3610536ee74330cd728f7371011e5a8
|
||||
Fix incorrect open container check
|
||||
|
||||
Was this always broken, or did it happen in a Minecraft update? Don't
|
||||
know, but it's a very silly mistake either way. Fixes #544
|
||||
```
|
||||
|
||||
```
|
||||
0832974725b2478c5227b81f82c35bbf03cf6aba
|
||||
Translations for Swedish
|
||||
|
||||
Co-authored-by: David Isaksson <davidisaksson93@gmail.com>
|
||||
```
|
||||
|
||||
```
|
||||
84036d97d99efd8762e0170002060ae3471508bf
|
||||
Fix io.open documentation
|
||||
|
||||
Well, that was silly.
|
||||
```
|
||||
|
||||
I set the default properties for computers as `Block.GLASS` and then set their strength to `2F` and their soundgroup to stone
|
||||
```
|
||||
8472112fc1eaad18ed6ed2c6c62b040fe421e81a
|
||||
Don't propagate adjacent redstone signals for computers (#549)
|
||||
|
||||
Minecraft propagates "strong" redstone signals (such as those directly
|
||||
from comparators or repeaters) through solid blocks. This includes
|
||||
computers, which is a little annoying as it means one cannot feed
|
||||
redstone wire from one side and a repeater from another.
|
||||
|
||||
This changes computers to not propagate strong redstone signals, in the
|
||||
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 :).
|
||||
```
|
@ -126,10 +126,10 @@ public final class ComputerCraft implements ModInitializer {
|
||||
|
||||
public static List<AddressRule> buildHttpRulesFromConfig(String[] blacklist, String[] whitelist) {
|
||||
return Stream.concat(Stream.of(blacklist)
|
||||
.map(x -> AddressRule.parse(x, Action.DENY.toPartial()))
|
||||
.map( x -> AddressRule.parse( x, null, Action.DENY.toPartial()))
|
||||
.filter(Objects::nonNull),
|
||||
Stream.of(whitelist)
|
||||
.map(x -> AddressRule.parse(x, Action.ALLOW.toPartial()))
|
||||
.map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial()))
|
||||
.filter(Objects::nonNull))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -21,14 +21,14 @@ public class CheckUrl extends Resource<CheckUrl> {
|
||||
private static final String EVENT = "http_check";
|
||||
private final IAPIEnvironment environment;
|
||||
private final String address;
|
||||
private final String host;
|
||||
private final URI uri;
|
||||
private Future<?> future;
|
||||
|
||||
public CheckUrl(ResourceGroup<CheckUrl> limiter, IAPIEnvironment environment, String address, URI uri) {
|
||||
super(limiter);
|
||||
this.environment = environment;
|
||||
this.address = address;
|
||||
this.host = uri.getHost();
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
@ -45,8 +45,9 @@ public class CheckUrl extends Resource<CheckUrl> {
|
||||
}
|
||||
|
||||
try {
|
||||
InetSocketAddress netAddress = NetworkUtils.getAddress(this.host, 80, false);
|
||||
NetworkUtils.getOptions(this.host, netAddress);
|
||||
boolean ssl = uri.getScheme().equalsIgnoreCase( "https" );
|
||||
InetSocketAddress netAddress = NetworkUtils.getAddress( uri, ssl );
|
||||
NetworkUtils.getOptions( uri.getHost(), netAddress );
|
||||
|
||||
if (this.tryClose()) {
|
||||
this.environment.queueEvent(EVENT, this.address, true);
|
||||
|
@ -7,6 +7,7 @@
|
||||
package dan200.computercraft.core.apis.http;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.security.KeyStore;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
@ -94,6 +95,21 @@ public final class NetworkUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link InetSocketAddress} from a {@link java.net.URI}.
|
||||
*
|
||||
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
|
||||
*
|
||||
* @param uri The URI to fetch.
|
||||
* @param ssl Whether to connect with SSL. This is used to find the default port if not otherwise specified.
|
||||
* @return The resolved address.
|
||||
* @throws HTTPRequestException If the host is not malformed.
|
||||
*/
|
||||
public static InetSocketAddress getAddress( URI uri, boolean ssl ) throws HTTPRequestException
|
||||
{
|
||||
return getAddress( uri.getHost(), uri.getPort(), ssl );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link InetSocketAddress} from the resolved {@code host} and port.
|
||||
*
|
||||
@ -125,7 +141,7 @@ public final class NetworkUtils {
|
||||
* @throws HTTPRequestException If the host is not permitted
|
||||
*/
|
||||
public static Options getOptions(String host, InetSocketAddress address) throws HTTPRequestException {
|
||||
Options options = AddressRule.apply(ComputerCraft.httpRules, host, address.getAddress());
|
||||
Options options = AddressRule.apply( ComputerCraft.httpRules, host, address );
|
||||
if (options.action == Action.DENY) {
|
||||
throw new HTTPRequestException("Domain not permitted");
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ package dan200.computercraft.core.apis.http.options;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@ -26,15 +27,22 @@ public final class AddressRule {
|
||||
public static final int WEBSOCKET_MESSAGE = 128 * 1024;
|
||||
private final HostRange ip;
|
||||
private final Pattern domainPattern;
|
||||
private final Integer port;
|
||||
private final PartialOptions partial;
|
||||
private AddressRule(@Nullable HostRange ip, @Nullable Pattern domainPattern, @Nonnull PartialOptions partial) {
|
||||
private AddressRule(
|
||||
@Nullable HostRange ip,
|
||||
@Nullable Pattern domainPattern,
|
||||
@Nullable Integer port,
|
||||
@Nonnull PartialOptions partial )
|
||||
{
|
||||
this.ip = ip;
|
||||
this.domainPattern = domainPattern;
|
||||
this.partial = partial;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static AddressRule parse(String filter, @Nonnull PartialOptions partial) {
|
||||
public static AddressRule parse( String filter, @Nullable Integer port, @Nonnull PartialOptions partial ) {
|
||||
int cidr = filter.indexOf('/');
|
||||
if (cidr >= 0) {
|
||||
String addressStr = filter.substring(0, cidr);
|
||||
@ -73,14 +81,14 @@ public final class AddressRule {
|
||||
size -= 8;
|
||||
}
|
||||
|
||||
return new AddressRule(new HostRange(minBytes, maxBytes), null, partial);
|
||||
return new AddressRule(new HostRange(minBytes, maxBytes), null, port, partial);
|
||||
} else {
|
||||
Pattern pattern = Pattern.compile("^\\Q" + filter.replaceAll("\\*", "\\\\E.*\\\\Q") + "\\E$");
|
||||
return new AddressRule(null, pattern, partial);
|
||||
return new AddressRule(null, pattern, port, partial);
|
||||
}
|
||||
}
|
||||
|
||||
public static Options apply(Iterable<? extends AddressRule> rules, String domain, InetAddress address) {
|
||||
public static Options apply(Iterable<? extends AddressRule> rules, String domain, InetSocketAddress address) {
|
||||
PartialOptions options = null;
|
||||
boolean hasMany = false;
|
||||
|
||||
@ -108,11 +116,14 @@ public final class AddressRule {
|
||||
/**
|
||||
* Determine whether the given address matches a series of patterns.
|
||||
*
|
||||
* @param domain The domain to match
|
||||
* @param address The address to check.
|
||||
* @param domain The domain to match
|
||||
* @param socketAddress The address to check.
|
||||
* @return Whether it matches any of these patterns.
|
||||
*/
|
||||
private boolean matches(String domain, InetAddress address) {
|
||||
private boolean matches(String domain, InetSocketAddress socketAddress) {
|
||||
InetAddress address = socketAddress.getAddress();
|
||||
if( port != null && port != socketAddress.getPort() ) return false;
|
||||
|
||||
if (this.domainPattern != null) {
|
||||
if (this.domainPattern.matcher(domain)
|
||||
.matches()) {
|
||||
|
@ -9,6 +9,8 @@ package dan200.computercraft.core.apis.http.options;
|
||||
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 );
|
||||
@ -39,17 +41,19 @@ public class AddressRuleConfig {
|
||||
// {
|
||||
// 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, PartialOptions.DEFAULT ) != null;
|
||||
// && 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 );
|
||||
@ -66,7 +70,7 @@ public class AddressRuleConfig {
|
||||
// websocketMessage
|
||||
// );
|
||||
//
|
||||
// return AddressRule.parse( hostObj, options );
|
||||
// return AddressRule.parse( hostObj, port, options );
|
||||
// }
|
||||
//
|
||||
// private static <T> boolean check( UnmodifiableConfig config, String field, Class<T> klass )
|
||||
|
@ -131,7 +131,7 @@ public class HttpRequest extends Resource<HttpRequest> {
|
||||
try {
|
||||
boolean ssl = uri.getScheme()
|
||||
.equalsIgnoreCase("https");
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress(uri.getHost(), uri.getPort(), ssl);
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress(uri, ssl);
|
||||
Options options = NetworkUtils.getOptions(uri.getHost(), socketAddress);
|
||||
SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null;
|
||||
|
||||
|
@ -117,7 +117,7 @@ public class Websocket extends Resource<Websocket> {
|
||||
boolean ssl = this.uri.getScheme()
|
||||
.equalsIgnoreCase("wss");
|
||||
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress(this.uri.getHost(), this.uri.getPort(), ssl);
|
||||
InetSocketAddress socketAddress = NetworkUtils.getAddress(uri, ssl);
|
||||
Options options = NetworkUtils.getOptions(this.uri.getHost(), socketAddress);
|
||||
SslContext sslContext = ssl ? NetworkUtils.getSslContext() : null;
|
||||
|
||||
|
@ -55,6 +55,7 @@ import dan200.computercraft.shared.turtle.items.ItemTurtle;
|
||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
||||
import dan200.computercraft.shared.util.FixedPointTileEntityType;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.Material;
|
||||
@ -68,6 +69,7 @@ import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.ScreenHandlerType;
|
||||
import net.minecraft.sound.BlockSoundGroup;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
@ -121,8 +123,12 @@ public final class ComputerCraftRegistry {
|
||||
public static final BlockCable CABLE = register("cable", new BlockCable(emProperties()));
|
||||
|
||||
private static Block.Settings properties() {
|
||||
return FabricBlockSettings.copyOf(Blocks.STONE)
|
||||
.strength(2);
|
||||
//return FabricBlockSettings.copyOf(Blocks.GLASS)
|
||||
// .strength(2);
|
||||
return AbstractBlock.Settings.of(Material.GLASS)
|
||||
.strength(2F)
|
||||
.sounds(BlockSoundGroup.STONE)
|
||||
.nonOpaque();
|
||||
}
|
||||
|
||||
private static Block.Settings turtleProperties() {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -15,7 +15,6 @@ import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.SimpleInventory;
|
||||
import net.minecraft.item.DyeItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.ArrayPropertyDelegate;
|
||||
import net.minecraft.screen.PropertyDelegate;
|
||||
@ -87,7 +86,7 @@ public class ContainerPrinter extends ScreenHandler {
|
||||
}
|
||||
} else {
|
||||
// Transfer from inventory to printer
|
||||
if (stack.getItem() instanceof DyeItem) {
|
||||
if( TilePrinter.isInk( stack ) ) {
|
||||
if (!this.insertItem(stack, 0, 1, false)) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
@ -278,8 +278,8 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInk(@Nonnull ItemStack stack) {
|
||||
return stack.getItem() instanceof DyeItem;
|
||||
static boolean isInk(@Nonnull ItemStack stack) {
|
||||
return ColourUtils.getStackColour( stack ) != null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@ -380,9 +380,8 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
|
||||
|
||||
private boolean inputPage() {
|
||||
ItemStack inkStack = this.m_inventory.get(0);
|
||||
if (!isInk(inkStack)) {
|
||||
return false;
|
||||
}
|
||||
DyeColor dye = ColourUtils.getStackColour( inkStack );
|
||||
if( dye == null ) return false;
|
||||
|
||||
for (int i = 1; i < 7; i++) {
|
||||
ItemStack paperStack = this.m_inventory.get(i);
|
||||
@ -391,8 +390,7 @@ public final class TilePrinter extends TileGeneric implements DefaultSidedInvent
|
||||
}
|
||||
|
||||
// Setup the new page
|
||||
DyeColor dye = ColourUtils.getStackColour(inkStack);
|
||||
this.m_page.setTextColour(dye != null ? dye.getId() : 15);
|
||||
m_page.setTextColour( dye.getId() );
|
||||
|
||||
this.m_page.clear();
|
||||
if (paperStack.getItem() instanceof ItemPrintout) {
|
||||
|
@ -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,22 +43,41 @@ 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;
|
||||
}
|
||||
|
||||
private void setState(ITurtleAccess turtle) {
|
||||
if (this.currentScreenHandler != null) {
|
||||
if (this.currentScreenHandler != playerScreenHandler) {
|
||||
ComputerCraft.log.warn("Turtle has open container ({})", this.currentScreenHandler);
|
||||
this.currentScreenHandler.close(this);
|
||||
this.currentScreenHandler = null;
|
||||
closeCurrentScreen();
|
||||
}
|
||||
|
||||
BlockPos position = turtle.getPosition();
|
||||
@ -71,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);
|
||||
}
|
||||
|
@ -35,8 +35,6 @@ public final class DropConsumer {
|
||||
dropWorld = new WeakReference<>(entity.world);
|
||||
dropPos = null;
|
||||
dropBounds = new Box(entity.getBlockPos()).expand(2, 2, 2);
|
||||
|
||||
// entity.getScale().captureDrops( new ArrayList<>() );
|
||||
}
|
||||
|
||||
public static void set(World world, BlockPos pos, Function<ItemStack, ItemStack> consumer) {
|
||||
|
@ -1,14 +1,14 @@
|
||||
{
|
||||
"block.computercraft.computer_normal": "Dator",
|
||||
"block.computercraft.computer_advanced": "Avancerad Dator",
|
||||
"block.computercraft.computer_command": "Kommando Dator",
|
||||
"block.computercraft.computer_command": "Kommandodator",
|
||||
"block.computercraft.disk_drive": "Diskettläsare",
|
||||
"block.computercraft.printer": "Skrivare",
|
||||
"block.computercraft.speaker": "Högtalare",
|
||||
"block.computercraft.monitor_normal": "Skärm",
|
||||
"block.computercraft.monitor_advanced": "Avancerad Skärm",
|
||||
"block.computercraft.wireless_modem_normal": "Trådlöst Modem",
|
||||
"block.computercraft.wireless_modem_advanced": "Ender Modem",
|
||||
"block.computercraft.wireless_modem_advanced": "Endermodem",
|
||||
"block.computercraft.wired_modem": "Trådat Modem",
|
||||
"block.computercraft.cable": "Nätverkskabel",
|
||||
"block.computercraft.wired_modem_full": "Trådat Modem",
|
||||
@ -38,5 +38,76 @@
|
||||
"upgrade.computercraft.speaker.adjective": "Högljudd",
|
||||
"chat.computercraft.wired_modem.peripheral_connected": "Kringutrustning \"%s\" är kopplad till nätverket",
|
||||
"chat.computercraft.wired_modem.peripheral_disconnected": "Kringutrustning \"%s\" är frånkopplad från nätverket",
|
||||
"gui.computercraft.tooltip.copy": "Kopiera till urklipp"
|
||||
"gui.computercraft.tooltip.copy": "Kopiera till urklipp",
|
||||
"gui.computercraft.tooltip.disk_id": "Diskett-ID: %s",
|
||||
"gui.computercraft.tooltip.computer_id": "Dator-ID: %s",
|
||||
"tracking_field.computercraft.coroutines_dead.name": "Coroutines borttagna",
|
||||
"tracking_field.computercraft.coroutines_created.name": "Coroutines skapade",
|
||||
"tracking_field.computercraft.websocket_outgoing.name": "Websocket utgående",
|
||||
"tracking_field.computercraft.websocket_incoming.name": "Websocket ingående",
|
||||
"tracking_field.computercraft.http_download.name": "HTTP-nedladdning",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP-uppladdning",
|
||||
"tracking_field.computercraft.http.name": "HTTP-förfrågningar",
|
||||
"tracking_field.computercraft.turtle.name": "Turtle-operationer",
|
||||
"tracking_field.computercraft.fs.name": "Filsystemoperationer",
|
||||
"tracking_field.computercraft.peripheral.name": "Samtal till kringutrustning",
|
||||
"tracking_field.computercraft.server_time.name": "Serveraktivitetstid",
|
||||
"tracking_field.computercraft.server_count.name": "Antal serveruppgifter",
|
||||
"tracking_field.computercraft.max.name": "Max tid",
|
||||
"tracking_field.computercraft.average.name": "Genomsnittlig tid",
|
||||
"tracking_field.computercraft.total.name": "Total tid",
|
||||
"tracking_field.computercraft.tasks.name": "Uppgifter",
|
||||
"argument.computercraft.argument_expected": "Argument förväntas",
|
||||
"argument.computercraft.tracking_field.no_field": "Okänt fält '%s'",
|
||||
"argument.computercraft.computer.many_matching": "Flera datorer matchar '%s' (%s träffar)",
|
||||
"argument.computercraft.computer.no_matching": "Inga datorer matchar '%s'",
|
||||
"commands.computercraft.generic.additional_rows": "%d ytterligare rader…",
|
||||
"commands.computercraft.generic.exception": "Ohanterat felfall (%s)",
|
||||
"commands.computercraft.generic.no": "N",
|
||||
"commands.computercraft.generic.yes": "J",
|
||||
"commands.computercraft.generic.position": "%s, %s, %s",
|
||||
"commands.computercraft.generic.no_position": "<no pos>",
|
||||
"commands.computercraft.queue.desc": "Skicka ett computer_command event till en kommandodator, skicka vidare ytterligare argument. Detta är mestadels utformat för kartmarkörer som fungerar som en mer datorvänlig version av /trigger. Alla spelare kan köra kommandot, vilket sannolikt skulle göras genom en textkomponents klick-event.",
|
||||
"commands.computercraft.queue.synopsis": "Skicka ett computer_command event till en kommandodator",
|
||||
"commands.computercraft.reload.done": "Konfiguration omladdad",
|
||||
"commands.computercraft.reload.desc": "Ladda om ComputerCrafts konfigurationsfil",
|
||||
"commands.computercraft.reload.synopsis": "Ladda om ComputerCrafts konfigurationsfil",
|
||||
"commands.computercraft.track.dump.computer": "Dator",
|
||||
"commands.computercraft.track.dump.no_timings": "Inga tidtagningar tillgängliga",
|
||||
"commands.computercraft.track.dump.desc": "Dumpa de senaste resultaten av datorspårning.",
|
||||
"commands.computercraft.track.dump.synopsis": "Dumpa de senaste spårningsresultaten",
|
||||
"commands.computercraft.track.stop.not_enabled": "Spårar för tillfället inga datorer",
|
||||
"commands.computercraft.track.stop.action": "Klicka för att stoppa spårning",
|
||||
"commands.computercraft.track.stop.desc": "Stoppa spårning av alla datorers körtider och eventräkningar",
|
||||
"commands.computercraft.track.stop.synopsis": "Stoppa spårning för alla datorer",
|
||||
"commands.computercraft.track.start.stop": "Kör %s för att stoppa spårning och visa resultaten",
|
||||
"commands.computercraft.track.start.desc": "Börja spåra alla dators körtider och eventräkningar. Detta kommer återställa resultaten från tidigare körningar.",
|
||||
"commands.computercraft.track.start.synopsis": "Starta spårning för alla datorer",
|
||||
"commands.computercraft.track.desc": "Spåra hur länge datorer exekverar, och även hur många event de hanterar. Detta presenterar information på liknande sätt som /forge track och kan vara användbart för att undersöka lagg.",
|
||||
"commands.computercraft.track.synopsis": "Spåra körningstider för denna dator.",
|
||||
"commands.computercraft.view.not_player": "Kan inte öppna terminalen för en ickespelare",
|
||||
"commands.computercraft.view.action": "Titta på denna dator",
|
||||
"commands.computercraft.view.desc": "Öppna datorns terminal för att möjligöra fjärrstyrning. Detta ger inte tillgång till turtlens inventory. Du kan ange en dators instans-id (t.ex. 123) eller dator-id (t.ex. #123).",
|
||||
"commands.computercraft.view.synopsis": "Titta på datorns terminal.",
|
||||
"commands.computercraft.tp.not_there": "Kan inte hitta datorn i världen",
|
||||
"commands.computercraft.tp.not_player": "Kan inte öppna terminalen för en ickespelare",
|
||||
"commands.computercraft.tp.action": "Teleportera till den här datorn",
|
||||
"commands.computercraft.tp.desc": "Teleportera till datorns position. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
|
||||
"commands.computercraft.tp.synopsis": "Teleportera till en specifik dator.",
|
||||
"commands.computercraft.turn_on.done": "Startade %s/%s datorer",
|
||||
"commands.computercraft.turn_on.desc": "Starta de listade datorerna eller alla om ingen anges. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
|
||||
"commands.computercraft.turn_on.synopsis": "Starta på datorer på distans.",
|
||||
"commands.computercraft.shutdown.done": "Stängde av %s/%s datorer",
|
||||
"commands.computercraft.dump.desc": "Visa status för alla datorer eller specifik information för en dator. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
|
||||
"commands.computercraft.shutdown.desc": "Stäng av de listade datorerna eller alla om ingen anges. Du kan ange en dators instans-id (t.ex. 123), dator-id (t.ex. #123) eller etikett (t.ex. \"@Min dator\").",
|
||||
"commands.computercraft.shutdown.synopsis": "Stäng av datorer på distans.",
|
||||
"commands.computercraft.dump.action": "Visa mer information om den här datorn",
|
||||
"commands.computercraft.dump.synopsis": "Visa status för datorer.",
|
||||
"commands.computercraft.help.no_command": "Inget sådant kommando '%s'",
|
||||
"commands.computercraft.help.no_children": "%s har inget underkommando",
|
||||
"commands.computercraft.help.desc": "Visa detta hjälpmeddelande",
|
||||
"commands.computercraft.help.synopsis": "Tillhandahåll hjälp för ett specifikt kommando",
|
||||
"commands.computercraft.desc": "/computercraft kommandot tillhandahåller olika debugging- och administrationsverktyg för att kontrollera och interagera med datorer.",
|
||||
"commands.computercraft.synopsis": "Olika kommandon för att kontrollera datorer.",
|
||||
"itemGroup.computercraft": "ComputerCraft"
|
||||
}
|
||||
|
48
src/main/resources/assets/computercraft/lang/vi.json
Normal file
48
src/main/resources/assets/computercraft/lang/vi.json
Normal file
@ -0,0 +1,48 @@
|
||||
{
|
||||
"gui.computercraft.tooltip.disk_id": "ID của đĩa: %s",
|
||||
"upgrade.computercraft.speaker.adjective": "Ồn ào",
|
||||
"upgrade.computercraft.wireless_modem_advanced.adjective": "Ender",
|
||||
"upgrade.computercraft.wireless_modem_normal.adjective": "Không dây",
|
||||
"upgrade.minecraft.crafting_table.adjective": "Chế tạo",
|
||||
"upgrade.minecraft.diamond_hoe.adjective": "Trồng trọt",
|
||||
"upgrade.minecraft.diamond_axe.adjective": "Đốn",
|
||||
"upgrade.minecraft.diamond_pickaxe.adjective": "Khai thác",
|
||||
"upgrade.minecraft.diamond_shovel.adjective": "Đào",
|
||||
"item.computercraft.pocket_computer_advanced.upgraded": "Máy tính bỏ túi tiên tiến %s",
|
||||
"item.computercraft.pocket_computer_advanced": "Máy tính bỏ túi tiên tiến",
|
||||
"item.computercraft.pocket_computer_normal.upgraded": "Máy tính bỏ túi %s",
|
||||
"item.computercraft.pocket_computer_normal": "Máy tính bỏ túi",
|
||||
"item.computercraft.printed_book": "Sách in",
|
||||
"item.computercraft.printed_page": "Trang in",
|
||||
"item.computercraft.treasure_disk": "Đĩa mềm",
|
||||
"item.computercraft.disk": "Đĩa mềm",
|
||||
"block.computercraft.turtle_advanced.upgraded_twice": "Rùa tiên tiến %s %s",
|
||||
"block.computercraft.turtle_advanced.upgraded": "Rùa tiên tiến %s",
|
||||
"block.computercraft.turtle_advanced": "Rùa tiên tiến",
|
||||
"block.computercraft.turtle_normal.upgraded_twice": "Rùa %s %s",
|
||||
"block.computercraft.turtle_normal.upgraded": "Rùa %s",
|
||||
"block.computercraft.turtle_normal": "Rùa",
|
||||
"block.computercraft.wired_modem_full": "Modem có dây",
|
||||
"block.computercraft.cable": "Dây cáp mạng",
|
||||
"block.computercraft.wired_modem": "Modem có dây",
|
||||
"block.computercraft.wireless_modem_advanced": "Modem Ender",
|
||||
"block.computercraft.wireless_modem_normal": "Modem không dây",
|
||||
"block.computercraft.monitor_advanced": "Màn hình tiên tiếng",
|
||||
"block.computercraft.monitor_normal": "Màn hình",
|
||||
"block.computercraft.speaker": "Loa",
|
||||
"block.computercraft.printer": "Máy in",
|
||||
"block.computercraft.disk_drive": "Ỗ đĩa",
|
||||
"block.computercraft.computer_command": "Máy tính điều khiển",
|
||||
"block.computercraft.computer_normal": "Máy tính",
|
||||
"itemGroup.computercraft": "ComputerCraft",
|
||||
"block.computercraft.computer_advanced": "Máy tính tiên tiến",
|
||||
"tracking_field.computercraft.websocket_incoming.name": "Websocket đến",
|
||||
"tracking_field.computercraft.websocket_outgoing.name": "Websocket đi",
|
||||
"gui.computercraft.tooltip.computer_id": "ID của máy tính: %s",
|
||||
"tracking_field.computercraft.coroutines_dead.name": "Coroutine bỏ đi",
|
||||
"tracking_field.computercraft.coroutines_created.name": "Coroutine đã tạo",
|
||||
"tracking_field.computercraft.http_download.name": "HTTP tải xuống",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP tải lên",
|
||||
"tracking_field.computercraft.http.name": "Yêu cầu HTTP",
|
||||
"gui.computercraft.tooltip.copy": "Sao chép vào clipboard"
|
||||
}
|
@ -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
|
||||
|
@ -289,7 +289,7 @@ end
|
||||
-- The `mode` string can be any of the following:
|
||||
-- - **"r"**: Read mode
|
||||
-- - **"w"**: Write mode
|
||||
-- - **"w"**: Append mode
|
||||
-- - **"a"**: Append mode
|
||||
--
|
||||
-- The mode may also have a `b` at the end, which opens the file in "binary
|
||||
-- mode". This allows you to read binary files, as well as seek within a file.
|
||||
|
@ -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
|
||||
@ -432,7 +432,7 @@ do
|
||||
|
||||
--- Skip any whitespace
|
||||
local function skip(str, pos)
|
||||
local _, last = find(str, "^[ \n\r\v]+", pos)
|
||||
local _, last = find(str, "^[ \n\r\t]+", pos)
|
||||
if last then return last + 1 else return pos 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
|
||||
@ -472,7 +472,7 @@ do
|
||||
buf[n], n, pos = utf8.char(tonumber(num_str, 16)), n + 1, pos + 6
|
||||
else
|
||||
local unesc = escapes[c]
|
||||
if not unesc then error_at(pos + 1, "Unknown escape character %q.", unesc) end
|
||||
if not unesc then error_at(pos + 1, "Unknown escape character %q.", c) end
|
||||
buf[n], n, pos = unesc, n + 1, pos + 2
|
||||
end
|
||||
elseif c >= '\x20' then
|
||||
@ -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)
|
||||
@ -440,7 +440,7 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible)
|
||||
end
|
||||
|
||||
--- Get the buffered contents of a line in this window.
|
||||
---
|
||||
--
|
||||
-- @tparam number y The y position of the line to get.
|
||||
-- @treturn string The textual content of this line.
|
||||
-- @treturn string The text colours of this line, suitable for use with @{term.blit}.
|
||||
@ -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,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,15 +1,24 @@
|
||||
local tMotd = {}
|
||||
local date = os.date("*t")
|
||||
if date.month == 1 and date.day == 1 then
|
||||
print("Happy new year!")
|
||||
elseif date.month == 12 and date.day == 24 then
|
||||
print("Merry X-mas!")
|
||||
elseif date.month == 10 and date.day == 31 then
|
||||
print("OOoooOOOoooo! Spooky!")
|
||||
else
|
||||
local tMotd = {}
|
||||
|
||||
for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do
|
||||
if fs.exists(sPath) then
|
||||
for sLine in io.lines(sPath) do
|
||||
table.insert(tMotd, sLine)
|
||||
for sPath in string.gmatch(settings.get("motd.path"), "[^:]+") do
|
||||
if fs.exists(sPath) then
|
||||
for sLine in io.lines(sPath) do
|
||||
table.insert(tMotd, sLine)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #tMotd == 0 then
|
||||
print("missingno")
|
||||
else
|
||||
print(tMotd[math.random(1, #tMotd)])
|
||||
if #tMotd == 0 then
|
||||
print("missingno")
|
||||
else
|
||||
print(tMotd[math.random(1, #tMotd)])
|
||||
end
|
||||
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
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.core.apis.http.options;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class AddressRuleTest
|
||||
{
|
||||
@Test
|
||||
public void matchesPort()
|
||||
{
|
||||
Iterable<AddressRule> rules = Collections.singletonList( AddressRule.parse(
|
||||
"127.0.0.1", 8080,
|
||||
new PartialOptions( Action.ALLOW, null, null, null, null )
|
||||
) );
|
||||
|
||||
assertEquals( apply( rules, "localhost", 8080 ).action, Action.ALLOW );
|
||||
assertEquals( apply( rules, "localhost", 8081 ).action, Action.DENY );
|
||||
}
|
||||
|
||||
private Options apply( Iterable<AddressRule> rules, String host, int port )
|
||||
{
|
||||
return AddressRule.apply( rules, host, new InetSocketAddress( host, port ) );
|
||||
}
|
||||
}
|
@ -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)
|
36
src/test/resources/test-rom/spec/programs/motd_spec.lua
Normal file
36
src/test/resources/test-rom/spec/programs/motd_spec.lua
Normal file
@ -0,0 +1,36 @@
|
||||
local capture = require "test_helpers".capture_program
|
||||
|
||||
describe("The motd program", function()
|
||||
local function setup_date(month, day)
|
||||
stub(os, "date", function() return { month = month, day = day } end)
|
||||
end
|
||||
|
||||
it("displays MOTD", function()
|
||||
setup_date(0, 0)
|
||||
local file = fs.open("/motd_check.txt", "w")
|
||||
file.write("Hello World!")
|
||||
file.close()
|
||||
settings.set("motd.path", "/motd_check.txt")
|
||||
|
||||
expect(capture(stub, "motd"))
|
||||
:matches { ok = true, output = "Hello World!\n", error = "" }
|
||||
end)
|
||||
|
||||
it("displays date-specific MOTD (1/1)", function()
|
||||
setup_date(1, 1)
|
||||
expect(capture(stub, "motd"))
|
||||
:matches { ok = true, output = "Happy new year!\n", error = "" }
|
||||
end)
|
||||
|
||||
it("displays date-specific MOTD (10/31)", function()
|
||||
setup_date(10, 31)
|
||||
expect(capture(stub, "motd"))
|
||||
:matches { ok = true, output = "OOoooOOOoooo! Spooky!\n", error = "" }
|
||||
end)
|
||||
|
||||
it("displays date-specific MOTD (12/24)", function()
|
||||
setup_date(12, 24)
|
||||
expect(capture(stub, "motd"))
|
||||
:matches { ok = true, output = "Merry X-mas!\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)
|
Loading…
x
Reference in New Issue
Block a user