1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-15 04:30:29 +00:00

Merge branch 'mc-1.16.x' into mc-1.17.x

This commit is contained in:
Jonathan Coates 2021-11-29 19:40:05 +00:00
commit af966179ce
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
44 changed files with 1306 additions and 353 deletions

View File

@ -17,7 +17,7 @@ plugins {
id "com.github.hierynomus.license" version "0.16.1" id "com.github.hierynomus.license" version "0.16.1"
id "com.matthewprenger.cursegradle" version "1.4.0" id "com.matthewprenger.cursegradle" version "1.4.0"
id "com.github.breadmoirai.github-release" version "2.2.12" id "com.github.breadmoirai.github-release" version "2.2.12"
id "org.jetbrains.kotlin.jvm" version "1.5.21" id "org.jetbrains.kotlin.jvm" version "1.6.0"
id "com.modrinth.minotaur" version "1.2.1" id "com.modrinth.minotaur" version "1.2.1"
} }
@ -162,13 +162,13 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
testImplementation 'org.hamcrest:hamcrest:2.2' testImplementation 'org.hamcrest:hamcrest:2.2'
testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21' testImplementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.0'
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'
testModImplementation sourceSets.main.output testModImplementation sourceSets.main.output
testModExtra 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21' testModExtra 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.5.21'
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.1' cctJavadoc 'cc.tweaked:cct-javadoc:1.4.2'
} }
// Compile tasks // Compile tasks

View File

@ -2,7 +2,7 @@
module: [kind=event] redstone module: [kind=event] redstone
--- ---
The @{redstone} event is fired whenever any redstone inputs on the computer change. The @{event!redstone} event is fired whenever any redstone inputs on the computer change.
## Example ## Example
Prints a message when a redstone input changes: Prints a message when a redstone input changes:

View File

@ -1,7 +1,7 @@
org.gradle.jvmargs=-Xmx3G org.gradle.jvmargs=-Xmx3G
# Mod properties # Mod properties
mod_version=1.98.2 mod_version=1.99.0
# Minecraft properties (update mods.toml when changing) # Minecraft properties (update mods.toml when changing)
mc_version=1.17.1 mc_version=1.17.1

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

269
gradlew vendored
View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,67 +17,101 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MSYS* | MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the Please set the JAVA_HOME variable in your environment to match the
@ -106,80 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

402
package-lock.json generated
View File

@ -16,10 +16,45 @@
"@rollup/plugin-typescript": "^8.2.5", "@rollup/plugin-typescript": "^8.2.5",
"requirejs": "^2.3.6", "requirejs": "^2.3.6",
"rollup": "^2.33.1", "rollup": "^2.33.1",
"terser": "^5.3.8", "rollup-plugin-terser": "^7.0.2",
"typescript": "^4.0.5" "typescript": "^4.0.5"
} }
}, },
"node_modules/@babel/code-frame": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz",
"integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.16.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz",
"integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.15.7",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@rollup/plugin-typescript": { "node_modules/@rollup/plugin-typescript": {
"version": "8.3.0", "version": "8.3.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz",
@ -61,18 +96,74 @@
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
"dev": true "dev": true
}, },
"node_modules/@types/node": {
"version": "16.11.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz",
"integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==",
"dev": true
},
"node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/buffer-from": { "node_modules/buffer-from": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true "dev": true
}, },
"node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"node_modules/commander": { "node_modules/commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true "dev": true
}, },
"node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/estree-walker": { "node_modules/estree-walker": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
@ -111,6 +202,15 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.8.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
@ -123,6 +223,53 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/jest-worker": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
"integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
"dev": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^7.0.0"
},
"engines": {
"node": ">= 10.13.0"
}
},
"node_modules/jest-worker/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
"engines": {
"node": ">=8"
}
},
"node_modules/jest-worker/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"node_modules/path-parse": { "node_modules/path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
@ -142,14 +289,23 @@
} }
}, },
"node_modules/preact": { "node_modules/preact": {
"version": "10.5.15", "version": "10.6.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.5.15.tgz", "resolved": "https://registry.npmjs.org/preact/-/preact-10.6.1.tgz",
"integrity": "sha512-5chK29n6QcJc3m1lVrKQSQ+V7K1Gb8HeQY6FViQ5AxCAEGu3DaHffWNDkC9+miZgsLvbvU9rxbV1qinGHMHzqA==", "integrity": "sha512-ydCg+ISIq70vqiThvNWStZWLRjR9U2awP/JAmGdWUKm9+Tyuy+MqVdAIyEByeIspAVtD4GWC/SJtxO8XD4knVA==",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/preact" "url": "https://opencollective.com/preact"
} }
}, },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/requirejs": { "node_modules/requirejs": {
"version": "2.3.6", "version": "2.3.6",
"resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz", "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.3.6.tgz",
@ -177,9 +333,9 @@
} }
}, },
"node_modules/rollup": { "node_modules/rollup": {
"version": "2.60.0", "version": "2.60.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.1.tgz",
"integrity": "sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==", "integrity": "sha512-akwfnpjY0rXEDSn1UTVfKXJhPsEBu+imi1gqBA1ZkHGydUnkV/fWCC90P7rDaLEW8KTwBcS1G3N4893Ndz+jwg==",
"dev": true, "dev": true,
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
@ -191,6 +347,50 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/rollup-plugin-terser": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
"integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
"jest-worker": "^26.2.1",
"serialize-javascript": "^4.0.0",
"terser": "^5.0.0"
},
"peerDependencies": {
"rollup": "^2.0.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"dev": true,
"dependencies": {
"randombytes": "^2.1.0"
}
},
"node_modules/source-map": { "node_modules/source-map": {
"version": "0.7.3", "version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
@ -219,6 +419,18 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/terser": { "node_modules/terser": {
"version": "5.10.0", "version": "5.10.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",
@ -264,6 +476,32 @@
} }
}, },
"dependencies": { "dependencies": {
"@babel/code-frame": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz",
"integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==",
"dev": true,
"requires": {
"@babel/highlight": "^7.16.0"
}
},
"@babel/helper-validator-identifier": {
"version": "7.15.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
"integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
"dev": true
},
"@babel/highlight": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz",
"integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.15.7",
"chalk": "^2.0.0",
"js-tokens": "^4.0.0"
}
},
"@rollup/plugin-typescript": { "@rollup/plugin-typescript": {
"version": "8.3.0", "version": "8.3.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-8.3.0.tgz",
@ -291,18 +529,65 @@
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
"dev": true "dev": true
}, },
"@types/node": {
"version": "16.11.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.10.tgz",
"integrity": "sha512-3aRnHa1KlOEEhJ6+CvyHKK5vE9BcLGjtUpwvqYLRvYNQKMfabu3BwfJaA/SLW8dxe28LsNDjtHwePTuzn3gmOA==",
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"buffer-from": { "buffer-from": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true "dev": true
}, },
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
},
"commander": { "commander": {
"version": "2.20.3", "version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true "dev": true
}, },
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
"dev": true
},
"estree-walker": { "estree-walker": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
@ -331,6 +616,12 @@
"function-bind": "^1.1.1" "function-bind": "^1.1.1"
} }
}, },
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
"dev": true
},
"is-core-module": { "is-core-module": {
"version": "2.8.0", "version": "2.8.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz",
@ -340,6 +631,46 @@
"has": "^1.0.3" "has": "^1.0.3"
} }
}, },
"jest-worker": {
"version": "26.6.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
"integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
"dev": true,
"requires": {
"@types/node": "*",
"merge-stream": "^2.0.0",
"supports-color": "^7.0.0"
},
"dependencies": {
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true
},
"merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"path-parse": { "path-parse": {
"version": "1.0.7", "version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
@ -353,9 +684,18 @@
"dev": true "dev": true
}, },
"preact": { "preact": {
"version": "10.5.15", "version": "10.6.1",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.5.15.tgz", "resolved": "https://registry.npmjs.org/preact/-/preact-10.6.1.tgz",
"integrity": "sha512-5chK29n6QcJc3m1lVrKQSQ+V7K1Gb8HeQY6FViQ5AxCAEGu3DaHffWNDkC9+miZgsLvbvU9rxbV1qinGHMHzqA==" "integrity": "sha512-ydCg+ISIq70vqiThvNWStZWLRjR9U2awP/JAmGdWUKm9+Tyuy+MqVdAIyEByeIspAVtD4GWC/SJtxO8XD4knVA=="
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.0"
}
}, },
"requirejs": { "requirejs": {
"version": "2.3.6", "version": "2.3.6",
@ -374,14 +714,41 @@
} }
}, },
"rollup": { "rollup": {
"version": "2.60.0", "version": "2.60.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.0.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.60.1.tgz",
"integrity": "sha512-cHdv9GWd58v58rdseC8e8XIaPUo8a9cgZpnCMMDGZFDZKEODOiPPEQFXLriWr/TjXzhPPmG5bkAztPsOARIcGQ==", "integrity": "sha512-akwfnpjY0rXEDSn1UTVfKXJhPsEBu+imi1gqBA1ZkHGydUnkV/fWCC90P7rDaLEW8KTwBcS1G3N4893Ndz+jwg==",
"dev": true, "dev": true,
"requires": { "requires": {
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"rollup-plugin-terser": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
"integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"jest-worker": "^26.2.1",
"serialize-javascript": "^4.0.0",
"terser": "^5.0.0"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"dev": true
},
"serialize-javascript": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
"integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
}
},
"source-map": { "source-map": {
"version": "0.7.3", "version": "0.7.3",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
@ -406,6 +773,15 @@
} }
} }
}, },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
},
"terser": { "terser": {
"version": "5.10.0", "version": "5.10.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz",

View File

@ -12,7 +12,7 @@
"@rollup/plugin-typescript": "^8.2.5", "@rollup/plugin-typescript": "^8.2.5",
"requirejs": "^2.3.6", "requirejs": "^2.3.6",
"rollup": "^2.33.1", "rollup": "^2.33.1",
"terser": "^5.3.8", "rollup-plugin-terser": "^7.0.2",
"typescript": "^4.0.5" "typescript": "^4.0.5"
} }
} }

View File

@ -1,7 +1,8 @@
import { readFileSync, promises as fs } from "fs"; import { readFileSync } from "fs";
import path from "path"; import path from "path";
import typescript from "@rollup/plugin-typescript"; import typescript from "@rollup/plugin-typescript";
import { terser } from "rollup-plugin-terser";
const input = "src/web"; const input = "src/web";
const requirejs = readFileSync("node_modules/requirejs/require.js"); const requirejs = readFileSync("node_modules/requirejs/require.js");
@ -12,7 +13,14 @@ export default {
file: "build/rollup/index.js", file: "build/rollup/index.js",
// We bundle requirejs (and config) into the header. It's rather gross // We bundle requirejs (and config) into the header. It's rather gross
// but also works reasonably well. // but also works reasonably well.
banner: `${requirejs}\nrequire.config({ paths: { copycat: "https://copy-cat.squiddev.cc" } });`, // Also suffix a ?v=${date} onto the end in the event we need to require a specific copy-cat version.
banner: `
${requirejs}
require.config({
paths: { copycat: "https://copy-cat.squiddev.cc" },
urlArgs: function(id) { return id == "copycat/embed" ? "?v=20211127" : ""; }
});
`,
format: "amd", format: "amd",
preferConst: true, preferConst: true,
amd: { amd: {
@ -27,22 +35,6 @@ export default {
{ {
name: "cc-tweaked", name: "cc-tweaked",
async options(options) {
// Generate .d.ts files for all /mount files. This is the worst way to do it,
// but we need to run before the TS pass.
const template = "declare const contents : string;\nexport default contents;\n";
const files = await fs.readdir(`${input}/mount`);
await Promise.all(files
.filter(x => path.extname(x) !== ".ts")
.map(async file => {
const path = `${input}/mount/${file}.d.ts`;
const contents = await fs.readFile(path, { encoding: "utf-8" }).catch(() => "");
if (contents !== template) await fs.writeFile(path, template);
})
);
return options;
},
async transform(code, file) { async transform(code, file) {
// Allow loading files in /mount. // Allow loading files in /mount.
const ext = path.extname(file); const ext = path.extname(file);
@ -50,6 +42,8 @@ export default {
? `export default ${JSON.stringify(code)};\n` ? `export default ${JSON.stringify(code)};\n`
: null; : null;
}, },
} },
terser(),
], ],
}; };

View File

@ -10,6 +10,8 @@ import net.minecraftforge.common.capabilities.Capability;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Set;
/** /**
* The interface that defines a peripheral. * The interface that defines a peripheral.
@ -31,6 +33,18 @@ public interface IPeripheral
@Nonnull @Nonnull
String getType(); String getType();
/**
* Return additional types/traits associated with this object.
*
* @return A collection of additional object traits.
* @see PeripheralType#getAdditionalTypes()
*/
@Nonnull
default Set<String> getAdditionalTypes()
{
return Collections.emptySet();
}
/** /**
* Is called when when a computer is attaching to the peripheral. * Is called when when a computer is attaching to the peripheral.
* *

View File

@ -6,9 +6,13 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
/** /**
* The type of a {@link GenericPeripheral}. * The type of a {@link GenericPeripheral}.
@ -18,13 +22,19 @@ import javax.annotation.Nullable;
*/ */
public final class PeripheralType public final class PeripheralType
{ {
private static final PeripheralType UNTYPED = new PeripheralType( null ); private static final PeripheralType UNTYPED = new PeripheralType( null, Collections.emptySet() );
private final String type; private final String type;
private final Set<String> additionalTypes;
public PeripheralType( String type ) public PeripheralType( String type, Set<String> additionalTypes )
{ {
this.type = type; this.type = type;
this.additionalTypes = additionalTypes;
if( additionalTypes.contains( null ) )
{
throw new IllegalArgumentException( "All additional types must be non-null" );
}
} }
/** /**
@ -46,7 +56,55 @@ public final class PeripheralType
public static PeripheralType ofType( @Nonnull String type ) public static PeripheralType ofType( @Nonnull String type )
{ {
if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" );
return new PeripheralType( type ); return new PeripheralType( type, Collections.emptySet() );
}
/**
* Create a new non-empty peripheral type with additional traits.
*
* @param type The name of the type.
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofType( @Nonnull String type, Collection<String> additionalTypes )
{
if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" );
return new PeripheralType( type, ImmutableSet.copyOf( additionalTypes ) );
}
/**
* Create a new non-empty peripheral type with additional traits.
*
* @param type The name of the type.
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofType( @Nonnull String type, @Nonnull String... additionalTypes )
{
if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" );
return new PeripheralType( type, ImmutableSet.copyOf( additionalTypes ) );
}
/**
* Create a new peripheral type with no primary type but additional traits.
*
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofAdditional( Collection<String> additionalTypes )
{
return new PeripheralType( null, ImmutableSet.copyOf( additionalTypes ) );
}
/**
* Create a new peripheral type with no primary type but additional traits.
*
* @param additionalTypes Additional types, or "traits" of this peripheral. For instance, {@literal "inventory"}.
* @return The constructed peripheral type.
*/
public static PeripheralType ofAdditional( @Nonnull String... additionalTypes )
{
return new PeripheralType( null, ImmutableSet.copyOf( additionalTypes ) );
} }
/** /**
@ -59,4 +117,15 @@ public final class PeripheralType
{ {
return type; return type;
} }
/**
* Get any additional types or "traits" of this peripheral. These effectively act as a standard set of interfaces
* a peripheral might have.
*
* @return All additional types.
*/
public Set<String> getAdditionalTypes()
{
return additionalTypes;
}
} }

View File

@ -484,7 +484,7 @@ public class FSAPI implements ILuaAPI
* *
* This string is formatted like a normal path string, but can include any * This string is formatted like a normal path string, but can include any
* number of wildcards ({@code *}) to look for files matching anything. * number of wildcards ({@code *}) to look for files matching anything.
* For example, {@code rom/* /command*} will look for any path starting with * For example, <code>rom/&#42;/command*</code> will look for any path starting with
* {@code command} inside any subdirectory of {@code /rom}. * {@code command} inside any subdirectory of {@code /rom}.
* *
* @param path The wildcard-qualified path to search for. * @param path The wildcard-qualified path to search for.

View File

@ -17,6 +17,7 @@ import dan200.computercraft.core.asm.NamedMethod;
import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.tracking.TrackingField; import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.shared.util.LuaUtil;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -36,6 +37,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
private final IPeripheral peripheral; private final IPeripheral peripheral;
private final String type; private final String type;
private final Set<String> additionalTypes;
private final Map<String, PeripheralMethod> methodMap; private final Map<String, PeripheralMethod> methodMap;
private boolean attached; private boolean attached;
@ -47,6 +49,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
attached = false; attached = false;
type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" );
additionalTypes = peripheral.getAdditionalTypes();
methodMap = PeripheralAPI.getMethods( peripheral ); methodMap = PeripheralAPI.getMethods( peripheral );
} }
@ -61,6 +64,11 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
return type; return type;
} }
public Set<String> getAdditionalTypes()
{
return additionalTypes;
}
public Collection<String> getMethods() public Collection<String> getMethods()
{ {
return methodMap.keySet(); return methodMap.keySet();
@ -298,7 +306,23 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
synchronized( peripherals ) synchronized( peripherals )
{ {
PeripheralWrapper p = peripherals[side.ordinal()]; PeripheralWrapper p = peripherals[side.ordinal()];
if( p != null ) return new Object[] { p.getType() }; return p == null ? null : LuaUtil.consArray( p.getType(), p.getAdditionalTypes() );
}
}
@LuaFunction
public final Object[] hasType( String sideName, String type )
{
ComputerSide side = ComputerSide.valueOfInsensitive( sideName );
if( side == null ) return null;
synchronized( peripherals )
{
PeripheralWrapper p = peripherals[side.ordinal()];
if( p != null )
{
return new Object[] { p.getType().equals( type ) || p.getAdditionalTypes().contains( type ) };
}
} }
return null; return null;
} }

View File

@ -38,13 +38,13 @@ public final class Peripherals
} }
@Nullable @Nullable
public static IPeripheral getPeripheral( Level world, BlockPos pos, Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate ) public static IPeripheral getPeripheral( Level world, BlockPos pos, Direction side, NonNullConsumer<Object> invalidate )
{ {
return world.isInWorldBounds( pos ) && !world.isClientSide ? getPeripheralAt( world, pos, side, invalidate ) : null; return world.isInWorldBounds( pos ) && !world.isClientSide ? getPeripheralAt( world, pos, side, invalidate ) : null;
} }
@Nullable @Nullable
private static IPeripheral getPeripheralAt( Level world, BlockPos pos, Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate ) private static IPeripheral getPeripheralAt( Level world, BlockPos pos, Direction side, NonNullConsumer<? super Object> invalidate )
{ {
BlockEntity block = world.getBlockEntity( pos ); BlockEntity block = world.getBlockEntity( pos );
if( block != null ) if( block != null )

View File

@ -59,7 +59,7 @@ public abstract class BlockComputerBase<T extends TileComputerBase> extends Bloc
super.onPlace( state, world, pos, oldState, isMoving ); super.onPlace( state, world, pos, oldState, isMoving );
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if( tile instanceof TileComputerBase computer ) computer.updateInput(); if( tile instanceof TileComputerBase computer ) computer.updateInputsImmediately( );
} }
@Override @Override

View File

@ -31,14 +31,9 @@ import net.minecraft.world.Nameable;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items; import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.DiodeBlock;
import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.BlockHitResult;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.util.NonNullConsumer; import net.minecraftforge.common.util.NonNullConsumer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -57,7 +52,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
private boolean on = false; private boolean on = false;
boolean startOn = false; boolean startOn = false;
private boolean fresh = false; private boolean fresh = false;
private final NonNullConsumer<LazyOptional<IPeripheral>>[] invalidate;
private int invalidSides = 0;
private final NonNullConsumer<Object>[] invalidate;
private final ComputerFamily family; private final ComputerFamily family;
@ -68,10 +65,11 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
// We cache these so we can guarantee we only ever register one listener for adjacent capabilities. // We cache these so we can guarantee we only ever register one listener for adjacent capabilities.
@SuppressWarnings( { "unchecked", "rawtypes" } ) @SuppressWarnings( { "unchecked", "rawtypes" } )
NonNullConsumer<LazyOptional<IPeripheral>>[] invalidate = this.invalidate = new NonNullConsumer[6]; NonNullConsumer<Object>[] invalidate = this.invalidate = new NonNullConsumer[6];
for( Direction direction : Direction.values() ) for( Direction direction : Direction.values() )
{ {
invalidate[direction.ordinal()] = o -> updateInput( direction ); int mask = 1 << direction.ordinal();
invalidate[direction.ordinal()] = o -> invalidSides |= mask;
} }
} }
@ -143,19 +141,26 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
@Override @Override
public void onNeighbourChange( @Nonnull BlockPos neighbour ) public void onNeighbourChange( @Nonnull BlockPos neighbour )
{ {
updateInput( neighbour ); updateInputAt( neighbour );
} }
@Override @Override
public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour ) public void onNeighbourTileEntityChange( @Nonnull BlockPos neighbour )
{ {
updateInput( neighbour ); updateInputAt( neighbour );
} }
protected void serverTick() protected void serverTick()
{ {
ServerComputer computer = createServerComputer(); ServerComputer computer = createServerComputer();
if( computer == null ) return;
if( invalidSides != 0 )
{
for( Direction direction : DirectionUtil.FACINGS )
{
if( (invalidSides & (1 << direction.ordinal())) != 0 ) refreshPeripheral( computer, direction );
}
}
// If the computer isn't on and should be, then turn it on // If the computer isn't on and should be, then turn it on
if( startOn || (fresh && on) ) if( startOn || (fresh && on) )
@ -222,89 +227,80 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
return localSide; return localSide;
} }
private void updateSideInput( ServerComputer computer, Direction dir, BlockPos offset ) private void updateRedstoneInput( @Nonnull ServerComputer computer, Direction dir, BlockPos targetPos )
{ {
Direction offsetSide = dir.getOpposite(); Direction offsetSide = dir.getOpposite();
ComputerSide localDir = remapToLocalSide( dir ); ComputerSide localDir = remapToLocalSide( dir );
computer.setRedstoneInput( localDir, getRedstoneInput( level, offset, dir ) ); computer.setRedstoneInput( localDir, RedstoneUtil.getRedstoneInput( level, targetPos, dir ) );
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), offset, offsetSide ) ); computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getLevel(), targetPos, offsetSide ) );
if( !isPeripheralBlockedOnSide( localDir ) ) }
{
IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), offset, offsetSide, invalidate[dir.ordinal()] ); private void refreshPeripheral( @Nonnull ServerComputer computer, Direction dir )
computer.setPeripheral( localDir, peripheral ); {
} invalidSides &= ~(1 << dir.ordinal());
ComputerSide localDir = remapToLocalSide( dir );
if( isPeripheralBlockedOnSide( localDir ) ) return;
Direction offsetSide = dir.getOpposite();
IPeripheral peripheral = Peripherals.getPeripheral( getLevel(), getBlockPos().relative( dir ), offsetSide, invalidate[dir.ordinal()] );
computer.setPeripheral( localDir, peripheral );
}
public void updateInputsImmediately()
{
ServerComputer computer = getServerComputer();
if( computer != null ) updateInputsImmediately( computer );
} }
/** /**
* Gets the redstone input for an adjacent block. * Update all redstone and peripherals.
* *
* @param world The world we exist in * This should only be really be called when the computer is being ticked (though there are some cases where it
* @param pos The position of the neighbour * won't be), as peripheral scanning requires adjacent tiles to be in a "correct" state - which may not be the case
* @param side The side we are reading from * if they're still updating!
* @return The effective redstone power *
* @see DiodeBlock#getInputSignal(Level, BlockPos, BlockState) * @param computer The current computer instance.
*/ */
protected static int getRedstoneInput( Level world, BlockPos pos, Direction side ) private void updateInputsImmediately( @Nonnull ServerComputer computer )
{ {
int power = world.getSignal( pos, side ); BlockPos pos = getBlockPos();
if( power >= 15 ) return power;
BlockState neighbour = world.getBlockState( pos );
return neighbour.getBlock() == Blocks.REDSTONE_WIRE
? Math.max( power, neighbour.getValue( RedStoneWireBlock.POWER ) )
: power;
}
public void updateInput()
{
if( getLevel() == null || getLevel().isClientSide ) return;
// Update all sides
ServerComputer computer = getServerComputer();
if( computer == null ) return;
BlockPos pos = computer.getPosition();
for( Direction dir : DirectionUtil.FACINGS ) for( Direction dir : DirectionUtil.FACINGS )
{ {
updateSideInput( computer, dir, pos.relative( dir ) ); updateRedstoneInput( computer, dir, pos.relative( dir ) );
refreshPeripheral( computer, dir );
} }
} }
private void updateInput( BlockPos neighbour ) private void updateInputAt( @Nonnull BlockPos neighbour )
{ {
if( getLevel() == null || getLevel().isClientSide ) return;
ServerComputer computer = getServerComputer(); ServerComputer computer = getServerComputer();
if( computer == null ) return; if( computer == null ) return;
for( Direction dir : DirectionUtil.FACINGS ) for( Direction dir : DirectionUtil.FACINGS )
{ {
BlockPos offset = worldPosition.relative( dir ); BlockPos offset = getBlockPos().relative( dir );
if( offset.equals( neighbour ) ) if( offset.equals( neighbour ) )
{ {
updateSideInput( computer, dir, offset ); updateRedstoneInput( computer, dir, offset );
invalidSides |= 1 << dir.ordinal();
return; return;
} }
} }
// If the position is not any adjacent one, update all inputs. // If the position is not any adjacent one, update all inputs. This is pretty terrible, but some redstone mods
updateInput(); // handle this incorrectly.
} BlockPos pos = getBlockPos();
for( Direction dir : DirectionUtil.FACINGS ) updateRedstoneInput( computer, dir, pos.relative( dir ) );
private void updateInput( Direction dir ) invalidSides = (1 << 6) - 1; // Mark all peripherals as dirty.
{
if( getLevel() == null || getLevel().isClientSide ) return;
ServerComputer computer = getServerComputer();
if( computer == null ) return;
updateSideInput( computer, dir, worldPosition.relative( dir ) );
} }
/**
* Update the block's state and propagate redstone output.
*/
public void updateOutput() public void updateOutput()
{ {
// Update redstone
updateBlock(); updateBlock();
for( Direction dir : DirectionUtil.FACINGS ) for( Direction dir : DirectionUtil.FACINGS )
{ {
@ -354,9 +350,10 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
return family; return family;
} }
@Nonnull
public ServerComputer createServerComputer() public ServerComputer createServerComputer()
{ {
if( getLevel().isClientSide ) return null; if( getLevel().isClientSide ) throw new IllegalStateException( "Cannot access server computer on the client." );
boolean changed = false; boolean changed = false;
if( instanceID < 0 ) if( instanceID < 0 )
@ -364,18 +361,21 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID(); instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID();
changed = true; changed = true;
} }
if( !ComputerCraft.serverComputerRegistry.contains( instanceID ) )
ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instanceID );
if( computer == null )
{ {
ServerComputer computer = createComputer( instanceID, computerID ); computer = createComputer( instanceID, computerID );
ComputerCraft.serverComputerRegistry.add( instanceID, computer ); ComputerCraft.serverComputerRegistry.add( instanceID, computer );
fresh = true; fresh = true;
changed = true; changed = true;
} }
if( changed ) updateInput(); if( changed ) updateInputsImmediately( computer );
return ComputerCraft.serverComputerRegistry.get( instanceID ); return computer;
} }
@Nullable
public ServerComputer getServerComputer() public ServerComputer getServerComputer()
{ {
return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID ); return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID );

View File

@ -128,7 +128,7 @@ public class CommandBlockPeripheral implements IPeripheral, ICapabilityProvider
public static void onCapability( AttachCapabilitiesEvent<BlockEntity> event ) public static void onCapability( AttachCapabilitiesEvent<BlockEntity> event )
{ {
BlockEntity tile = event.getObject(); BlockEntity tile = event.getObject();
if( tile instanceof CommandBlockEntity ) if( ComputerCraft.enableCommandBlock && tile instanceof CommandBlockEntity )
{ {
CommandBlockPeripheral peripheral = new CommandBlockPeripheral( (CommandBlockEntity) tile ); CommandBlockPeripheral peripheral = new CommandBlockPeripheral( (CommandBlockEntity) tile );
event.addCapability( CAP_ID, peripheral ); event.addCapability( CAP_ID, peripheral );

View File

@ -18,18 +18,21 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.List; import java.util.List;
import java.util.Set;
class GenericPeripheral implements IDynamicPeripheral class GenericPeripheral implements IDynamicPeripheral
{ {
private final String type; private final String type;
private final Set<String> additionalTypes;
private final BlockEntity tile; private final BlockEntity tile;
private final List<SaturatedMethod> methods; private final List<SaturatedMethod> methods;
GenericPeripheral( BlockEntity tile, String name, List<SaturatedMethod> methods ) GenericPeripheral( BlockEntity tile, String name, Set<String> additionalTypes, List<SaturatedMethod> methods )
{ {
ResourceLocation type = tile.getType().getRegistryName(); ResourceLocation type = tile.getType().getRegistryName();
this.tile = tile; this.tile = tile;
this.type = name != null ? name : (type != null ? type.toString() : "unknown"); this.type = name != null ? name : (type != null ? type.toString() : "unknown");
this.additionalTypes = additionalTypes;
this.methods = methods; this.methods = methods;
} }
@ -56,6 +59,13 @@ class GenericPeripheral implements IDynamicPeripheral
return type; return type;
} }
@Nonnull
@Override
public Set<String> getAdditionalTypes()
{
return additionalTypes;
}
@Nullable @Nullable
@Override @Override
public Object getTarget() public Object getTarget()

View File

@ -9,6 +9,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.PeripheralType; import dan200.computercraft.api.peripheral.PeripheralType;
import dan200.computercraft.core.asm.NamedMethod; import dan200.computercraft.core.asm.NamedMethod;
import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.shared.util.CapabilityUtil;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
@ -19,9 +20,7 @@ import net.minecraftforge.common.util.NonNullConsumer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Objects;
public class GenericPeripheralProvider public class GenericPeripheralProvider
{ {
@ -34,7 +33,7 @@ public class GenericPeripheralProvider
} }
@Nullable @Nullable
public static IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate ) public static IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer<Object> invalidate )
{ {
BlockEntity tile = world.getBlockEntity( pos ); BlockEntity tile = world.getBlockEntity( pos );
if( tile == null ) return null; if( tile == null ) return null;
@ -52,7 +51,7 @@ public class GenericPeripheralProvider
if( capabilityMethods.isEmpty() ) return; if( capabilityMethods.isEmpty() ) return;
saturated.addMethods( contents, capabilityMethods ); saturated.addMethods( contents, capabilityMethods );
wrapper.addListener( cast( invalidate ) ); CapabilityUtil.addListener( wrapper, invalidate );
} ); } );
} }
@ -61,15 +60,16 @@ public class GenericPeripheralProvider
private static class GenericPeripheralBuilder private static class GenericPeripheralBuilder
{ {
String name; private String name;
final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 ); private final Set<String> additionalTypes = new HashSet<>( 0 );
private final ArrayList<SaturatedMethod> methods = new ArrayList<>( 0 );
IPeripheral toPeripheral( BlockEntity tile ) IPeripheral toPeripheral( BlockEntity tile )
{ {
if( methods.isEmpty() ) return null; if( methods.isEmpty() ) return null;
methods.trimToSize(); methods.trimToSize();
return new GenericPeripheral( tile, name, methods ); return new GenericPeripheral( tile, name, additionalTypes, methods );
} }
void addMethods( Object target, List<NamedMethod<PeripheralMethod>> methods ) void addMethods( Object target, List<NamedMethod<PeripheralMethod>> methods )
@ -88,13 +88,8 @@ public class GenericPeripheralProvider
String name = type.getPrimaryType(); String name = type.getPrimaryType();
if( this.name == null || this.name.compareTo( name ) > 0 ) this.name = name; if( this.name == null || this.name.compareTo( name ) > 0 ) this.name = name;
} }
if( type != null ) additionalTypes.addAll( type.getAdditionalTypes() );
} }
} }
} }
@SuppressWarnings( { "unchecked", "rawtypes" } )
private static <T> NonNullConsumer<T> cast( NonNullConsumer<?> consumer )
{
return (NonNullConsumer) consumer;
}
} }

View File

@ -6,8 +6,9 @@
package dan200.computercraft.shared.peripheral.generic.methods; package dan200.computercraft.shared.peripheral.generic.methods;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.peripheral.GenericPeripheral;
import dan200.computercraft.api.peripheral.PeripheralType;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.energy.IEnergyStorage; import net.minecraftforge.energy.IEnergyStorage;
@ -25,8 +26,15 @@ import javax.annotation.Nonnull;
* *
* @cc.module energy_storage * @cc.module energy_storage
*/ */
public class EnergyMethods implements GenericSource public class EnergyMethods implements GenericPeripheral
{ {
@Nonnull
@Override
public PeripheralType getType()
{
return PeripheralType.ofAdditional( "energy_storage" );
}
@Nonnull @Nonnull
@Override @Override
public ResourceLocation id() public ResourceLocation id()

View File

@ -6,13 +6,15 @@
package dan200.computercraft.shared.peripheral.generic.methods; package dan200.computercraft.shared.peripheral.generic.methods;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.peripheral.GenericPeripheral;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.generic.data.FluidData; import dan200.computercraft.shared.peripheral.generic.data.FluidData;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluid;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
@ -34,8 +36,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
* *
* @cc.module fluid_storage * @cc.module fluid_storage
*/ */
public class FluidMethods implements GenericSource public class FluidMethods implements GenericPeripheral
{ {
@Nonnull
@Override
public PeripheralType getType()
{
return PeripheralType.ofAdditional( "fluid_storage" );
}
@Nonnull @Nonnull
@Override @Override
public ResourceLocation id() public ResourceLocation id()
@ -155,13 +164,15 @@ public class FluidMethods implements GenericSource
@Nullable @Nullable
private static IFluidHandler extractHandler( @Nullable Object object ) private static IFluidHandler extractHandler( @Nullable Object object )
{ {
if( object instanceof ICapabilityProvider ) if( object instanceof BlockEntity blockEntity && blockEntity.isRemoved() ) return null;
if( object instanceof ICapabilityProvider provider )
{ {
LazyOptional<IFluidHandler> cap = ((ICapabilityProvider) object).getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY ); LazyOptional<IFluidHandler> cap = provider.getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY );
if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new ); if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new );
} }
if( object instanceof IFluidHandler ) return (IFluidHandler) object; if( object instanceof IFluidHandler handler ) return handler;
return null; return null;
} }

View File

@ -6,16 +6,18 @@
package dan200.computercraft.shared.peripheral.generic.methods; package dan200.computercraft.shared.peripheral.generic.methods;
import dan200.computercraft.ComputerCraft; import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.api.peripheral.GenericPeripheral;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.PeripheralType;
import dan200.computercraft.shared.peripheral.generic.data.ItemData; import dan200.computercraft.shared.peripheral.generic.data.ItemData;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.Container; import net.minecraft.world.Container;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
@ -36,8 +38,15 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
* *
* @cc.module inventory * @cc.module inventory
*/ */
public class InventoryMethods implements GenericSource public class InventoryMethods implements GenericPeripheral
{ {
@Nonnull
@Override
public PeripheralType getType()
{
return PeripheralType.ofAdditional( "inventory" );
}
@Nonnull @Nonnull
@Override @Override
public ResourceLocation id() public ResourceLocation id()
@ -259,14 +268,16 @@ public class InventoryMethods implements GenericSource
@Nullable @Nullable
private static IItemHandler extractHandler( @Nullable Object object ) private static IItemHandler extractHandler( @Nullable Object object )
{ {
if( object instanceof ICapabilityProvider ) if( object instanceof BlockEntity blockEntity && blockEntity.isRemoved() ) return null;
if( object instanceof ICapabilityProvider provider )
{ {
LazyOptional<IItemHandler> cap = ((ICapabilityProvider) object).getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY ); LazyOptional<IItemHandler> cap = provider.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY );
if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new ); if( cap.isPresent() ) return cap.orElseThrow( NullPointerException::new );
} }
if( object instanceof IItemHandler ) return (IItemHandler) object; if( object instanceof IItemHandler handler ) return handler;
if( object instanceof Container ) return new InvWrapper( (Container) object ); if( object instanceof Container container ) return new InvWrapper( container );
return null; return null;
} }

View File

@ -77,8 +77,9 @@ public class TileCable extends TileGeneric
} }
} }
private boolean invalidPeripheral;
private boolean peripheralAccessAllowed; private boolean peripheralAccessAllowed;
private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral( this::refreshPeripheral ); private final WiredModemLocalPeripheral peripheral = new WiredModemLocalPeripheral( this::queueRefreshPeripheral );
private boolean destroyed = false; private boolean destroyed = false;
@ -234,12 +235,20 @@ public class TileCable extends TileGeneric
if( !level.isClientSide && peripheralAccessAllowed ) if( !level.isClientSide && peripheralAccessAllowed )
{ {
Direction facing = getDirection(); Direction facing = getDirection();
if( getBlockPos().relative( facing ).equals( neighbour ) ) refreshPeripheral(); if( getBlockPos().relative( facing ).equals( neighbour ) ) queueRefreshPeripheral();
} }
} }
private void queueRefreshPeripheral()
{
if( invalidPeripheral ) return;
invalidPeripheral = true;
TickScheduler.schedule( this );
}
private void refreshPeripheral() private void refreshPeripheral()
{ {
invalidPeripheral = false;
if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), getDirection() ) ) if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), getDirection() ) )
{ {
updateConnectedPeripherals(); updateConnectedPeripherals();
@ -310,6 +319,8 @@ public class TileCable extends TileGeneric
{ {
if( getLevel().isClientSide ) return; if( getLevel().isClientSide ) return;
if( invalidPeripheral ) refreshPeripheral();
if( modem.getModemState().pollChanged() ) updateBlockState(); if( modem.getModemState().pollChanged() ) updateBlockState();
if( !connectionsFormed ) if( !connectionsFormed )

View File

@ -108,13 +108,15 @@ public class TileWiredModemFull extends TileGeneric
private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged(); private final NonNullConsumer<LazyOptional<IWiredElement>> connectedNodeChanged = x -> connectionsChanged();
private int invalidSides = 0;
public TileWiredModemFull( BlockEntityType<TileWiredModemFull> type, BlockPos pos, BlockState state ) public TileWiredModemFull( BlockEntityType<TileWiredModemFull> type, BlockPos pos, BlockState state )
{ {
super( type, pos, state ); super( type, pos, state );
for( int i = 0; i < peripherals.length; i++ ) for( int i = 0; i < peripherals.length; i++ )
{ {
Direction facing = Direction.from3DDataValue( i ); Direction facing = Direction.from3DDataValue( i );
peripherals[i] = new WiredModemLocalPeripheral( () -> refreshPeripheral( facing ) ); peripherals[i] = new WiredModemLocalPeripheral( () -> queueRefreshPeripheral( facing ) );
} }
} }
@ -173,13 +175,20 @@ public class TileWiredModemFull extends TileGeneric
{ {
for( Direction facing : DirectionUtil.FACINGS ) for( Direction facing : DirectionUtil.FACINGS )
{ {
if( getBlockPos().relative( facing ).equals( neighbour ) ) refreshPeripheral( facing ); if( getBlockPos().relative( facing ).equals( neighbour ) ) queueRefreshPeripheral( facing );
} }
} }
} }
private void queueRefreshPeripheral( @Nonnull Direction facing )
{
if( invalidSides == 0 ) TickScheduler.schedule( this );
invalidSides |= 1 << facing.ordinal();
}
private void refreshPeripheral( @Nonnull Direction facing ) private void refreshPeripheral( @Nonnull Direction facing )
{ {
invalidSides &= ~(1 << facing.ordinal());
WiredModemLocalPeripheral peripheral = peripherals[facing.ordinal()]; WiredModemLocalPeripheral peripheral = peripherals[facing.ordinal()];
if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), facing ) ) if( level != null && !isRemoved() && peripheral.attach( level, getBlockPos(), facing ) )
{ {
@ -262,6 +271,14 @@ public class TileWiredModemFull extends TileGeneric
{ {
if( getLevel().isClientSide ) return; if( getLevel().isClientSide ) return;
if( invalidSides != 0 )
{
for( Direction direction : DirectionUtil.FACINGS )
{
if( (invalidSides & (1 << direction.ordinal())) != 0 ) refreshPeripheral( direction );
}
}
if( modemState.pollChanged() ) updateBlockState(); if( modemState.pollChanged() ) updateBlockState();
if( !connectionsFormed ) if( !connectionsFormed )

View File

@ -15,7 +15,6 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.common.util.NonNullConsumer; import net.minecraftforge.common.util.NonNullConsumer;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -38,7 +37,7 @@ public final class WiredModemLocalPeripheral
private String type; private String type;
private IPeripheral peripheral; private IPeripheral peripheral;
private final NonNullConsumer<LazyOptional<IPeripheral>> invalidate; private final NonNullConsumer<Object> invalidate;
public WiredModemLocalPeripheral( @Nonnull Runnable invalidate ) public WiredModemLocalPeripheral( @Nonnull Runnable invalidate )
{ {

View File

@ -21,6 +21,7 @@ import dan200.computercraft.core.apis.PeripheralAPI;
import dan200.computercraft.core.asm.PeripheralMethod; import dan200.computercraft.core.asm.PeripheralMethod;
import dan200.computercraft.shared.peripheral.modem.ModemPeripheral; import dan200.computercraft.shared.peripheral.modem.ModemPeripheral;
import dan200.computercraft.shared.peripheral.modem.ModemState; import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.LuaUtil;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -118,13 +119,35 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
* @param name The peripheral's name. * @param name The peripheral's name.
* @return The peripheral's name. * @return The peripheral's name.
* @cc.treturn string|nil The peripheral's type, or {@code nil} if it is not present. * @cc.treturn string|nil The peripheral's type, or {@code nil} if it is not present.
* @cc.changed 1.99 Peripherals can have multiple types - this function returns multiple values.
* @see PeripheralAPI#getType * @see PeripheralAPI#getType
*/ */
@LuaFunction @LuaFunction
public final Object[] getTypeRemote( IComputerAccess computer, String name ) public final Object[] getTypeRemote( IComputerAccess computer, String name )
{ {
RemotePeripheralWrapper wrapper = getWrapper( computer, name ); RemotePeripheralWrapper wrapper = getWrapper( computer, name );
return wrapper != null ? new Object[] { wrapper.getType() } : null; return wrapper == null ? null : LuaUtil.consArray( wrapper.getType(), wrapper.getAdditionalTypes() );
}
/**
* Check a peripheral is of a particular type.
*
* <blockquote><strong>Important:</strong> This function only appears on wired modems. Check {@link #isWireless}
* returns false before calling it.</blockquote>
*
* @param computer The calling computer.
* @param name The peripheral's name.
* @param type The type to check.
* @return The peripheral's name.
* @cc.treturn boolean|nil If a peripheral has a particular type, or {@literal nil} if it is not present.
* @cc.since 1.99
* @see PeripheralAPI#getType
*/
@LuaFunction
public final Object[] hasTypeRemote( IComputerAccess computer, String name, String type )
{
RemotePeripheralWrapper wrapper = getWrapper( computer, name );
return wrapper == null ? null : new Object[] { wrapper.getType().equals( type ) || wrapper.getAdditionalTypes().contains( getType() ) };
} }
/** /**
@ -307,6 +330,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
private final String name; private final String name;
private final String type; private final String type;
private final Set<String> additionalTypes;
private final Map<String, PeripheralMethod> methodMap; private final Map<String, PeripheralMethod> methodMap;
private volatile boolean attached; private volatile boolean attached;
@ -320,6 +344,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
this.name = name; this.name = name;
type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" ); type = Objects.requireNonNull( peripheral.getType(), "Peripheral type cannot be null" );
additionalTypes = peripheral.getAdditionalTypes();
methodMap = PeripheralAPI.getMethods( peripheral ); methodMap = PeripheralAPI.getMethods( peripheral );
} }
@ -353,6 +378,11 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
return type; return type;
} }
public Set<String> getAdditionalTypes()
{
return additionalTypes;
}
public Collection<String> getMethodNames() public Collection<String> getMethodNames()
{ {
return methodMap.keySet(); return methodMap.keySet();

View File

@ -331,8 +331,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
{ {
if( dir.getAxis() == Direction.Axis.Y ) dir = Direction.NORTH; if( dir.getAxis() == Direction.Axis.Y ) dir = Direction.NORTH;
level.setBlockAndUpdate( worldPosition, getBlockState().setValue( BlockTurtle.FACING, dir ) ); level.setBlockAndUpdate( worldPosition, getBlockState().setValue( BlockTurtle.FACING, dir ) );
updateOutput(); updateOutput();
updateInput(); updateInputsImmediately();
onTileEntityChange(); onTileEntityChange();
} }

View File

@ -332,16 +332,17 @@ public class TurtleBrain implements ITurtleAccess
// Copy the old turtle state into the new turtle // Copy the old turtle state into the new turtle
newTurtle.setLevel( world ); newTurtle.setLevel( world );
newTurtle.transferStateFrom( oldOwner ); newTurtle.transferStateFrom( oldOwner );
newTurtle.createServerComputer().setLevel( world );
newTurtle.createServerComputer().setPosition( pos ); ServerComputer computer = newTurtle.createServerComputer();
computer.setLevel( world );
computer.setPosition( pos );
// Remove the old turtle // Remove the old turtle
oldWorld.removeBlock( oldPos, false ); oldWorld.removeBlock( oldPos, false );
// Make sure everybody knows about it // Make sure everybody knows about it
newTurtle.updateBlock();
newTurtle.updateInput();
newTurtle.updateOutput(); newTurtle.updateOutput();
newTurtle.updateInputsImmediately();
return true; return true;
} }
} }
@ -613,16 +614,16 @@ public class TurtleBrain implements ITurtleAccess
@Override @Override
public void setUpgrade( @Nonnull TurtleSide side, ITurtleUpgrade upgrade ) public void setUpgrade( @Nonnull TurtleSide side, ITurtleUpgrade upgrade )
{ {
if( !setUpgradeDirect( side, upgrade ) ) return; if( !setUpgradeDirect( side, upgrade ) || owner.getLevel() == null ) return;
// This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as // This is a separate function to avoid updating the block when reading the NBT. We don't need to do this as
// either the block is newly placed (and so won't have changed) or is being updated with /data, which calls // either the block is newly placed (and so won't have changed) or is being updated with /data, which calls
// updateBlock for us. // updateBlock for us.
if( owner.getLevel() != null ) owner.updateBlock();
{
owner.updateBlock(); // Recompute peripherals in case an upgrade being removed has exposed a new peripheral.
owner.updateInput(); // TODO: Only update peripherals, or even only two sides?
} owner.updateInputsImmediately();
} }
private boolean setUpgradeDirect( @Nonnull TurtleSide side, ITurtleUpgrade upgrade ) private boolean setUpgradeDirect( @Nonnull TurtleSide side, ITurtleUpgrade upgrade )
@ -644,7 +645,7 @@ public class TurtleBrain implements ITurtleAccess
if( upgrade != null ) upgrades.put( side, upgrade ); if( upgrade != null ) upgrades.put( side, upgrade );
// Notify clients and create peripherals // Notify clients and create peripherals
if( owner.getLevel() != null ) if( owner.getLevel() != null && !owner.getLevel().isClientSide )
{ {
updatePeripherals( owner.createServerComputer() ); updatePeripherals( owner.createServerComputer() );
} }

View File

@ -35,12 +35,20 @@ public final class CapabilityUtil
} }
} }
public static <T> void addListener( LazyOptional<T> p, NonNullConsumer<? super LazyOptional<T>> invalidate )
{
// We can make this safe with invalidate::accept, but then we're allocating it's just kind of absurd.
@SuppressWarnings( "unchecked" )
NonNullConsumer<LazyOptional<T>> safeInvalidate = (NonNullConsumer<LazyOptional<T>>) invalidate;
p.addListener( safeInvalidate );
}
@Nullable @Nullable
public static <T> T unwrap( LazyOptional<T> p, NonNullConsumer<LazyOptional<T>> invalidate ) public static <T> T unwrap( LazyOptional<T> p, NonNullConsumer<? super LazyOptional<T>> invalidate )
{ {
if( !p.isPresent() ) return null; if( !p.isPresent() ) return null;
p.addListener( invalidate ); addListener( p, invalidate );
return p.orElseThrow( NullPointerException::new ); return p.orElseThrow( NullPointerException::new );
} }

View File

@ -0,0 +1,23 @@
/*
* 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 java.util.Collection;
public class LuaUtil
{
public static Object[] consArray( Object value, Collection<?> rest )
{
if( rest.isEmpty() ) return new Object[] { value };
// I'm not proud of this code.
Object[] out = new Object[rest.size() + 1];
out[0] = value;
int i = 1;
for( Object additionalType : rest ) out[i++] = additionalType;
return out;
}
}

View File

@ -8,6 +8,9 @@ package dan200.computercraft.shared.util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.DiodeBlock;
import net.minecraft.world.level.block.RedStoneWireBlock;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.event.ForgeEventFactory;
@ -15,6 +18,30 @@ import java.util.EnumSet;
public final class RedstoneUtil public final class RedstoneUtil
{ {
private RedstoneUtil()
{
}
/**
* Gets the redstone input for an adjacent block.
*
* @param world The world we exist in
* @param pos The position of the neighbour
* @param side The side we are reading from
* @return The effective redstone power
* @see DiodeBlock#getInputSignal(Level, BlockPos, BlockState)
*/
public static int getRedstoneInput( Level world, BlockPos pos, Direction side )
{
int power = world.getSignal( pos, side );
if( power >= 15 ) return power;
BlockState neighbour = world.getBlockState( pos );
return neighbour.getBlock() == Blocks.REDSTONE_WIRE
? Math.max( power, neighbour.getValue( RedStoneWireBlock.POWER ) )
: power;
}
public static void propagateRedstoneOutput( Level world, BlockPos pos, Direction side ) public static void propagateRedstoneOutput( Level world, BlockPos pos, Direction side )
{ {
// Propagate ordinary output. See BlockRedstoneDiode.notifyNeighbors // Propagate ordinary output. See BlockRedstoneDiode.notifyNeighbors

View File

@ -68,7 +68,7 @@ end
-- @{paintutils.drawImage}, or `nil` if the file does not exist. -- @{paintutils.drawImage}, or `nil` if the file does not exist.
-- @usage Load an image and draw it. -- @usage Load an image and draw it.
-- --
-- local image = paintutils.loadImage("test-image.nfp") -- local image = paintutils.loadImage("data/example.nfp")
-- paintutils.drawImage(image, term.getCursorPos()) -- paintutils.drawImage(image, term.getCursorPos())
function loadImage(path) function loadImage(path)
expect(1, path, "string") expect(1, path, "string")

View File

@ -1,18 +1,90 @@
--- The Peripheral API is for interacting with peripherals connected to the --[[- Peripherals are blocks (or turtle and pocket computer upgrades) which can
-- computer, such as the Disk Drive, the Advanced Monitor and Monitor. be controlled by a computer. For instance, the @{speaker} peripheral allows a
-- computer to play music and the @{monitor} peripheral allows you to display text
-- Each peripheral block has a name, either referring to the side the peripheral in the world.
-- can be found on, or a name on an adjacent wired network.
-- ## Referencing peripherals
-- If the peripheral is next to the computer, its side is either `front`,
-- `back`, `left`, `right`, `top` or `bottom`. If the peripheral is attached by Computers can interact with adjacent peripherals. Each peripheral is given a
-- a cable, its side will follow the format `type_id`, for example `printer_0`. name based on which direction it is in. For instance, a disk drive below your
-- computer will be called `"bottom"` in your Lua code, one to the left called
-- Peripheral functions are called *methods*, a term borrowed from Java. `"left"` , and so on for all 6 directions (`"bottom"`, `"top"`, `"left"`,
-- `"right"`, `"front"`, `"back"`).
-- @module peripheral
-- @since 1.3 You can list the names of all peripherals with the `peripherals` program, or the
-- @changed 1.51 Add support for wired modems. @{peripheral.getNames} function.
It's also possible to use peripherals which are further away from your computer
through the use of @{modem|Wired Modems}. Place one modem against your computer,
run Networking Cable to your peripheral, and then place another modem against
that block. You can then right click the modem to use (or *attach*) the
peripheral. This will print a peripheral name to chat, which can then be used
just like a direction name to access the peripheral. You can click on the message
to copy the name to your clipboard.
## Using peripherals
Once you have the name of a peripheral, you can call functions on it using the
@{peripheral.call} function. This takes the name of our peripheral, the name of
the function we want to call, and then its arguments.
> Some bits of the peripheral API call peripheral functions *methods* instead
> (for example, the @{peripheral.getMethods} function). Don't worry, they're the
> same thing!
Let's say we have a monitor above our computer (and so "top") and want to
@{monitor.write|write some text to it}. We'd write the following:
```lua
peripheral.call("top", "write", "This is displayed on a monitor!")
```
Once you start calling making a couple of peripheral calls this can get very
repetitive, and so we can @{peripheral.wrap|wrap} a peripheral. This builds a
table of all the peripheral's functions so you can use it like an API or module.
For instance, we could have written the above example as follows:
```lua
local my_monitor = peripheral.wrap("top")
my_monitor.write("This is displayed on a monitor!")
```
## Finding peripherals
Sometimes when you're writing a program you don't care what a peripheral is
called, you just need to know it's there. For instance, if you're writing a
music player, you just need a speaker - it doesn't matter if it's above or below
the computer.
Thankfully there's a quick way to do this: @{peripheral.find}. This takes a
*peripheral type* and returns all the attached peripherals which are of this
type.
What is a peripheral type though? This is a string which describes what a
peripheral is, and so what functions are available on it. For instance, speakers
are just called `"speaker"`, and monitors `"monitor"`. Some peripherals might
have more than one type; a Minecraft chest is both a `"minecraft:chest"` and
`"inventory"`.
You can get all the types a peripheral has with @{peripheral.getType}, and check
a peripheral is a specific type with @{peripheral.hasType}.
To return to our original example, let's use @{peripheral.find} to find an
attached speaker:
```lua
local speaker = peripheral.find("speaker")
speaker.playNote("harp")
```
@module peripheral
@see event!peripheral This event is fired whenever a new peripheral is attached.
@see event!peripheral_detach This event is fired whenever a peripheral is detached.
@since 1.3
@changed 1.51 Add support for wired modems.
@changed 1.99 Peripherals can have multiple types.
]]
local expect = dofile("rom/modules/main/cc/expect.lua").expect local expect = dofile("rom/modules/main/cc/expect.lua").expect
@ -33,7 +105,7 @@ function getNames()
local side = sides[n] local side = sides[n]
if native.isPresent(side) then if native.isPresent(side) then
table.insert(results, side) table.insert(results, side)
if native.getType(side) == "modem" and not native.call(side, "isWireless") then if native.hasType(side, "modem") and not native.call(side, "isWireless") then
local remote = native.call(side, "getNamesRemote") local remote = native.call(side, "getNamesRemote")
for _, name in ipairs(remote) do for _, name in ipairs(remote) do
table.insert(results, name) table.insert(results, name)
@ -58,7 +130,7 @@ function isPresent(name)
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and if native.hasType(side, "modem") and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", name) native.call(side, "isPresentRemote", name)
then then
return true return true
@ -67,12 +139,17 @@ function isPresent(name)
return false return false
end end
--- Get the type of a wrapped peripheral, or a peripheral with the given name. --[[- Get the types of a named or wrapped peripheral.
--
-- @tparam string|table peripheral The name of the peripheral to find, or a @tparam string|table peripheral The name of the peripheral to find, or a
-- wrapped peripheral instance. wrapped peripheral instance.
-- @treturn string|nil The peripheral's type, or `nil` if it is not present. @treturn string... The peripheral's types, or `nil` if it is not present.
-- @changed 1.88.0 Accepts a wrapped peripheral as an argument. @changed 1.88.0 Accepts a wrapped peripheral as an argument.
@changed 1.99 Now returns multiple types.
@usage Get the type of a peripheral above this computer.
peripheral.getType("top")
]]
function getType(peripheral) function getType(peripheral)
expect(1, peripheral, "string", "table") expect(1, peripheral, "string", "table")
if type(peripheral) == "string" then -- Peripheral name passed if type(peripheral) == "string" then -- Peripheral name passed
@ -81,7 +158,7 @@ function getType(peripheral)
end end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and if native.hasType(side, "modem") and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", peripheral) native.call(side, "isPresentRemote", peripheral)
then then
return native.call(side, "getTypeRemote", peripheral) return native.call(side, "getTypeRemote", peripheral)
@ -90,10 +167,43 @@ function getType(peripheral)
return nil return nil
else else
local mt = getmetatable(peripheral) local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.type) ~= "string" then if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2) error("bad argument #1 (table is not a peripheral)", 2)
end end
return mt.type return table.unpack(mt.types)
end
end
--[[- Check if a peripheral is of a particular type.
@tparam string|table peripheral The name of the peripheral or a wrapped peripheral instance.
@tparam string peripheral_type The type to check.
@treturn boolean|nil If a peripheral has a particular type, or `nil` if it is not present.
@since 1.99
]]
function hasType(peripheral, peripheral_type)
expect(1, peripheral, "string", "table")
expect(2, peripheral_type, "string")
if type(peripheral) == "string" then -- Peripheral name passed
if native.isPresent(peripheral) then
return native.hasType(peripheral, peripheral_type)
end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "modem") and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", peripheral)
then
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
end
end
return nil
else
local mt = getmetatable(peripheral)
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
error("bad argument #1 (table is not a peripheral)", 2)
end
return mt.types[peripheral_type] ~= nil
end end
end end
@ -109,7 +219,7 @@ function getMethods(name)
end end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and if native.hasType(side, "modem") and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", name) native.call(side, "isPresentRemote", name)
then then
return native.call(side, "getMethodsRemote", name) return native.call(side, "getMethodsRemote", name)
@ -151,7 +261,7 @@ function call(name, method, ...)
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.getType(side) == "modem" and not native.call(side, "isWireless") and if native.hasType(side, "modem") and not native.call(side, "isWireless") and
native.call(side, "isPresentRemote", name) native.call(side, "isPresentRemote", name)
then then
return native.call(side, "callRemote", name, method, ...) return native.call(side, "callRemote", name, method, ...)
@ -160,15 +270,16 @@ function call(name, method, ...)
return nil return nil
end end
--- Get a table containing functions pointing to the peripheral's methods, which --- Get a table containing all functions available on a peripheral. These can
-- can then be called as if using @{peripheral.call}. -- then be called instead of using @{peripheral.call} every time.
-- --
-- @tparam string name The name of the peripheral to wrap. -- @tparam string name The name of the peripheral to wrap.
-- @treturn table|nil The table containing the peripheral's methods, or `nil` if -- @treturn table|nil The table containing the peripheral's methods, or `nil` if
-- there is no peripheral present with the given name. -- there is no peripheral present with the given name.
-- @usage Open the modem on the top of this computer. -- @usage Open the modem on the top of this computer.
-- --
-- peripheral.wrap("top").open(1) -- local modem = peripheral.wrap("top")
-- modem.open(1)
function wrap(name) function wrap(name)
expect(1, name, "string") expect(1, name, "string")
@ -177,10 +288,14 @@ function wrap(name)
return nil return nil
end end
-- We store our types array as a list (for getType) and a lookup table (for hasType).
local types = { peripheral.getType(name) }
for i = 1, #types do types[types[i]] = true end
local result = setmetatable({}, { local result = setmetatable({}, {
__name = "peripheral", __name = "peripheral",
name = name, name = name,
type = peripheral.getType(name), type = types[1],
types = types,
}) })
for _, method in ipairs(methods) do for _, method in ipairs(methods) do
result[method] = function(...) result[method] = function(...)
@ -222,7 +337,7 @@ function find(ty, filter)
local results = {} local results = {}
for _, name in ipairs(peripheral.getNames()) do for _, name in ipairs(peripheral.getNames()) do
if peripheral.getType(name) == ty then if peripheral.hasType(name, ty) then
local wrapped = peripheral.wrap(name) local wrapped = peripheral.wrap(name)
if filter == nil or filter(name, wrapped) then if filter == nil or filter(name, wrapped) then
table.insert(results, wrapped) table.insert(results, wrapped)

View File

@ -1,3 +1,34 @@
# New features in CC: Tweaked 1.99.0
* Pocket computers in their offhand will open without showing a terminal. You can look around and interact with the world, but your keyboard will be forwarded to the computer. (Wojbie, MagGen-hub).
* Peripherals can now have multiple types. `peripheral.getType` now returns multiple values, and `peripheral.hasType` checks if a peripheral has a specific type.
* Add several missing keys to the `keys` table. (ralphgod3)
* Add feature introduction/changed version information to the documentation. (MCJack123)
* Increase the file upload limit to 512KiB.
* Rednet can now handle computer IDs larger than 65535. (Ale32bit)
* Optimise deduplication of rednet messages (MCJack123)
* Make `term.blit` colours case insensitive. (Ocawesome101)
* Add a new `about` program for easier version identification. (MCJack123)
* Optimise peripheral calls in `rednet.run`. (xAnavrins)
* Add dimension parameter to `commands.getBlockInfo`.
* Add `cc.pretty.pretty_print` helper function (Lupus590).
* Add back JEI integration.
* Turtle and pocket computer upgrades can now be added and modified with data packs.
* Various translation updates (MORIMORI3017, Ale2Bit, mindy15963)
And several bug fixes:
* Fix various computer commands failing when OP level was 4.
* Various documentation fixes. (xXTurnerLP, MCJack123)
* Fix `textutils.serialize` not serialising infinity and nan values. (Wojbie)
* Wired modems now correctly clean up mounts when a peripheral is detached.
* Fix incorrect turtle and pocket computer upgrade recipes in the recipe book.
* Fix speakers not playing sounds added via resource packs which are not registered in-game.
* Fix speaker upgrades sending packets after the server has stopped.
* Monitor sizing has been rewritten, hopefully making it more stable.
* Peripherals are now invalidated when the computer ticks, rather than when the peripheral changes.
* Fix printouts and pocket computers rendering at fullbright when in item frames.
* All mod blocks now have an effective tool (pickaxe).
# New features in CC: Tweaked 1.98.2 # New features in CC: Tweaked 1.98.2
* Add JP translation (MORIMORI0317) * Add JP translation (MORIMORI0317)

View File

@ -1,13 +1,32 @@
New features in CC: Tweaked 1.98.2 New features in CC: Tweaked 1.99.0
* Add JP translation (MORIMORI0317) * Pocket computers in their offhand will open without showing a terminal. You can look around and interact with the world, but your keyboard will be forwarded to the computer. (Wojbie, MagGen-hub).
* Migrate several recipes to data generators. * Peripherals can now have multiple types. `peripheral.getType` now returns multiple values, and `peripheral.hasType` checks if a peripheral has a specific type.
* Add several missing keys to the `keys` table. (ralphgod3)
* Add feature introduction/changed version information to the documentation. (MCJack123)
* Increase the file upload limit to 512KiB.
* Rednet can now handle computer IDs larger than 65535. (Ale32bit)
* Optimise deduplication of rednet messages (MCJack123)
* Make `term.blit` colours case insensitive. (Ocawesome101)
* Add a new `about` program for easier version identification. (MCJack123)
* Optimise peripheral calls in `rednet.run`. (xAnavrins)
* Add dimension parameter to `commands.getBlockInfo`.
* Add `cc.pretty.pretty_print` helper function (Lupus590).
* Add back JEI integration.
* Turtle and pocket computer upgrades can now be added and modified with data packs.
* Various translation updates (MORIMORI3017, Ale2Bit, mindy15963)
Several bug fixes: And several bug fixes:
* Fix volume speaker sounds are played at. * Fix various computer commands failing when OP level was 4.
* Fix several rendering issues when holding pocket computers and printouts in * Various documentation fixes. (xXTurnerLP, MCJack123)
hand. * Fix `textutils.serialize` not serialising infinity and nan values. (Wojbie)
* Ensure wired modems and cables join the wired network on chunk load. * Wired modems now correctly clean up mounts when a peripheral is detached.
* Fix stack overflow when using wired networks. * Fix incorrect turtle and pocket computer upgrade recipes in the recipe book.
* Fix speakers not playing sounds added via resource packs which are not registered in-game.
* Fix speaker upgrades sending packets after the server has stopped.
* Monitor sizing has been rewritten, hopefully making it more stable.
* Peripherals are now invalidated when the computer ticks, rather than when the peripheral changes.
* Fix printouts and pocket computers rendering at fullbright when in item frames.
* All mod blocks now have an effective tool (pickaxe).
Type "help changelog" to see the full version history. Type "help changelog" to see the full version history.

View File

@ -9,8 +9,8 @@
-- @usage Load an image from `example.nft` and draw it. -- @usage Load an image from `example.nft` and draw it.
-- --
-- local nft = require "cc.image.nft" -- local nft = require "cc.image.nft"
-- local image = assert(nft.load("example.nft")) -- local image = assert(nft.load("data/example.nft"))
-- nft.draw(image) -- nft.draw(image, term.getCursorPos())
local expect = require "cc.expect".expect local expect = require "cc.expect".expect
@ -41,6 +41,7 @@ local function parse(image)
end end
line = line + 1 line = line + 1
foreground, background = "0", "f"
else else
local next = image:find("[\n\30\31]", i) or #image + 1 local next = image:find("[\n\30\31]", i) or #image + 1
local seg_len = next - i local seg_len = next - i

View File

@ -19,7 +19,7 @@ The structure of this module is based on [A Prettier Printer][prettier].
@usage Print a table to the terminal @usage Print a table to the terminal
local pretty = require "cc.pretty" local pretty = require "cc.pretty"
pretty.print(pretty.pretty({ 1, 2, 3 })) pretty.pretty_print({ 1, 2, 3 })
@usage Build a custom document and display it @usage Build a custom document and display it
@ -463,6 +463,7 @@ end
-- --
-- local pretty = require "cc.pretty" -- local pretty = require "cc.pretty"
-- pretty.print(pretty.pretty({ 1, 2, 3 })) -- pretty.print(pretty.pretty({ 1, 2, 3 }))
-- @see pretty_print for a shorthand to prettify and print an object.
local function pretty(obj, options) local function pretty(obj, options)
expect(2, options, "table", "nil") expect(2, options, "table", "nil")
options = options or {} options = options or {}
@ -474,6 +475,33 @@ local function pretty(obj, options)
return pretty_impl(obj, actual_options, {}) return pretty_impl(obj, actual_options, {})
end end
--[[- A shortcut for calling @{pretty} and @{print} together.
@param obj The object to pretty-print.
@tparam[opt] { function_args = boolean, function_source = boolean } options
Controls how various properties are displayed.
- `function_args`: Show the arguments to a function if known (`false` by default).
- `function_source`: Show where the function was defined, instead of
`function: xxxxxxxx` (`false` by default).
@tparam[opt] number ribbon_frac The maximum fraction of the width that we should write in.
@usage Display a table on the screen.
local pretty = require "cc.pretty"
pretty.pretty_print({ 1, 2, 3 })
@see pretty
@see print
@since 1.99
]]
local function pretty_print(obj, options, ribbon_frac)
expect(2, options, "table", "nil")
options = options or {}
expect(3, ribbon_frac, "number", "nil")
return print(pretty(obj, options), ribbon_frac)
end
return { return {
empty = empty, empty = empty,
space = space, space = space,
@ -489,4 +517,6 @@ return {
render = render, render = render,
pretty = pretty, pretty = pretty,
pretty_print = pretty_print,
} }

View File

@ -3,7 +3,7 @@ print("Attached Peripherals:")
if #tPeripherals > 0 then if #tPeripherals > 0 then
for n = 1, #tPeripherals do for n = 1, #tPeripherals do
local sPeripheral = tPeripherals[n] local sPeripheral = tPeripherals[n]
print(sPeripheral .. " (" .. peripheral.getType(sPeripheral) .. ")") print(sPeripheral .. " (" .. table.concat({ peripheral.getType(sPeripheral) }, ", ") .. ")")
end end
else else
print("None") print("None")

View File

@ -15,6 +15,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeout
import kotlin.time.Duration import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
import kotlin.time.ExperimentalTime import kotlin.time.ExperimentalTime

View File

@ -1,6 +1,13 @@
describe("The peripheral library", function() describe("The peripheral library", function()
local it_modem = peripheral.getType("top") == "modem" and it or pending local it_modem = peripheral.getType("top") == "modem" and it or pending
local multitype_peripheral = setmetatable({}, {
__name = "peripheral",
name = "top",
type = "modem",
types = { "modem", "inventory", modem = true, inventory = true },
})
describe("peripheral.isPresent", function() describe("peripheral.isPresent", function()
it("validates arguments", function() it("validates arguments", function()
peripheral.isPresent("") peripheral.isPresent("")
@ -26,6 +33,10 @@ describe("The peripheral library", function()
expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)") expect.error(peripheral.getType, {}):eq("bad argument #1 (table is not a peripheral)")
end) end)
it("returns nil when no peripheral is present", function()
expect(peripheral.getType("bottom")):eq(nil)
end)
it_modem("can get the type of a peripheral by side", function() it_modem("can get the type of a peripheral by side", function()
expect(peripheral.getType("top")):eq("modem") expect(peripheral.getType("top")):eq("modem")
end) end)
@ -33,6 +44,38 @@ describe("The peripheral library", function()
it_modem("can get the type of a wrapped peripheral", function() it_modem("can get the type of a wrapped peripheral", function()
expect(peripheral.getType(peripheral.wrap("top"))):eq("modem") expect(peripheral.getType(peripheral.wrap("top"))):eq("modem")
end) end)
it("can return multiple types", function()
expect({ peripheral.getType(multitype_peripheral) }):same { "modem", "inventory" }
end)
end)
describe("peripheral.hasType", function()
it("validates arguments", function()
peripheral.getType("")
expect.error(peripheral.hasType, nil):eq("bad argument #1 (expected string or table, got nil)")
expect.error(peripheral.hasType, {}, ""):eq("bad argument #1 (table is not a peripheral)")
expect.error(peripheral.hasType, ""):eq("bad argument #2 (expected string, got nil)")
end)
it("returns nil when no peripherals are present", function()
expect(peripheral.hasType("bottom", "modem")):eq(nil)
end)
it_modem("can check type of a peripheral by side", function()
expect(peripheral.hasType("top", "modem")):eq(true)
expect(peripheral.hasType("top", "not_a_modem")):eq(false)
end)
it_modem("can check the type of a wrapped peripheral (true)", function()
expect(peripheral.hasType(peripheral.wrap("top"), "modem")):eq(true)
end)
it("can check the type of a wrapped peripheral (fake)", function()
expect(peripheral.hasType(multitype_peripheral, "modem")):eq(true)
expect(peripheral.hasType(multitype_peripheral, "inventory")):eq(true)
expect(peripheral.hasType(multitype_peripheral, "something else")):eq(false)
end)
end) end)
describe("peripheral.getMethods", function() describe("peripheral.getMethods", function()

21
src/web/copy-cat.d.ts vendored
View File

@ -1,21 +0,0 @@
import { h, Component, render, ComponentChild } from "preact";
export { h, Component, render };
export type ComputerAccess = unknown;
export type MainProps = {
hdFont?: boolean | string,
persistId?: number,
files?: { [filename: string]: string | ArrayBuffer },
label?: string,
width?: number,
height?: number,
resolve?: (computer: ComputerAccess) => void,
}
declare class Computer extends Component<MainProps, unknown> {
public render(props: MainProps, state: unknown): ComponentChild;
}
export { Computer };

View File

@ -4,15 +4,15 @@ import type { ComponentChild } from "preact";
import settingsFile from "./mount/.settings"; import settingsFile from "./mount/.settings";
import startupFile from "./mount/startup.lua"; import startupFile from "./mount/startup.lua";
import exprTemplate from "./mount/expr_template.lua"; import exprTemplate from "./mount/expr_template.lua";
import exampleImage from "./mount/example.nfp"; import exampleNfp from "./mount/example.nfp";
import exampleNft from "./mount/example.nft";
const defaultFiles: { [filename: string]: string } = { const defaultFiles: { [filename: string]: string } = {
".settings": settingsFile, ".settings": settingsFile,
"startup.lua": startupFile, "startup.lua": startupFile,
// TODO: Ideally this'd be in data/image.nfp or something, but copy-cat's "data/example.nfp": exampleNfp,
// dir bootstrapping doesn't cope with that right now. "data/example.nft": exampleNft,
"test-image.nfp": exampleImage
}; };
const clamp = (value: number, min: number, max: number): number => { const clamp = (value: number, min: number, max: number): number => {

15
src/web/mount/example.nft Normal file
View File

@ -0,0 +1,15 @@
4
4
4  4
0 4  4>0 ls 4
0 4  drom/ 4 0
0 4  startup.lua 4
0 4  4> 0hello 4
0 4  aHello World! 0 4
0 4  4
0 4  4
0 4  4
0 4
0 4  4
0 4

45
src/web/typings.ts Normal file
View File

@ -0,0 +1,45 @@
declare module "*.lua" {
const contents: string;
export default contents;
}
declare module "*.nfp" {
const contents: string;
export default contents;
}
declare module "*.nft" {
const contents: string;
export default contents;
}
declare module "*.settings" {
const contents: string;
export default contents;
}
declare module "copycat/embed" {
import { h, Component, render, ComponentChild } from "preact";
export { h, Component, render };
export type ComputerAccess = unknown;
export type MainProps = {
hdFont?: boolean | string,
persistId?: number,
files?: { [filename: string]: string | ArrayBuffer },
label?: string,
width?: number,
height?: number,
resolve?: (computer: ComputerAccess) => void,
}
class Computer extends Component<MainProps, unknown> {
public render(props: MainProps, state: unknown): ComponentChild;
}
export { Computer };
}

View File

@ -22,11 +22,6 @@
"noFallthroughCasesInSwitch": true, "noFallthroughCasesInSwitch": true,
"importsNotUsedAsValues": "error", "importsNotUsedAsValues": "error",
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"paths": {
"copycat/embed": [
"src/web/copy-cat.d.ts"
],
}
}, },
"include": [ "include": [
"src/web", "src/web",