mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-15 22:17:39 +00:00
Compare commits
35 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
54eac0a2f8 | ||
![]() |
51ca5e620c | ||
![]() |
076d572831 | ||
![]() |
75f2b91fef | ||
![]() |
79534e5630 | ||
![]() |
d483a91459 | ||
![]() |
71d764f122 | ||
![]() |
2e527eb11e | ||
![]() |
19273b3696 | ||
![]() |
4643641d51 | ||
![]() |
63cd9c5bc7 | ||
![]() |
e9c11ff325 | ||
![]() |
452464aa01 | ||
![]() |
8885462175 | ||
![]() |
b8bd64913b | ||
![]() |
88722d484f | ||
![]() |
6d103e2114 | ||
![]() |
42f23d56ae | ||
![]() |
89d5211bd7 | ||
![]() |
83e70377f7 | ||
![]() |
f6a26f75c3 | ||
![]() |
664df62d5d | ||
![]() |
1348ee0588 | ||
![]() |
145dce7653 | ||
![]() |
7f2651c23e | ||
![]() |
05464107a8 | ||
![]() |
86705787f0 | ||
![]() |
b34d8387d9 | ||
![]() |
4d00969ef0 | ||
![]() |
01d3d12992 | ||
![]() |
5e31dcde83 | ||
![]() |
5184883af1 | ||
![]() |
0c45112262 | ||
![]() |
0bf1672f45 | ||
![]() |
e1b8ac1f84 |
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"
|
||||
}
|
10
README.md
10
README.md
@@ -1,7 +1,9 @@
|
||||
# CC:T for Fabric
|
||||
# CC:Restitched Patchwork
|
||||
# This is a Work In Progress Port
|
||||
*it runs and works-ish*
|
||||
|
||||
* [Download on CurseForge](https://www.curseforge.com/minecraft/mc-mods/cc-tweaked-fabric)
|
||||
## Reached Parity with CC:T 1.93.0
|
||||
|
||||
A fork of [CC: Tweaked](https://github.com/SquidDev-CC/CC-Tweaked) for use with the latest Fabric.
|
||||
THis is just a quick patchwork of my attempts at getting CC:R up to date with CC:T
|
||||
|
||||
NOTE: This project is currently in alpha stage. It may not be well-tested and stable, so use it at your own peril!
|
||||
The changelog is located at [PatchWork.md](patchwork.md)
|
||||
|
@@ -38,6 +38,9 @@ dependencies {
|
||||
implementation "blue.endless:jankson:${jankson_version}"
|
||||
implementation 'com.google.code.findbugs:jsr305:3.0.2'
|
||||
|
||||
compileOnly 'com.google.auto.service:auto-service:1.0-rc7'
|
||||
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'
|
||||
|
||||
include "me.shedaniel.cloth:config-2:${cloth_config_version}"
|
||||
include "blue.endless:jankson:${jankson_version}"
|
||||
include 'javax.vecmath:vecmath:1.5.2'
|
||||
|
@@ -2,7 +2,7 @@
|
||||
org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Mod properties
|
||||
mod_version=1.91.1
|
||||
mod_version=1.93.0
|
||||
|
||||
# Minecraft properties
|
||||
mc_version=1.16.2
|
||||
|
124
patchwork.md
Normal file
124
patchwork.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# 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.
|
||||
|
||||
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.
|
||||
```
|
@@ -10,7 +10,6 @@ import static dan200.computercraft.shared.ComputerCraftRegistry.ModBlocks;
|
||||
import static dan200.computercraft.shared.ComputerCraftRegistry.init;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -19,10 +18,10 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import dan200.computercraft.api.turtle.event.TurtleAction;
|
||||
import dan200.computercraft.core.apis.AddressPredicate;
|
||||
import dan200.computercraft.core.apis.http.options.Action;
|
||||
import dan200.computercraft.core.apis.http.options.AddressRule;
|
||||
import dan200.computercraft.core.apis.http.websocket.Websocket;
|
||||
import dan200.computercraft.core.asm.GenericSource;
|
||||
import dan200.computercraft.shared.common.ColourableRecipe;
|
||||
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputerRegistry;
|
||||
@@ -50,6 +49,7 @@ import dan200.computercraft.shared.turtle.upgrades.TurtleTool;
|
||||
import dan200.computercraft.shared.util.Config;
|
||||
import dan200.computercraft.shared.util.ImpostorRecipe;
|
||||
import dan200.computercraft.shared.util.ImpostorShapelessRecipe;
|
||||
import dan200.computercraft.shared.util.ServiceUtil;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -72,6 +72,7 @@ public final class ComputerCraft implements ModInitializer {
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16",
|
||||
"fd00::/8",
|
||||
"0.0.0.0/8"
|
||||
};
|
||||
public static final int terminalWidth_computer = 51;
|
||||
public static final int terminalHeight_computer = 19;
|
||||
@@ -85,13 +86,6 @@ public final class ComputerCraft implements ModInitializer {
|
||||
// Logging
|
||||
public static final Logger log = LogManager.getLogger(MOD_ID);
|
||||
public static ItemGroup MAIN_GROUP = FabricItemGroupBuilder.build(new Identifier(MOD_ID, "main"), () -> new ItemStack(ModBlocks.COMPUTER_NORMAL));
|
||||
public static List<AddressRule> httpRules = Collections.unmodifiableList(Stream.concat(Stream.of(DEFAULT_HTTP_BLACKLIST)
|
||||
.map(x -> AddressRule.parse(x, Action.DENY.toPartial()))
|
||||
.filter(Objects::nonNull),
|
||||
Stream.of(DEFAULT_HTTP_WHITELIST)
|
||||
.map(x -> AddressRule.parse(x, Action.ALLOW.toPartial()))
|
||||
.filter(Objects::nonNull))
|
||||
.collect(Collectors.toList()));
|
||||
public static boolean commandRequireCreative = false;
|
||||
public static MonitorRenderer monitorRenderer = MonitorRenderer.BEST;
|
||||
public static int computerSpaceLimit = 1000 * 1000;
|
||||
@@ -106,8 +100,6 @@ public final class ComputerCraft implements ModInitializer {
|
||||
public static long maxMainComputerTime = TimeUnit.MILLISECONDS.toNanos(5);
|
||||
public static boolean http_enable = true;
|
||||
public static boolean http_websocket_enable = true;
|
||||
public static AddressPredicate http_whitelist = new AddressPredicate(DEFAULT_HTTP_WHITELIST);
|
||||
public static AddressPredicate http_blacklist = new AddressPredicate(DEFAULT_HTTP_BLACKLIST);
|
||||
public static int httpTimeout = 30000;
|
||||
public static int httpMaxRequests = 16;
|
||||
public static long httpMaxDownload = 16 * 1024 * 1024;
|
||||
@@ -130,6 +122,18 @@ public final class ComputerCraft implements ModInitializer {
|
||||
public static int monitorHeight = 6;
|
||||
public static double monitorDistanceSq = 4096;
|
||||
|
||||
public static List<AddressRule> httpRules = buildHttpRulesFromConfig(DEFAULT_HTTP_BLACKLIST, DEFAULT_HTTP_WHITELIST);
|
||||
|
||||
public static List<AddressRule> buildHttpRulesFromConfig(String[] blacklist, String[] whitelist) {
|
||||
return Stream.concat(Stream.of(blacklist)
|
||||
.map( x -> AddressRule.parse( x, null, Action.DENY.toPartial()))
|
||||
.filter(Objects::nonNull),
|
||||
Stream.of(whitelist)
|
||||
.map( x -> AddressRule.parse( x, null, Action.ALLOW.toPartial()))
|
||||
.filter(Objects::nonNull))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
Config.load(Paths.get(FabricLoader.getInstance()
|
||||
@@ -152,6 +156,7 @@ public final class ComputerCraft implements ModInitializer {
|
||||
Registry.register(Registry.LOOT_CONDITION_TYPE, new Identifier(ComputerCraft.MOD_ID, "player_creative"), PlayerCreativeLootCondition.TYPE);
|
||||
Registry.register(Registry.LOOT_CONDITION_TYPE, new Identifier(ComputerCraft.MOD_ID, "has_id"), HasComputerIdLootCondition.TYPE);
|
||||
init();
|
||||
GenericSource.setup( () -> ServiceUtil.loadServices( GenericSource.class ));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@ public abstract class ItemMapLikeRenderer {
|
||||
float tZ = -0.4f * MathHelper.sin(swingRt * (float) Math.PI);
|
||||
transform.translate(0, -tX / 2, tZ);
|
||||
|
||||
HeldItemRendererAccess access = (HeldItemRendererAccess) render;
|
||||
HeldItemRendererAccess access = (HeldItemRendererAccess) renderer;
|
||||
float pitchAngle = access.callGetMapAngle(pitch);
|
||||
transform.translate(0, 0.04F + equipProgress * -1.2f + pitchAngle * -0.5f, -0.72f);
|
||||
transform.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(pitchAngle * -85.0f));
|
||||
|
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.core.apis;
|
||||
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.net.InetAddresses;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
|
||||
/**
|
||||
* Used to determine whether a domain or IP address matches a series of patterns.
|
||||
*/
|
||||
public class AddressPredicate {
|
||||
private final List<Pattern> wildcards;
|
||||
private final List<HostRange> ranges;
|
||||
|
||||
public AddressPredicate(String... filters) {
|
||||
this(Arrays.asList(filters));
|
||||
}
|
||||
|
||||
public AddressPredicate(Iterable<? extends String> filters) {
|
||||
List<Pattern> wildcards = this.wildcards = new ArrayList<>();
|
||||
List<HostRange> ranges = this.ranges = new ArrayList<>();
|
||||
|
||||
for (String filter : filters) {
|
||||
int cidr = filter.indexOf('/');
|
||||
if (cidr >= 0) {
|
||||
String addressStr = filter.substring(0, cidr);
|
||||
String prefixSizeStr = filter.substring(cidr + 1);
|
||||
|
||||
int prefixSize;
|
||||
try {
|
||||
prefixSize = Integer.parseInt(prefixSizeStr);
|
||||
} catch (NumberFormatException e) {
|
||||
ComputerCraft.log.error("Malformed http whitelist/blacklist entry '{}': Cannot extract size of CIDR mask from '{}'.",
|
||||
filter,
|
||||
prefixSizeStr);
|
||||
continue;
|
||||
}
|
||||
|
||||
InetAddress address;
|
||||
try {
|
||||
address = InetAddresses.forString(addressStr);
|
||||
} catch (IllegalArgumentException e) {
|
||||
ComputerCraft.log.error("Malformed http whitelist/blacklist entry '{}': Cannot extract IP address from '{}'.", filter, prefixSizeStr);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mask the bytes of the IP address.
|
||||
byte[] minBytes = address.getAddress(), maxBytes = address.getAddress();
|
||||
int size = prefixSize;
|
||||
for (int i = 0; i < minBytes.length; i++) {
|
||||
if (size <= 0) {
|
||||
minBytes[i] &= 0;
|
||||
maxBytes[i] |= 0xFF;
|
||||
} else if (size < 8) {
|
||||
minBytes[i] &= 0xFF << (8 - size);
|
||||
maxBytes[i] |= ~(0xFF << (8 - size));
|
||||
}
|
||||
|
||||
size -= 8;
|
||||
}
|
||||
|
||||
ranges.add(new HostRange(minBytes, maxBytes));
|
||||
} else {
|
||||
wildcards.add(Pattern.compile("^\\Q" + filter.replaceAll("\\*", "\\\\E.*\\\\Q") + "\\E$"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given address matches a series of patterns
|
||||
*
|
||||
* @param address The address to check.
|
||||
* @return Whether it matches any of these patterns.
|
||||
*/
|
||||
public boolean matches(InetAddress address) {
|
||||
// Match the host name
|
||||
String host = address.getHostName();
|
||||
if (host != null && this.matches(host)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Match the normal address
|
||||
if (this.matchesAddress(address)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we're an IPv4 address in disguise then let's check that.
|
||||
return address instanceof Inet6Address && InetAddresses.is6to4Address((Inet6Address) address) && this.matchesAddress(InetAddresses.get6to4IPv4Address(
|
||||
(Inet6Address) address));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a host name matches a series of patterns.
|
||||
*
|
||||
* This is intended to allow early exiting, before one has to look up the IP address. You should use {@link #matches(InetAddress)} instead of/in
|
||||
* addition to this one.
|
||||
*
|
||||
* @param domain The domain to match.
|
||||
* @return Whether the patterns were matched.
|
||||
*/
|
||||
public boolean matches(String domain) {
|
||||
for (Pattern domainPattern : this.wildcards) {
|
||||
if (domainPattern.matcher(domain)
|
||||
.matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean matchesAddress(InetAddress address) {
|
||||
String addressString = address.getHostAddress();
|
||||
for (Pattern domainPattern : this.wildcards) {
|
||||
if (domainPattern.matcher(addressString)
|
||||
.matches()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (HostRange range : this.ranges) {
|
||||
if (range.contains(address)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final class HostRange {
|
||||
private final byte[] min;
|
||||
private final byte[] max;
|
||||
|
||||
private HostRange(byte[] min, byte[] max) {
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public boolean contains(InetAddress address) {
|
||||
byte[] entry = address.getAddress();
|
||||
if (entry.length != this.min.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < entry.length; i++) {
|
||||
int value = 0xFF & entry[i];
|
||||
if (value < (0xFF & this.min[i]) || value > (0xFF & this.max[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
||||
|
@@ -106,7 +106,7 @@ public class FileSystemWrapperMount implements IFileSystem {
|
||||
@Override
|
||||
public boolean isDirectory(@Nonnull String path) throws IOException {
|
||||
try {
|
||||
return this.m_filesystem.exists(path);
|
||||
return this.m_filesystem.isDir(path);
|
||||
} catch (FileSystemException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
|
@@ -7,6 +7,6 @@ import net.minecraft.util.WorldSavePath;
|
||||
|
||||
@Mixin (WorldSavePath.class)
|
||||
public interface WorldSavePathAccess {
|
||||
@Invoker
|
||||
@Invoker("<init>")
|
||||
static WorldSavePath createWorldSavePath(String relativePath) { throw new UnsupportedOperationException(); }
|
||||
}
|
||||
|
@@ -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() {
|
||||
|
@@ -17,6 +17,7 @@ import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||
|
||||
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
@@ -53,7 +54,7 @@ public final class Peripherals {
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return GenericPeripheralProvider.getPeripheral(world, pos, side);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic;
|
||||
|
||||
import dan200.computercraft.api.lua.*;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IDynamicPeripheral;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.BlockEntityType;
|
||||
import net.minecraft.block.entity.LockableContainerBlockEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Nameable;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
|
||||
class GenericPeripheral implements IDynamicPeripheral
|
||||
{
|
||||
private final String type;
|
||||
private final BlockEntity tile;
|
||||
private final List<SaturatedMethod> methods;
|
||||
|
||||
GenericPeripheral( BlockEntity tile, List<SaturatedMethod> methods )
|
||||
{
|
||||
Identifier type = BlockEntityType.getId(tile.getType());
|
||||
this.tile = tile;
|
||||
this.type = type == null ? "unknown" : type.toString();
|
||||
this.methods = methods;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String[] getMethodNames()
|
||||
{
|
||||
String[] names = new String[methods.size()];
|
||||
for( int i = 0; i < methods.size(); i++ ) names[i] = methods.get( i ).getName();
|
||||
return names;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public MethodResult callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull IArguments arguments ) throws LuaException
|
||||
{
|
||||
return methods.get( method ).apply( context, computer, arguments );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getTarget()
|
||||
{
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( @Nullable IPeripheral other )
|
||||
{
|
||||
if( other == this ) return true;
|
||||
if( !(other instanceof GenericPeripheral) ) return false;
|
||||
|
||||
GenericPeripheral generic = (GenericPeripheral) other;
|
||||
return tile == generic.tile && methods.equals( generic.methods );
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.asm.NamedMethod;
|
||||
import dan200.computercraft.core.asm.PeripheralMethod;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GenericPeripheralProvider
|
||||
{
|
||||
@Nullable
|
||||
public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
|
||||
{
|
||||
BlockEntity tile = world.getBlockEntity( pos );
|
||||
if( tile == null ) return null;
|
||||
|
||||
ArrayList<SaturatedMethod> saturated = new ArrayList<>( 0 );
|
||||
|
||||
// This seems to add inventory methods, how???
|
||||
List<NamedMethod<PeripheralMethod>> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() );
|
||||
if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods );
|
||||
|
||||
return saturated.isEmpty() ? null : new GenericPeripheral( tile, saturated );
|
||||
}
|
||||
|
||||
private static void addSaturated( ArrayList<SaturatedMethod> saturated, Object target, List<NamedMethod<PeripheralMethod>> methods )
|
||||
{
|
||||
saturated.ensureCapacity( saturated.size() + methods.size() );
|
||||
for( NamedMethod<PeripheralMethod> method : methods )
|
||||
{
|
||||
saturated.add( new SaturatedMethod( target, method ) );
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic;
|
||||
|
||||
import dan200.computercraft.api.lua.IArguments;
|
||||
import dan200.computercraft.api.lua.ILuaContext;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.MethodResult;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.core.asm.NamedMethod;
|
||||
import dan200.computercraft.core.asm.PeripheralMethod;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
final class SaturatedMethod
|
||||
{
|
||||
private final Object target;
|
||||
private final String name;
|
||||
private final PeripheralMethod method;
|
||||
|
||||
SaturatedMethod( Object target, NamedMethod<PeripheralMethod> method )
|
||||
{
|
||||
this.target = target;
|
||||
this.name = method.getName();
|
||||
this.method = method.getMethod();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
MethodResult apply( @Nonnull ILuaContext context, @Nonnull IComputerAccess computer, @Nonnull IArguments args ) throws LuaException
|
||||
{
|
||||
return method.apply( target, context, computer, args );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals( Object obj )
|
||||
{
|
||||
if( obj == this ) return true;
|
||||
if( !(obj instanceof SaturatedMethod) ) return false;
|
||||
|
||||
SaturatedMethod other = (SaturatedMethod) obj;
|
||||
return method == other.method && target.equals( other.target );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return 31 * target.hashCode() + method.hashCode();
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic.data;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.state.property.Property;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class BlockData
|
||||
{
|
||||
@Nonnull
|
||||
public static <T extends Map<? super String, Object>> T fill( @Nonnull T data, @Nonnull BlockState state )
|
||||
{
|
||||
data.put("name", DataHelpers.getId( state.getBlock() ) );
|
||||
|
||||
Map<Object, Object> stateTable = new HashMap<>();
|
||||
for (ImmutableMap.Entry<Property<?>, ? extends Comparable<?>> entry : state.getEntries().entrySet()) {
|
||||
Property<?> property = entry.getKey();
|
||||
stateTable.put(property.getName(), getPropertyValue(property, entry.getValue()));
|
||||
}
|
||||
data.put("state", stateTable);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@SuppressWarnings( { "unchecked", "rawtypes" } )
|
||||
private static Object getPropertyValue( Property property, Comparable value )
|
||||
{
|
||||
if( value instanceof String || value instanceof Number || value instanceof Boolean ) return value;
|
||||
return property.name( value );
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic.data;
|
||||
|
||||
import net.minecraft.block.AbstractBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public final class DataHelpers
|
||||
{
|
||||
private DataHelpers()
|
||||
{ }
|
||||
|
||||
@Nonnull
|
||||
public static Map<String, Boolean> getTags( @Nonnull Collection<Identifier> tags )
|
||||
{
|
||||
Map<String, Boolean> result = new HashMap<>( tags.size() );
|
||||
for( Identifier location : tags ) result.put( location.toString(), true );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getId( @Nonnull Block block )
|
||||
{
|
||||
Identifier id = Registry.BLOCK.getId(block);
|
||||
return id == null ? null : id.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getId( @Nonnull Item item )
|
||||
{
|
||||
Identifier id = Registry.ITEM.getId(item);
|
||||
return id == null ? null : id.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getId( @Nonnull Enchantment enchantment)
|
||||
{
|
||||
Identifier id = Registry.ENCHANTMENT.getId(enchantment);
|
||||
return id == null ? null : id.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic.data;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import dan200.computercraft.shared.util.NBTUtil;
|
||||
import net.minecraft.enchantment.Enchantment;
|
||||
import net.minecraft.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.item.EnchantedBookItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Data providers for items.
|
||||
*/
|
||||
public class ItemData
|
||||
{
|
||||
@Nonnull
|
||||
public static <T extends Map<? super String, Object>> T fillBasicSafe( @Nonnull T data, @Nonnull ItemStack stack )
|
||||
{
|
||||
data.put( "name", DataHelpers.getId( stack.getItem() ) );
|
||||
data.put( "count", stack.getCount() );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static <T extends Map<? super String, Object>> T fillBasic( @Nonnull T data, @Nonnull ItemStack stack )
|
||||
{
|
||||
fillBasicSafe( data, stack );
|
||||
String hash = NBTUtil.getNBTHash( stack.getTag() );
|
||||
if( hash != null ) data.put( "nbt", hash );
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static <T extends Map<? super String, Object>> T fill( @Nonnull T data, @Nonnull ItemStack stack )
|
||||
{
|
||||
if( stack.isEmpty() ) return data;
|
||||
|
||||
fillBasic( data, stack );
|
||||
|
||||
data.put( "displayName", stack.toHoverableText().getString() );
|
||||
data.put( "maxCount", stack.getMaxCount() );
|
||||
|
||||
if( stack.isDamageable() )
|
||||
{
|
||||
data.put( "damage", stack.getDamage() );
|
||||
data.put( "maxDamage", stack.getMaxDamage() );
|
||||
}
|
||||
|
||||
if( stack.isDamaged() )
|
||||
{
|
||||
data.put( "durability", 1.0 - ( stack.getDamage() / stack.getMaxDamage() ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to hide some data from ItemStack tooltip.
|
||||
* @see https://minecraft.gamepedia.com/Tutorials/Command_NBT_tags
|
||||
* @see ItemStack#getTooltip
|
||||
*/
|
||||
CompoundTag tag = stack.getTag();
|
||||
int hideFlags = tag != null ? tag.getInt( "HideFlags" ) : 0;
|
||||
|
||||
List<Map<String, Object>> enchants = getAllEnchants( stack, hideFlags );
|
||||
if( !enchants.isEmpty() ) data.put( "enchantments", enchants );
|
||||
|
||||
if( tag != null && tag.getBoolean( "Unbreakable" ) && (hideFlags & 4) == 0 )
|
||||
{
|
||||
data.put( "unbreakable", true );
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Text parseTextComponent( @Nonnull Tag x )
|
||||
{
|
||||
try
|
||||
{
|
||||
return Text.Serializer.fromJson( x.toString() );
|
||||
}
|
||||
catch( JsonParseException e )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve all visible enchantments from given stack. Try to follow all tooltip rules : order and visibility.
|
||||
*
|
||||
* @param stack Stack to analyse
|
||||
* @param hideFlags An int used as bit field to provide visibility rules.
|
||||
* @return A filled list that contain all visible enchantments.
|
||||
*/
|
||||
@Nonnull
|
||||
private static List<Map<String, Object>> getAllEnchants( @Nonnull ItemStack stack, int hideFlags )
|
||||
{
|
||||
ArrayList<Map<String, Object>> enchants = new ArrayList<>( 0 );
|
||||
|
||||
if( stack.getItem() instanceof EnchantedBookItem && (hideFlags & 32) == 0 )
|
||||
{
|
||||
addEnchantments( EnchantedBookItem.getEnchantmentTag( stack ), enchants );
|
||||
}
|
||||
|
||||
if( stack.hasEnchantments() && (hideFlags & 1) == 0 )
|
||||
{
|
||||
/*
|
||||
* Mimic the EnchantmentHelper.getEnchantments(ItemStack stack) behavior without special case for Enchanted book.
|
||||
* I'll do that to have the same data than ones displayed in tooltip.
|
||||
* @see EnchantmentHelper.getEnchantments(ItemStack stack)
|
||||
*/
|
||||
addEnchantments( stack.getEnchantments(), enchants );
|
||||
}
|
||||
|
||||
return enchants;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Mojang enchant map to a Lua list.
|
||||
*
|
||||
* @param rawEnchants The raw NBT list of enchantments
|
||||
* @param enchants The enchantment map to add it to.
|
||||
* @see EnchantmentHelper
|
||||
*/
|
||||
private static void addEnchantments( @Nonnull ListTag rawEnchants, @Nonnull ArrayList<Map<String, Object>> enchants )
|
||||
{
|
||||
if( rawEnchants.isEmpty() ) return;
|
||||
|
||||
enchants.ensureCapacity( enchants.size() + rawEnchants.size() );
|
||||
|
||||
|
||||
for( Map.Entry<Enchantment, Integer> entry : EnchantmentHelper.fromTag( rawEnchants ).entrySet() )
|
||||
{
|
||||
Enchantment enchantment = entry.getKey();
|
||||
Integer level = entry.getValue();
|
||||
HashMap<String, Object> enchant = new HashMap<>( 3 );
|
||||
enchant.put( "name", DataHelpers.getId( enchantment ) );
|
||||
enchant.put( "level", level );
|
||||
enchant.put( "displayName", enchantment.getName( level ).getString() );
|
||||
enchants.add( enchant );
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
|
||||
/**
|
||||
* A few helpers for working with arguments.
|
||||
*
|
||||
* This should really be moved into the public API. However, until I have settled on a suitable format, we'll keep it
|
||||
* where it is used.
|
||||
*/
|
||||
final class ArgumentHelpers
|
||||
{
|
||||
private ArgumentHelpers()
|
||||
{
|
||||
}
|
||||
|
||||
public static void assertBetween( double value, double min, double max, String message ) throws LuaException
|
||||
{
|
||||
if( value < min || value > max || Double.isNaN( value ) )
|
||||
{
|
||||
throw new LuaException( String.format( message, "between " + min + " and " + max ) );
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertBetween( int value, int min, int max, String message ) throws LuaException
|
||||
{
|
||||
if( value < min || value > max )
|
||||
{
|
||||
throw new LuaException( String.format( message, "between " + min + " and " + max ) );
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.asm.GenericSource;
|
||||
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.ChestBlock;
|
||||
import net.minecraft.block.InventoryProvider;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.block.entity.ChestBlockEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.text.TranslatableText;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Nameable;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHelpers.assertBetween;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Methods for interacting with inventories.
|
||||
*
|
||||
* @cc.module inventory
|
||||
*/
|
||||
@AutoService( GenericSource.class )
|
||||
public class InventoryMethods implements GenericSource
|
||||
{
|
||||
@Nonnull
|
||||
@Override
|
||||
public Identifier id()
|
||||
{
|
||||
return new Identifier(ComputerCraft.MOD_ID, "inventory" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size of this inventory.
|
||||
*
|
||||
* @param inventory The current inventory.
|
||||
* @return The number of slots in this inventory.
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public static int size( Inventory inventory )
|
||||
{
|
||||
// Get appropriate inventory for source peripheral
|
||||
inventory = extractHandler(inventory);
|
||||
|
||||
return inventory.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this inventory.
|
||||
*
|
||||
* @param inventory The current inventory.
|
||||
* @return The name of this inventory, or {@code nil} if not present.
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public static String name( Nameable inventory )
|
||||
{
|
||||
return inventory.hasCustomName() ? inventory.getName().asString() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all items in this inventory. This returns a table, with an entry for each slot.
|
||||
*
|
||||
* Each item in the inventory is represented by a table containing some basic information, much like
|
||||
* @link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail includes. More information can be fetched
|
||||
* with {@link #getItemDetail}.
|
||||
*
|
||||
* The table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs` rather than
|
||||
* `ipairs`.
|
||||
*
|
||||
* @param inventory The current inventory.
|
||||
* @return All items in this inventory.
|
||||
* @cc.treturn { (table|nil)... } All items in this inventory.
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public static Map<Integer, Map<String, ?>> list( Inventory inventory )
|
||||
{
|
||||
// Get appropriate inventory for source peripheral
|
||||
inventory = extractHandler(inventory);
|
||||
|
||||
Map<Integer, Map<String, ?>> result = new HashMap<>();
|
||||
int size = inventory.size();
|
||||
for( int i = 0; i < size; i++ )
|
||||
{
|
||||
ItemStack stack = inventory.getStack( i );
|
||||
if( !stack.isEmpty() ) result.put( i + 1, ItemData.fillBasic( new HashMap<>( 4 ), stack ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get detailed information about an item.
|
||||
*
|
||||
* @param inventory The current inventory.
|
||||
* @param slot The slot to get information about.
|
||||
* @return Information about the item in this slot, or {@code nil} if not present.
|
||||
* @throws LuaException If the slot is out of range.
|
||||
* @cc.treturn table Information about the item in this slot, or {@code nil} if not present.
|
||||
*/
|
||||
@Nullable
|
||||
@LuaFunction( mainThread = true )
|
||||
public static Map<String, ?> getItemDetail( Inventory inventory, int slot ) throws LuaException
|
||||
{
|
||||
// Get appropriate inventory
|
||||
inventory = extractHandler(inventory);
|
||||
|
||||
assertBetween( slot, 1, inventory.size(), "Slot out of range (%s)" );
|
||||
|
||||
ItemStack stack = inventory.getStack( slot - 1 );
|
||||
return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack );
|
||||
}
|
||||
|
||||
/**
|
||||
* Push items from one inventory to another connected one.
|
||||
*
|
||||
* This allows you to push an item in an inventory to another inventory <em>on the same wired network</em>. Both
|
||||
* inventories must attached to wired modems which are connected via a cable.
|
||||
*
|
||||
* @param from Inventory to move items from.
|
||||
* @param computer The current computer.
|
||||
* @param toName The name of the peripheral/inventory to push to. This is the string given to @{peripheral.wrap},
|
||||
* and displayed by the wired modem.
|
||||
* @param fromSlot The slot in the current inventory to move items to.
|
||||
* @param limit The maximum number of items to move. Defaults to the current stack limit.
|
||||
* @param toSlot The slot in the target inventory to move to. If not given, the item will be inserted into any slot.
|
||||
* @return The number of transferred items.
|
||||
* @throws LuaException If the peripheral to transfer to doesn't exist or isn't an inventory.
|
||||
* @throws LuaException If either source or destination slot is out of range.
|
||||
* @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
|
||||
* @cc.usage Wrap two chests, and push an item from one to another.
|
||||
* <pre>{@code
|
||||
* local chest_a = peripheral.wrap("minecraft:chest_0")
|
||||
* local chest_b = peripheral.wrap("minecraft:chest_1")
|
||||
*
|
||||
* chest_a.pushItems(peripheral.getName(chest_b), 1)
|
||||
* }</pre>
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public static int pushItems(
|
||||
Inventory from, IComputerAccess computer,
|
||||
String toName, int fromSlot, Optional<Integer> limit, Optional<Integer> toSlot
|
||||
) throws LuaException
|
||||
{
|
||||
// Get appropriate inventory for source peripheral
|
||||
from = extractHandler(from);
|
||||
|
||||
// Find location to transfer to
|
||||
IPeripheral location = computer.getAvailablePeripheral( toName );
|
||||
if( location == null ) throw new LuaException( "Target '" + toName + "' does not exist" );
|
||||
|
||||
Inventory to = extractHandler( location.getTarget() );
|
||||
if( to == null ) throw new LuaException( "Target '" + toName + "' is not an inventory" );
|
||||
|
||||
// Validate slots
|
||||
int actualLimit = limit.orElse( Integer.MAX_VALUE );
|
||||
assertBetween( fromSlot, 1, from.size(), "From slot out of range (%s)" );
|
||||
if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.size(), "To slot out of range (%s)" );
|
||||
|
||||
if( actualLimit <= 0 ) return 0;
|
||||
return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull items from a connected inventory into this one.
|
||||
*
|
||||
* This allows you to transfer items between inventories <em>on the same wired network</em>. Both this and the source
|
||||
* inventory must attached to wired modems which are connected via a cable.
|
||||
*
|
||||
* @param to Inventory to move items to.
|
||||
* @param computer The current computer.
|
||||
* @param fromName The name of the peripheral/inventory to pull from. This is the string given to @{peripheral.wrap},
|
||||
* and displayed by the wired modem.
|
||||
* @param fromSlot The slot in the source inventory to move items from.
|
||||
* @param limit The maximum number of items to move. Defaults to the current stack limit.
|
||||
* @param toSlot The slot in current inventory to move to. If not given, the item will be inserted into any slot.
|
||||
* @return The number of transferred items.
|
||||
* @throws LuaException If the peripheral to transfer to doesn't exist or isn't an inventory.
|
||||
* @throws LuaException If either source or destination slot is out of range.
|
||||
* @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
|
||||
* @cc.usage Wrap two chests, and push an item from one to another.
|
||||
* <pre>{@code
|
||||
* local chest_a = peripheral.wrap("minecraft:chest_0")
|
||||
* local chest_b = peripheral.wrap("minecraft:chest_1")
|
||||
*
|
||||
* chest_a.pullItems(peripheral.getName(chest_b), 1)
|
||||
* }</pre>
|
||||
*/
|
||||
@LuaFunction( mainThread = true )
|
||||
public static int pullItems(
|
||||
Inventory to, IComputerAccess computer,
|
||||
String fromName, int fromSlot, Optional<Integer> limit, Optional<Integer> toSlot
|
||||
) throws LuaException
|
||||
{
|
||||
// Get appropriate inventory for source peripheral
|
||||
to = extractHandler(to);
|
||||
|
||||
// Find location to transfer to
|
||||
IPeripheral location = computer.getAvailablePeripheral( fromName );
|
||||
if( location == null ) throw new LuaException( "Source '" + fromName + "' does not exist" );
|
||||
|
||||
Inventory from = extractHandler( location.getTarget() );
|
||||
if( from == null ) throw new LuaException( "Source '" + fromName + "' is not an inventory" );
|
||||
|
||||
// Validate slots
|
||||
int actualLimit = limit.orElse( Integer.MAX_VALUE );
|
||||
assertBetween( fromSlot, 1, from.size(), "From slot out of range (%s)" );
|
||||
if( toSlot.isPresent() ) assertBetween( toSlot.get(), 1, to.size(), "To slot out of range (%s)" );
|
||||
|
||||
if( actualLimit <= 0 ) return 0;
|
||||
return moveItem( from, fromSlot - 1, to, toSlot.orElse( 0 ) - 1, actualLimit );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts the most appropriate inventory from the object
|
||||
* e.g., the correct inventory for a double chest or a sided inventory.
|
||||
*
|
||||
* @param object The handler to move from.
|
||||
* @return The appropriate Inventory.
|
||||
*/
|
||||
@Nullable
|
||||
private static Inventory extractHandler( @Nullable Object object )
|
||||
{
|
||||
Inventory inventory = null;
|
||||
|
||||
if (object instanceof BlockEntity ) {
|
||||
BlockEntity blockEntity = (BlockEntity) object;
|
||||
World world = blockEntity.getWorld();
|
||||
BlockPos blockPos = blockEntity.getPos();
|
||||
BlockState blockState = world.getBlockState(blockPos);
|
||||
Block block = blockState.getBlock();
|
||||
|
||||
if (block instanceof InventoryProvider) {
|
||||
inventory = ((InventoryProvider)block).getInventory(blockState, world, blockPos);
|
||||
} else if (blockEntity instanceof Inventory) {
|
||||
inventory = (Inventory)blockEntity;
|
||||
if (inventory instanceof ChestBlockEntity && block instanceof ChestBlock) {
|
||||
inventory = ChestBlock.getInventory((ChestBlock) block, blockState, world, blockPos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return inventory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an item from one handler to another.
|
||||
*
|
||||
* @param from The handler to move from.
|
||||
* @param fromSlot The slot to move from.
|
||||
* @param to The handler to move to.
|
||||
* @param toSlot The slot to move to. Use any number < 0 to represent any slot.
|
||||
* @param limit The max number to move. {@link Integer#MAX_VALUE} for no limit.
|
||||
* @return The number of items moved.
|
||||
*/
|
||||
private static int moveItem( Inventory from, int fromSlot, Inventory to, int toSlot, final int limit )
|
||||
{
|
||||
|
||||
/* ORIGINAL FORGE CODE
|
||||
// See how much we can get out of this slot
|
||||
// ItemStack extracted = from.extractItem( fromSlot, limit, true );
|
||||
if( extracted.isEmpty() ) return 0;
|
||||
|
||||
// Limit the amount to extract
|
||||
int extractCount = Math.min( extracted.getCount(), limit );
|
||||
extracted.setCount( extractCount );
|
||||
|
||||
// ItemStack remainder = toSlot < 0 ? bItemHandlerHelper.insertItem( to, extracted, false ) : to.insertItem( toSlot, extracted, false );
|
||||
int inserted = remainder.isEmpty() ? extractCount : extractCount - remainder.getCount();
|
||||
if( inserted <= 0 ) return 0;
|
||||
|
||||
// Remove the item from the original inventory. Technically this could fail, but there's little we can do
|
||||
// about that.
|
||||
from.extractItem( fromSlot, inserted, false );
|
||||
*/
|
||||
|
||||
// Vanilla minecraft inventory manipulation code
|
||||
Boolean recurse = false;
|
||||
ItemStack source = from.getStack( fromSlot );
|
||||
int count = 0;
|
||||
|
||||
// If target slot was selected, only push items to that slot.
|
||||
if (toSlot >= 0) {
|
||||
int space = amountStackCanAddFrom(to.getStack(toSlot), source, to);
|
||||
if (space == 0) return 0;
|
||||
count = space;
|
||||
}
|
||||
// If target slot not selected, push items where they will fit, possibly
|
||||
// across slots (by recurring on this method).
|
||||
else if (toSlot < 0) {
|
||||
recurse = true;
|
||||
int[] result = getFirstValidSlotAndSpace(source, to);
|
||||
toSlot = result[0];
|
||||
if(toSlot < 0) return 0;
|
||||
count = result[1];
|
||||
}
|
||||
|
||||
// Respect slot restrictions
|
||||
if (!to.isValid(toSlot, source)) { return 0; }
|
||||
|
||||
// Compare count available in target ItemStack to limit specified.
|
||||
count = Math.min(count, limit);
|
||||
if (count == 0) return 0;
|
||||
|
||||
// Mutate destination and source ItemStack
|
||||
ItemStack destination = to.getStack(toSlot);
|
||||
if (destination.isEmpty()) {
|
||||
ItemStack newStack = source.copy();
|
||||
newStack.setCount(count);
|
||||
to.setStack(toSlot, newStack);
|
||||
} else {
|
||||
destination.increment(count);
|
||||
}
|
||||
source.decrement(count);
|
||||
if (source.isEmpty()) from.setStack(fromSlot, ItemStack.EMPTY);
|
||||
|
||||
to.markDirty();
|
||||
from.markDirty();
|
||||
|
||||
// Recurse if no explicit destination slot and more items exist in source slot
|
||||
// and limit hasn't been reached. Else, return items moved.
|
||||
if (recurse && !source.isEmpty()) return count + moveItem(from, fromSlot, to, -1, limit - count);
|
||||
return count;
|
||||
}
|
||||
|
||||
// Maybe there is a nicer existing way to do this in the minecraft codebase. I couldn't find it.
|
||||
private static int[] getFirstValidSlotAndSpace(ItemStack fromStack, Inventory inventory) {
|
||||
for (int i = 0; i < inventory.size(); i++) {
|
||||
ItemStack stack = inventory.getStack(i);
|
||||
int space = amountStackCanAddFrom(stack, fromStack, inventory);
|
||||
if (space > 0) {
|
||||
return new int[]{i, space};
|
||||
}
|
||||
}
|
||||
return new int[]{-1, 0};
|
||||
}
|
||||
|
||||
private static int amountStackCanAddFrom(ItemStack existingStack, ItemStack fromStack, Inventory inventory) {
|
||||
if (fromStack.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
else if (existingStack.isEmpty()) {
|
||||
return Math.min(Math.min(existingStack.getMaxCount(),
|
||||
inventory.getMaxCountPerStack()),
|
||||
fromStack.getCount());
|
||||
}
|
||||
else if (InventoryMethods.areItemsEqual(existingStack, fromStack) &&
|
||||
existingStack.isStackable() &&
|
||||
existingStack.getCount() < existingStack.getMaxCount() &&
|
||||
existingStack.getCount() < inventory.getMaxCountPerStack()) {
|
||||
int stackSpace = existingStack.getMaxCount() - existingStack.getCount();
|
||||
int invSpace = inventory.getMaxCountPerStack() - existingStack.getCount();
|
||||
return Math.min(Math.min(stackSpace, invSpace), fromStack.getCount());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static boolean areItemsEqual(ItemStack stack1, ItemStack stack2) {
|
||||
return stack1.getItem() == stack2.getItem() && ItemStack.areTagsEqual(stack1, stack2);
|
||||
}
|
||||
}
|
@@ -181,17 +181,19 @@ public class BlockCable extends BlockGeneric implements Waterloggable {
|
||||
// : new ItemStack( ComputerCraftRegistry.ModItems.CABLE.get() );
|
||||
// }
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean canPlaceAt(BlockState state, @Nonnull WorldView world, @Nonnull BlockPos pos) {
|
||||
Direction facing = state.get(MODEM)
|
||||
.getFacing();
|
||||
if (facing == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return sideCoversSmallSquare(world, pos.offset(facing), facing.getOpposite());
|
||||
}
|
||||
// Commenting override to allow cable modems to be placed on chests, so that chests can be generic inventory peripherals.
|
||||
// TODO Perhaps there is a more selective way to achieve this?
|
||||
// @Override
|
||||
// @Deprecated
|
||||
// public boolean canPlaceAt(BlockState state, @Nonnull WorldView world, @Nonnull BlockPos pos) {
|
||||
// Direction facing = state.get(MODEM)
|
||||
// .getFacing();
|
||||
// if (facing == null) {
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return sideCoversSmallSquare(world, pos.offset(facing), facing.getOpposite());
|
||||
// }
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
|
@@ -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) {
|
||||
|
@@ -18,6 +18,7 @@ import dan200.computercraft.api.turtle.TurtleCommandResult;
|
||||
import dan200.computercraft.api.turtle.event.TurtleBlockEvent;
|
||||
import dan200.computercraft.api.turtle.event.TurtleEvent;
|
||||
|
||||
import dan200.computercraft.shared.peripheral.generic.data.BlockData;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.state.property.Property;
|
||||
@@ -49,20 +50,7 @@ public class TurtleInspectCommand implements ITurtleCommand {
|
||||
return TurtleCommandResult.failure("No block to inspect");
|
||||
}
|
||||
|
||||
Block block = state.getBlock();
|
||||
String name = Registry.BLOCK.getId(block)
|
||||
.toString();
|
||||
|
||||
Map<String, Object> table = new HashMap<>();
|
||||
table.put("name", name);
|
||||
|
||||
Map<Object, Object> stateTable = new HashMap<>();
|
||||
for (ImmutableMap.Entry<Property<?>, ? extends Comparable<?>> entry : state.getEntries()
|
||||
.entrySet()) {
|
||||
Property<?> property = entry.getKey();
|
||||
stateTable.put(property.getName(), getPropertyValue(property, entry.getValue()));
|
||||
}
|
||||
table.put("state", stateTable);
|
||||
Map<String, Object> table = BlockData.fill( new HashMap<>(), state );
|
||||
|
||||
// Fire the event, exiting if it is cancelled
|
||||
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer(turtle, oldPosition, direction);
|
||||
@@ -72,7 +60,6 @@ public class TurtleInspectCommand implements ITurtleCommand {
|
||||
}
|
||||
|
||||
return TurtleCommandResult.success(new Object[] {table});
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings ({
|
||||
|
@@ -228,9 +228,9 @@ public class TurtlePlaceCommand implements ITurtleCommand {
|
||||
cancelResult = hitEntity.interactAt(turtlePlayer, hitPos, Hand.MAIN_HAND);
|
||||
}
|
||||
|
||||
if (cancelResult.isAccepted()) {
|
||||
if (cancelResult != null && cancelResult.isAccepted()) {
|
||||
placed = true;
|
||||
} else {
|
||||
} else if (hitEntity instanceof LivingEntity) {
|
||||
// See EntityPlayer.interactOn
|
||||
cancelResult = stackCopy.useOnEntity(turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND);
|
||||
if (cancelResult != null && cancelResult.isAccepted()) {
|
||||
@@ -238,7 +238,7 @@ public class TurtlePlaceCommand implements ITurtleCommand {
|
||||
} else if (cancelResult == null) {
|
||||
if (hitEntity.interact(turtlePlayer, Hand.MAIN_HAND) == ActionResult.CONSUME) {
|
||||
placed = true;
|
||||
} else if (hitEntity instanceof LivingEntity) {
|
||||
} else {
|
||||
placed = stackCopy.useOnEntity(turtlePlayer, (LivingEntity) hitEntity, Hand.MAIN_HAND)
|
||||
.isAccepted();
|
||||
if (placed) {
|
||||
@@ -312,17 +312,11 @@ public class TurtlePlaceCommand implements ITurtleCommand {
|
||||
}
|
||||
|
||||
if (!placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof LilyPadItem || item instanceof GlassBottleItem)) {
|
||||
TypedActionResult<ItemStack> actionResult = stackCopy.use(turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND);
|
||||
if (actionResult != null && actionResult.getResult()
|
||||
.isAccepted()) {
|
||||
TypedActionResult<ItemStack> result = stackCopy.use(turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND);
|
||||
if (result.getResult()
|
||||
.isAccepted() && !ItemStack.areEqual(stack, result.getValue())) {
|
||||
placed = true;
|
||||
} else if (actionResult == null) {
|
||||
TypedActionResult<ItemStack> result = stackCopy.use(turtle.getWorld(), turtlePlayer, Hand.MAIN_HAND);
|
||||
if (result.getResult()
|
||||
.isAccepted() && !ItemStack.areEqual(stack, result.getValue())) {
|
||||
placed = true;
|
||||
turtlePlayer.loadInventory(result.getValue());
|
||||
}
|
||||
turtlePlayer.loadInventory(result.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,12 +26,14 @@ import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityDimensions;
|
||||
import net.minecraft.entity.EntityPose;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.entity.passive.HorseBaseEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.NamedScreenHandlerFactory;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
@@ -52,10 +54,9 @@ public final class TurtlePlayer extends FakePlayer {
|
||||
}
|
||||
|
||||
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();
|
||||
|
@@ -210,7 +210,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
||||
|
||||
// Destroy the block
|
||||
state.getBlock()
|
||||
.onBroken(world, blockPosition, state);
|
||||
.onBreak(world, blockPosition, state, turtlePlayer);
|
||||
if (world.removeBlock(blockPosition, false)) {
|
||||
state.getBlock()
|
||||
.onBroken(world, blockPosition, state);
|
||||
|
@@ -13,7 +13,6 @@ import com.google.common.base.CaseFormat;
|
||||
import com.google.common.base.Converter;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.turtle.event.TurtleAction;
|
||||
import dan200.computercraft.core.apis.AddressPredicate;
|
||||
import dan200.computercraft.core.apis.http.websocket.Websocket;
|
||||
|
||||
public class Config {
|
||||
@@ -84,8 +83,7 @@ public class Config {
|
||||
// HTTP
|
||||
ComputerCraft.http_enable = config.http.enabled;
|
||||
ComputerCraft.http_websocket_enable = config.http.websocket_enabled;
|
||||
ComputerCraft.http_whitelist = new AddressPredicate(config.http.whitelist);
|
||||
ComputerCraft.http_blacklist = new AddressPredicate(config.http.blacklist);
|
||||
ComputerCraft.httpRules = ComputerCraft.buildHttpRulesFromConfig(config.http.blacklist, config.http.whitelist);
|
||||
|
||||
ComputerCraft.httpTimeout = Math.max(0, config.http.timeout);
|
||||
ComputerCraft.httpMaxRequests = Math.max(1, config.http.max_requests);
|
||||
|
@@ -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.captureDrops( new ArrayList<>() );
|
||||
}
|
||||
|
||||
public static void set(World world, BlockPos pos, Function<ItemStack, ItemStack> consumer) {
|
||||
|
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
package dan200.computercraft.shared.util;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
public final class ServiceUtil
|
||||
{
|
||||
private static final Type AUTO_SERVICE = Type.getType( "Lcom/google/auto/service/AutoService;" );
|
||||
|
||||
private ServiceUtil()
|
||||
{
|
||||
}
|
||||
|
||||
public static <T> Stream<T> loadServices( Class<T> target )
|
||||
{
|
||||
return StreamSupport.stream( ServiceLoader.load( target, ServiceUtil.class.getClassLoader() ).spliterator(), false );
|
||||
}
|
||||
}
|
@@ -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"
|
||||
}
|
@@ -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
|
||||
|
@@ -3,10 +3,6 @@
|
||||
"package": "dan200.computercraft.mixin",
|
||||
"compatibilityLevel": "JAVA_8",
|
||||
"mixins": [
|
||||
"AffineTransformationAccess",
|
||||
"BakedQuadAccess",
|
||||
"ChatHudAccess",
|
||||
"HeldItemRendererAccess",
|
||||
"MinecraftServerAccess",
|
||||
"MixinBlock",
|
||||
"MixinEntity",
|
||||
@@ -17,6 +13,10 @@
|
||||
"WorldSavePathAccess"
|
||||
],
|
||||
"client": [
|
||||
"AffineTransformationAccess",
|
||||
"BakedQuadAccess",
|
||||
"ChatHudAccess",
|
||||
"HeldItemRendererAccess",
|
||||
"MixinHeldItemRenderer",
|
||||
"MixinItemFrameEntityRenderer",
|
||||
"MixinMinecraftGame",
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
@@ -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}.
|
||||
|
@@ -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,5 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
|
||||
"id": "computercraft",
|
||||
"name": "CC:T for Fabric",
|
||||
"version": "${version}",
|
||||
@@ -26,8 +25,12 @@
|
||||
},
|
||||
"environment": "*",
|
||||
"entrypoints": {
|
||||
"main": [ "dan200.computercraft.ComputerCraft" ],
|
||||
"client": ["dan200.computercraft.client.proxy.ComputerCraftProxyClient"]
|
||||
"main": [
|
||||
"dan200.computercraft.ComputerCraft"
|
||||
],
|
||||
"client": [
|
||||
"dan200.computercraft.client.proxy.ComputerCraftProxyClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"computercraft.mixins.json"
|
||||
|
@@ -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 ) );
|
||||
}
|
||||
}
|
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)
|
Reference in New Issue
Block a user