Compare commits
63 Commits
v1.15.2-1.
...
v1.15.2-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f385f5b35 | ||
|
|
34baa09b6c | ||
|
|
b21866fbff | ||
|
|
e0a288bcb9 | ||
|
|
4592534a18 | ||
|
|
28165bfcd6 | ||
|
|
953b94fd08 | ||
|
|
e10e30f82b | ||
|
|
aeb1fa0e7e | ||
|
|
349a7543b0 | ||
|
|
3d589eda4a | ||
|
|
de646b66b6 | ||
|
|
4f0d311df7 | ||
|
|
d6e3c9a7fa | ||
|
|
a7a724f134 | ||
|
|
b0e30fdce1 | ||
|
|
4e15afa254 | ||
|
|
84bac06178 | ||
|
|
1fecb995c9 | ||
|
|
99b719299c | ||
|
|
fb9590467d | ||
|
|
bc8e090873 | ||
|
|
cf0f67265f | ||
|
|
53dd15a213 | ||
|
|
eb2d617ed8 | ||
|
|
74dae4ec17 | ||
|
|
abbc46877b | ||
|
|
3cb25b3525 | ||
|
|
92b45b1868 | ||
|
|
003c7ec2e8 | ||
|
|
c45221a2d0 | ||
|
|
8494ba8ce2 | ||
|
|
058d63e77f | ||
|
|
17b5bca443 | ||
|
|
c3f5700494 | ||
|
|
b17ff6daf0 | ||
|
|
e8f5531a8c | ||
|
|
51d3b091da | ||
|
|
9708dd6786 | ||
|
|
e48427dbbc | ||
|
|
669b6d2d56 | ||
|
|
32d956bbe7 | ||
|
|
3a147c78a8 | ||
|
|
66e42e0817 | ||
|
|
0ee3d10fda | ||
|
|
ed0afc4068 | ||
|
|
1f70ed6985 | ||
|
|
8f3ea60c74 | ||
|
|
eb722a74cd | ||
|
|
1825f67eee | ||
|
|
975a994581 | ||
|
|
061514549d | ||
|
|
5e52429c23 | ||
|
|
396cf15a1f | ||
|
|
1316d6a3c9 | ||
|
|
e1cbbe3628 | ||
|
|
6d367e08a3 | ||
|
|
eaa7359c8c | ||
|
|
657ceda3af | ||
|
|
a934e42219 | ||
|
|
1544749282 | ||
|
|
763bab80fa | ||
|
|
444830cf2d |
@@ -16,6 +16,3 @@ indent_size = 2
|
|||||||
|
|
||||||
[*.yml]
|
[*.yml]
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|
||||||
[*.properties]
|
|
||||||
insert_final_newline = false
|
|
||||||
|
|||||||
17
.github/matchers/checkstyle.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"owner": "checkstyle",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^([a-z]+) ([\\w./-]+):(\\d+):(\\d+): (.*)$",
|
||||||
|
"severity": 1,
|
||||||
|
"file": 2,
|
||||||
|
"line": 3,
|
||||||
|
"column": 4,
|
||||||
|
"message": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
18
.github/matchers/illuaminate.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"owner": "illuaminate",
|
||||||
|
"severity": "warning",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^([\\w./-]+):\\[(\\d+):(\\d+)\\-(?:\\d+):(?:\\d+)\\]: (.*) \\[([a-z:-]+)\\]$",
|
||||||
|
"file": 1,
|
||||||
|
"line": 2,
|
||||||
|
"column": 3,
|
||||||
|
"message": 4,
|
||||||
|
"code": 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
15
.github/matchers/junit.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"problemMatcher": [
|
||||||
|
{
|
||||||
|
"owner": "junit",
|
||||||
|
"pattern": [
|
||||||
|
{
|
||||||
|
"regexp": "^## ([\\w./-]+):(\\d+): (.*)$",
|
||||||
|
"file": 1,
|
||||||
|
"line": 2,
|
||||||
|
"message": 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
36
.github/workflows/main-ci.yml
vendored
@@ -23,10 +23,15 @@ jobs:
|
|||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-gradle-
|
${{ runner.os }}-gradle-
|
||||||
|
|
||||||
|
- name: Disable Gradle daemon
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.gradle
|
||||||
|
echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
|
||||||
|
|
||||||
- name: Build with Gradle
|
- name: Build with Gradle
|
||||||
run: |
|
run: |
|
||||||
./gradlew assemble --no-daemon || ./gradlew assemble --no-daemon
|
./gradlew assemble || ./gradlew assemble
|
||||||
./gradlew downloadAssets --no-daemon || ./gradlew downloadAssets --no-daemon
|
./gradlew downloadAssets || ./gradlew downloadAssets
|
||||||
./gradlew build
|
./gradlew build
|
||||||
|
|
||||||
- name: Upload Jar
|
- name: Upload Jar
|
||||||
@@ -36,18 +41,21 @@ jobs:
|
|||||||
path: build/libs
|
path: build/libs
|
||||||
|
|
||||||
- name: Upload Coverage
|
- name: Upload Coverage
|
||||||
run: bash <(curl -s https://codecov.io/bash)
|
uses: codecov/codecov-action@v1
|
||||||
continue-on-error: true
|
|
||||||
|
|
||||||
- name: Generate Java documentation stubs
|
- name: Parse test reports
|
||||||
run: ./gradlew luaJavadoc --no-daemon
|
run: ./tools/parse-reports.py
|
||||||
|
if: ${{ failure() }}
|
||||||
|
|
||||||
- name: Lint Lua code
|
- name: Cache pre-commit
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pre-commit
|
||||||
|
key: ${{ runner.os }}-pre-commit-${{ hashFiles('config/pre-commit/config.yml') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pre-commit-
|
||||||
|
|
||||||
|
- name: Run linters
|
||||||
run: |
|
run: |
|
||||||
test -d bin || mkdir bin
|
pip install pre-commit
|
||||||
test -f bin/illuaminate || wget -q -Obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
|
pre-commit run --config config/pre-commit/config.yml --show-diff-on-failure --all --color=always
|
||||||
chmod +x bin/illuaminate
|
|
||||||
bin/illuaminate lint
|
|
||||||
|
|
||||||
- name: Check whitespace
|
|
||||||
run: python3 tools/check-lines.py
|
|
||||||
|
|||||||
@@ -51,18 +51,10 @@ illuaminate, which spits out our HTML.
|
|||||||
For various reasons, getting the environment set up to build documentation can be pretty complex. I'd quite like to
|
For various reasons, getting the environment set up to build documentation can be pretty complex. I'd quite like to
|
||||||
automate this via Docker and/or nix in the future, but this needs to be done manually for now.
|
automate this via Docker and/or nix in the future, but this needs to be done manually for now.
|
||||||
|
|
||||||
First, you will need JDK 9+ (in addition to JDK 8 which is required to build Minecraft itself). Sadly our version of
|
This tooling is only needed if you need to build the whole website. If you just want to generate the Lua stubs, you can
|
||||||
Gradle doesn't support multiple toolchains, and so you need to install this yourself.
|
skp this section.
|
||||||
|
- Install Node/npm and install our Node packages with `npm ci`.
|
||||||
Gradle needs to be told about this JDK via the `JAVA_HOME_11_X64` environment variable or adding `java11Home` to
|
- Install [illuaminate][illuaminate-usage] as described above.
|
||||||
`~/.gradle/gradle.properties`. On my system this looks like:
|
|
||||||
|
|
||||||
```properties
|
|
||||||
java11Home=/usr/lib/jvm/java-11-openjdk/
|
|
||||||
```
|
|
||||||
|
|
||||||
If you just want to build the documentation stubs for linting, this is enough. However, if you want to build the full
|
|
||||||
website, you will also need to install a few Node packages by running `npm ci`.
|
|
||||||
|
|
||||||
#### Building documentation
|
#### Building documentation
|
||||||
Gradle should be your entrypoint to building most documentation. There's two tasks which are of interest:
|
Gradle should be your entrypoint to building most documentation. There's two tasks which are of interest:
|
||||||
|
|||||||
150
build.gradle
@@ -4,37 +4,41 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven {
|
maven {
|
||||||
name = "forge"
|
name = "forge"
|
||||||
url = "https://files.minecraftforge.net/maven"
|
url = "https://maven.minecraftforge.net"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.google.code.gson:gson:2.8.1'
|
classpath 'com.google.code.gson:gson:2.8.1'
|
||||||
classpath 'net.minecraftforge.gradle:ForgeGradle:3.0.190'
|
classpath 'net.minecraftforge.gradle:ForgeGradle:4.1.9'
|
||||||
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
|
classpath 'net.sf.proguard:proguard-gradle:6.1.0beta2'
|
||||||
classpath 'org.ajoberstar.grgit:grgit-gradle:3.0.0'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "checkstyle"
|
id "checkstyle"
|
||||||
id "jacoco"
|
id "jacoco"
|
||||||
|
id "maven-publish"
|
||||||
id "com.github.hierynomus.license" version "0.15.0"
|
id "com.github.hierynomus.license" version "0.15.0"
|
||||||
id "com.matthewprenger.cursegradle" version "1.3.0"
|
id "com.matthewprenger.cursegradle" version "1.4.0"
|
||||||
id "com.github.breadmoirai.github-release" version "2.2.4"
|
id "com.github.breadmoirai.github-release" version "2.2.12"
|
||||||
id "org.jetbrains.kotlin.jvm" version "1.3.72"
|
id "org.jetbrains.kotlin.jvm" version "1.3.72"
|
||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'net.minecraftforge.gradle'
|
apply plugin: 'net.minecraftforge.gradle'
|
||||||
apply plugin: 'org.ajoberstar.grgit'
|
|
||||||
apply plugin: 'maven-publish'
|
|
||||||
apply plugin: 'maven'
|
|
||||||
|
|
||||||
version = mod_version
|
version = mod_version
|
||||||
|
|
||||||
group = "org.squiddev"
|
group = "org.squiddev"
|
||||||
archivesBaseName = "cc-tweaked-${mc_version}"
|
archivesBaseName = "cc-tweaked-${mc_version}"
|
||||||
|
|
||||||
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8'
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(8)
|
||||||
|
}
|
||||||
|
|
||||||
|
withSourcesJar()
|
||||||
|
withJavadocJar()
|
||||||
|
}
|
||||||
|
|
||||||
minecraft {
|
minecraft {
|
||||||
runs {
|
runs {
|
||||||
@@ -110,7 +114,6 @@ repositories {
|
|||||||
configurations {
|
configurations {
|
||||||
shade
|
shade
|
||||||
compile.extendsFrom shade
|
compile.extendsFrom shade
|
||||||
deployerJars
|
|
||||||
cctJavadoc
|
cctJavadoc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,10 +127,7 @@ dependencies {
|
|||||||
|
|
||||||
runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3")
|
runtimeOnly fg.deobf("mezz.jei:jei-1.15.2:6.0.0.3")
|
||||||
|
|
||||||
compileOnly 'com.google.auto.service:auto-service:1.0-rc7'
|
shade 'org.squiddev:Cobalt:0.5.2-SNAPSHOT'
|
||||||
annotationProcessor 'com.google.auto.service:auto-service:1.0-rc7'
|
|
||||||
|
|
||||||
shade 'org.squiddev:Cobalt:0.5.1-SNAPSHOT'
|
|
||||||
|
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
|
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
|
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.7.0'
|
||||||
@@ -137,9 +137,7 @@ dependencies {
|
|||||||
testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.72'
|
testImplementation 'org.jetbrains.kotlin:kotlin-reflect:1.3.72'
|
||||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
|
||||||
|
|
||||||
deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
|
cctJavadoc 'cc.tweaked:cct-javadoc:1.4.0'
|
||||||
|
|
||||||
cctJavadoc 'cc.tweaked:cct-javadoc:1.3.0'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compile tasks
|
// Compile tasks
|
||||||
@@ -158,17 +156,14 @@ task luaJavadoc(type: Javadoc) {
|
|||||||
|
|
||||||
options.docletpath = configurations.cctJavadoc.files as List
|
options.docletpath = configurations.cctJavadoc.files as List
|
||||||
options.doclet = "cc.tweaked.javadoc.LuaDoclet"
|
options.doclet = "cc.tweaked.javadoc.LuaDoclet"
|
||||||
|
options.noTimestamp = false
|
||||||
|
|
||||||
// Attempt to run under Java 11 (any Java >= 9 will work though).
|
javadocTool = javaToolchains.javadocToolFor {
|
||||||
if(System.getProperty("java.version").startsWith("1.")
|
languageVersion = JavaLanguageVersion.of(11)
|
||||||
&& (System.getenv("JAVA_HOME_11_X64") != null || project.hasProperty("java11Home"))) {
|
|
||||||
executable = "${System.getenv("JAVA_HOME_11_X64") ?: project.property("java11Home")}/bin/javadoc"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
dependsOn javadoc
|
|
||||||
|
|
||||||
manifest {
|
manifest {
|
||||||
attributes(["Specification-Title": "computercraft",
|
attributes(["Specification-Title": "computercraft",
|
||||||
"Specification-Vendor": "SquidDev",
|
"Specification-Vendor": "SquidDev",
|
||||||
@@ -179,10 +174,6 @@ jar {
|
|||||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
|
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
|
||||||
}
|
}
|
||||||
|
|
||||||
from (sourceSets.main.allSource) {
|
|
||||||
include "dan200/computercraft/api/**/*.java"
|
|
||||||
}
|
|
||||||
|
|
||||||
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
|
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +191,6 @@ import com.google.gson.GsonBuilder
|
|||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.hierynomus.gradle.license.tasks.LicenseCheck
|
import com.hierynomus.gradle.license.tasks.LicenseCheck
|
||||||
import com.hierynomus.gradle.license.tasks.LicenseFormat
|
import com.hierynomus.gradle.license.tasks.LicenseFormat
|
||||||
import org.ajoberstar.grgit.Grgit
|
|
||||||
import proguard.gradle.ProGuardTask
|
import proguard.gradle.ProGuardTask
|
||||||
|
|
||||||
task proguard(type: ProGuardTask, dependsOn: jar) {
|
task proguard(type: ProGuardTask, dependsOn: jar) {
|
||||||
@@ -253,16 +243,15 @@ processResources {
|
|||||||
def hash = 'none'
|
def hash = 'none'
|
||||||
Set<String> contributors = []
|
Set<String> contributors = []
|
||||||
try {
|
try {
|
||||||
def grgit = Grgit.open(dir: '.')
|
hash = ["git", "-C", projectDir, "rev-parse", "HEAD"].execute().text.trim()
|
||||||
hash = grgit.head().id
|
|
||||||
|
|
||||||
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
|
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
|
||||||
grgit.log().each {
|
["git", "-C", projectDir, "log", "--format=tformat:%an%n%cn"].execute().text.split('\n').each {
|
||||||
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
|
if (!blacklist.contains(it)) contributors.add(it)
|
||||||
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
|
|
||||||
}
|
}
|
||||||
} catch(Exception ignored) { }
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
inputs.property "commithash", hash
|
inputs.property "commithash", hash
|
||||||
|
|
||||||
from(sourceSets.main.resources.srcDirs) {
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
@@ -483,8 +472,8 @@ tasks.register('jacocoTestInGameReport', JacocoReport.class).configure {
|
|||||||
it.dependsOn('testInGame')
|
it.dependsOn('testInGame')
|
||||||
|
|
||||||
it.executionData(new File(buildDir, 'jacoco/testInGame.exec'))
|
it.executionData(new File(buildDir, 'jacoco/testInGame.exec'))
|
||||||
it.setSourceDirectories(project.files(sourceSets.main.allJava.srcDirs))
|
it.sourceDirectories.from(sourceSets.main.allJava.srcDirs)
|
||||||
it.setClassDirectories(project.files(new File(buildDir, 'jacocoClassDump/testInGame')))
|
it.classDirectories.from(new File(buildDir, 'jacocoClassDump/testInGame'))
|
||||||
|
|
||||||
it.reports {
|
it.reports {
|
||||||
xml.enabled true
|
xml.enabled true
|
||||||
@@ -551,51 +540,41 @@ curseforge {
|
|||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
publications {
|
publications {
|
||||||
mavenJava(MavenPublication) {
|
maven(MavenPublication) {
|
||||||
from components.java
|
from components.java
|
||||||
// artifact sourceJar
|
|
||||||
|
pom {
|
||||||
|
name = 'CC: Tweaked'
|
||||||
|
description = 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
|
||||||
|
url = 'https://github.com/SquidDev-CC/CC-Tweaked'
|
||||||
|
|
||||||
|
scm {
|
||||||
|
url = 'https://github.com/SquidDev-CC/CC-Tweaked.git'
|
||||||
|
}
|
||||||
|
|
||||||
|
issueManagement {
|
||||||
|
system = 'github'
|
||||||
|
url = 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
|
||||||
|
}
|
||||||
|
|
||||||
|
licenses {
|
||||||
|
license {
|
||||||
|
name = 'ComputerCraft Public License, Version 1.0'
|
||||||
|
url = 'https://github.com/SquidDev-CC/CC-Tweaked/blob/mc-1.15.x/LICENSE'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uploadArchives {
|
|
||||||
repositories {
|
repositories {
|
||||||
if(project.hasProperty('mavenUploadUrl')) {
|
if (project.hasProperty("mavenUser")) {
|
||||||
mavenDeployer {
|
maven {
|
||||||
configuration = configurations.deployerJars
|
name = "SquidDev"
|
||||||
|
url = "https://squiddev.cc/maven"
|
||||||
repository(url: project.property('mavenUploadUrl')) {
|
credentials {
|
||||||
authentication(
|
username = project.property("mavenUser") as String
|
||||||
userName: project.property('mavenUploadUser'),
|
password = project.property("mavenPass") as String
|
||||||
privateKey: project.property('mavenUploadKey'))
|
|
||||||
}
|
|
||||||
|
|
||||||
pom.project {
|
|
||||||
name 'CC: Tweaked'
|
|
||||||
packaging 'jar'
|
|
||||||
description 'CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.'
|
|
||||||
url 'https://github.com/SquidDev-CC/CC-Tweaked'
|
|
||||||
|
|
||||||
scm {
|
|
||||||
url 'https://github.com/SquidDev-CC/CC-Tweaked.git'
|
|
||||||
}
|
|
||||||
|
|
||||||
issueManagement {
|
|
||||||
system 'github'
|
|
||||||
url 'https://github.com/SquidDev-CC/CC-Tweaked/issues'
|
|
||||||
}
|
|
||||||
|
|
||||||
licenses {
|
|
||||||
license {
|
|
||||||
name 'ComputerCraft Public License, Version 1.0'
|
|
||||||
url 'https://github.com/SquidDev-CC/CC-Tweaked/blob/master/LICENSE'
|
|
||||||
distribution 'repo'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pom.whenConfigured { pom ->
|
|
||||||
pom.dependencies.clear()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -606,22 +585,27 @@ githubRelease {
|
|||||||
token project.hasProperty('githubApiKey') ? project.githubApiKey : ''
|
token project.hasProperty('githubApiKey') ? project.githubApiKey : ''
|
||||||
owner 'SquidDev-CC'
|
owner 'SquidDev-CC'
|
||||||
repo 'CC-Tweaked'
|
repo 'CC-Tweaked'
|
||||||
try {
|
targetCommitish.set(project.provider({
|
||||||
targetCommitish = Grgit.open(dir: '.').branch.current().name
|
try {
|
||||||
} catch(Exception ignored) { }
|
return ["git", "-C", projectDir, "rev-parse", "--abbrev-ref", "HEAD"].execute().text.trim()
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return "master"
|
||||||
|
}))
|
||||||
|
|
||||||
tagName "v${mc_version}-${mod_version}"
|
tagName "v${mc_version}-${mod_version}"
|
||||||
releaseName "[${mc_version}] ${mod_version}"
|
releaseName "[${mc_version}] ${mod_version}"
|
||||||
body {
|
body.set(project.provider({
|
||||||
"## " + new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
|
"## " + new File(projectDir, "src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt")
|
||||||
.readLines()
|
.readLines()
|
||||||
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
|
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
|
||||||
.join("\n").trim()
|
.join("\n").trim()
|
||||||
}
|
}))
|
||||||
prerelease false
|
prerelease false
|
||||||
}
|
}
|
||||||
|
|
||||||
def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]
|
def uploadTasks = ["publish", "curseforge", "githubRelease"]
|
||||||
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
|
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
|
||||||
|
|
||||||
task uploadAll(dependsOn: uploadTasks) {
|
task uploadAll(dependsOn: uploadTasks) {
|
||||||
|
|||||||
55
config/pre-commit/config.yml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# See https://pre-commit.com for more information
|
||||||
|
# See https://pre-commit.com/hooks.html for more hooks
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v3.2.0
|
||||||
|
hooks:
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: check-merge-conflict
|
||||||
|
|
||||||
|
# Quick syntax checkers
|
||||||
|
- id: check-xml
|
||||||
|
- id: check-yaml
|
||||||
|
- id: check-toml
|
||||||
|
- id: check-json
|
||||||
|
exclude: "tsconfig\\.json$"
|
||||||
|
|
||||||
|
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
|
||||||
|
rev: 2.3.5
|
||||||
|
hooks:
|
||||||
|
- id: editorconfig-checker
|
||||||
|
args: ['-disable-indentation']
|
||||||
|
exclude: "^(.*\\.(bat)|LICENSE)$"
|
||||||
|
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: checkstyle
|
||||||
|
name: Check Java codestyle
|
||||||
|
files: ".*\\.java$"
|
||||||
|
language: system
|
||||||
|
entry: ./gradlew checkstyleMain checkstyleTest
|
||||||
|
pass_filenames: false
|
||||||
|
require_serial: true
|
||||||
|
- id: license
|
||||||
|
name: Check Java license headers
|
||||||
|
files: ".*\\.java$"
|
||||||
|
language: system
|
||||||
|
entry: ./gradlew licenseFormat
|
||||||
|
pass_filenames: false
|
||||||
|
require_serial: true
|
||||||
|
- id: illuaminate
|
||||||
|
name: Check Lua code
|
||||||
|
files: ".*\\.(lua|java|md)"
|
||||||
|
language: script
|
||||||
|
entry: config/pre-commit/illuaminate-lint.sh
|
||||||
|
pass_filenames: false
|
||||||
|
require_serial: true
|
||||||
|
|
||||||
|
exclude: |
|
||||||
|
(?x)^(
|
||||||
|
src/generated|
|
||||||
|
src/test/resources/test-rom/data/json-parsing/|
|
||||||
|
src/test/server-files/|
|
||||||
|
config/idea/
|
||||||
|
)
|
||||||
16
config/pre-commit/illuaminate-lint.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
set -e
|
||||||
|
|
||||||
|
test -d bin || mkdir bin
|
||||||
|
test -f bin/illuaminate || curl -s -obin/illuaminate https://squiddev.cc/illuaminate/linux-x86-64/illuaminate
|
||||||
|
chmod +x bin/illuaminate
|
||||||
|
|
||||||
|
if [ -n ${GITHUB_ACTIONS+x} ]; then
|
||||||
|
# Register a problem matcher (see https://github.com/actions/toolkit/blob/master/docs/problem-matchers.md)
|
||||||
|
# for illuaminate.
|
||||||
|
echo "::add-matcher::.github/matchers/illuaminate.json"
|
||||||
|
trap 'echo "::remove-matcher owner=illuaminate::"' EXIT
|
||||||
|
fi
|
||||||
|
|
||||||
|
./gradlew luaJavadoc
|
||||||
|
bin/illuaminate lint
|
||||||
21
doc/events/alarm.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] alarm
|
||||||
|
see: os.setAlarm To start an alarm.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{timer} event is fired when an alarm started with @{os.setAlarm} completes.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{number}: The ID of the alarm that finished.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Starts a timer and then prints its ID:
|
||||||
|
```lua
|
||||||
|
local alarmID = os.setAlarm(os.time() + 0.05)
|
||||||
|
local event, id
|
||||||
|
repeat
|
||||||
|
event, id = os.pullEvent("alarm")
|
||||||
|
until id == alarmID
|
||||||
|
print("Alarm with ID " .. id .. " was fired")
|
||||||
|
```
|
||||||
18
doc/events/computer_command.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] computer_command
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{computer_command} event is fired when the `/computercraft queue` command is run for the current computer.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
... @{string}: The arguments passed to the command.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints the contents of messages sent:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event = {os.pullEvent("computer_command")}
|
||||||
|
print("Received message:", table.unpack(event, 2))
|
||||||
|
end
|
||||||
|
```
|
||||||
19
doc/events/disk.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] disk
|
||||||
|
see: disk_eject For the event sent when a disk is removed.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{disk} event is fired when a disk is inserted into an adjacent or networked disk drive.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The side of the disk drive that had a disk inserted.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a disk is inserted:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, side = os.pullEvent("disk")
|
||||||
|
print("Inserted a disk on side " .. side)
|
||||||
|
end
|
||||||
|
```
|
||||||
19
doc/events/disk_eject.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] disk_eject
|
||||||
|
see: disk For the event sent when a disk is inserted.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{disk_eject} event is fired when a disk is removed from an adjacent or networked disk drive.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The side of the disk drive that had a disk removed.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a disk is removed:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, side = os.pullEvent("disk_eject")
|
||||||
|
print("Removed a disk on side " .. side)
|
||||||
|
end
|
||||||
|
```
|
||||||
14
doc/events/http_check.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] http_check
|
||||||
|
see: http.checkURLAsync To check a URL asynchronously.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{http_check} event is fired when a URL check finishes.
|
||||||
|
|
||||||
|
This event is normally handled inside @{http.checkURL}, but it can still be seen when using @{http.checkURLAsync}.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The URL requested to be checked.
|
||||||
|
3. @{boolean}: Whether the check succeeded.
|
||||||
|
4. @{string|nil}: If the check failed, a reason explaining why the check failed.
|
||||||
39
doc/events/http_failure.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] http_failure
|
||||||
|
see: http.request To send an HTTP request.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{http_failure} event is fired when an HTTP request fails.
|
||||||
|
|
||||||
|
This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The URL of the site requested.
|
||||||
|
3. @{string}: An error describing the failure.
|
||||||
|
4. @{http.Response|nil}: A response handle if the connection succeeded, but the server's response indicated failure.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints an error why the website cannot be contacted:
|
||||||
|
```lua
|
||||||
|
local myURL = "https://does.not.exist.tweaked.cc"
|
||||||
|
http.request(myURL)
|
||||||
|
local event, url, err
|
||||||
|
repeat
|
||||||
|
event, url, err = os.pullEvent("http_failure")
|
||||||
|
until url == myURL
|
||||||
|
print("The URL " .. url .. " could not be reached: " .. err)
|
||||||
|
```
|
||||||
|
|
||||||
|
Prints the contents of a webpage that does not exist:
|
||||||
|
```lua
|
||||||
|
local myURL = "https://tweaked.cc/this/does/not/exist"
|
||||||
|
http.request(myURL)
|
||||||
|
local event, url, err, handle
|
||||||
|
repeat
|
||||||
|
event, url, err, handle = os.pullEvent("http_failure")
|
||||||
|
until url == myURL
|
||||||
|
print("The URL " .. url .. " could not be reached: " .. err)
|
||||||
|
print(handle.getResponseCode())
|
||||||
|
handle.close()
|
||||||
|
```
|
||||||
27
doc/events/http_success.md
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] http_success
|
||||||
|
see: http.request To make an HTTP request.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{http_success} event is fired when an HTTP request returns successfully.
|
||||||
|
|
||||||
|
This event is normally handled inside @{http.get} and @{http.post}, but it can still be seen when using @{http.request}.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The URL of the site requested.
|
||||||
|
3. @{http.Response}: The handle for the response text.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints the content of a website (this may fail if the request fails):
|
||||||
|
```lua
|
||||||
|
local myURL = "https://tweaked.cc/"
|
||||||
|
http.request(myURL)
|
||||||
|
local event, url, handle
|
||||||
|
repeat
|
||||||
|
event, url, handle = os.pullEvent("http_success")
|
||||||
|
until url == myURL
|
||||||
|
print("Contents of " .. url .. ":")
|
||||||
|
print(handle.readAll())
|
||||||
|
handle.close()
|
||||||
|
```
|
||||||
@@ -11,9 +11,9 @@ If the button pressed represented a printable character, then the @{key} event w
|
|||||||
event. If you are consuming text input, use a @{char} event instead!
|
event. If you are consuming text input, use a @{char} event instead!
|
||||||
|
|
||||||
## Return values
|
## Return values
|
||||||
1. [`string`]: The event name.
|
1. @{string}: The event name.
|
||||||
2. [`number`]: The numerical key value of the key pressed.
|
2. @{number}: The numerical key value of the key pressed.
|
||||||
3. [`boolean`]: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}).
|
3. @{boolean}: Whether the key event was generated while holding the key (@{true}), rather than pressing it the first time (@{false}).
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
Prints each key when the user presses it, and if the key is being held.
|
Prints each key when the user presses it, and if the key is being held.
|
||||||
|
|||||||
22
doc/events/modem_message.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] modem_message
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{modem_message} event is fired when a message is received on an open channel on any modem.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The side of the modem that received the message.
|
||||||
|
3. @{number}: The channel that the message was sent on.
|
||||||
|
4. @{number}: The reply channel set by the sender.
|
||||||
|
5. @{any}: The message as sent by the sender.
|
||||||
|
6. @{number}: The distance between the sender and the receiver, in blocks (decimal).
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when one is sent:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, side, channel, replyChannel, message, distance = os.pullEvent("modem_message")
|
||||||
|
print(("Message received on side %s on channel %d (reply to %d) from %f blocks away with message %s"):format(side, channel, replyChannel, distance, tostring(message)))
|
||||||
|
end
|
||||||
|
```
|
||||||
18
doc/events/monitor_resize.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] monitor_resize
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{monitor_resize} event is fired when an adjacent or networked monitor's size is changed.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The side or network ID of the monitor that resized.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a monitor is resized:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, side = os.pullEvent("monitor_resize")
|
||||||
|
print("The monitor on side " .. side .. " was resized.")
|
||||||
|
end
|
||||||
|
```
|
||||||
20
doc/events/monitor_touch.md
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] monitor_touch
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{monitor_touch} event is fired when an adjacent or networked Advanced Monitor is right-clicked.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The side or network ID of the monitor that was touched.
|
||||||
|
3. @{number}: The X coordinate of the touch, in characters.
|
||||||
|
4. @{number}: The Y coordinate of the touch, in characters.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a monitor is touched:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, side, x, y = os.pullEvent("monitor_touch")
|
||||||
|
print("The monitor on side " .. side .. " was touched at (" .. x .. ", " .. y .. ")")
|
||||||
|
end
|
||||||
|
```
|
||||||
@@ -20,5 +20,3 @@ while true do
|
|||||||
print(("The mouse button %s was dragged at %d, %d"):format(button, x, y))
|
print(("The mouse button %s was dragged at %d, %d"):format(button, x, y))
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,3 @@ while true do
|
|||||||
print(("The mouse button %s was released at %d, %d"):format(button, x, y))
|
print(("The mouse button %s was released at %d, %d"):format(button, x, y))
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
[`string`]: string
|
|
||||||
[`number`]: number
|
|
||||||
|
|||||||
18
doc/events/paste.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] paste
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{paste} event is fired when text is pasted into the computer through Ctrl-V (or ⌘V on Mac).
|
||||||
|
|
||||||
|
## Return values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string} The text that was pasted.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints pasted text:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, text = os.pullEvent("paste")
|
||||||
|
print('"' .. text .. '" was pasted')
|
||||||
|
end
|
||||||
|
```
|
||||||
19
doc/events/peripheral.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] peripheral
|
||||||
|
see: peripheral_detach For the event fired when a peripheral is detached.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{peripheral} event is fired when a peripheral is attached on a side or to a modem.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The side the peripheral was attached to.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a peripheral is attached:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, side = os.pullEvent("peripheral")
|
||||||
|
print("A peripheral was attached on side " .. side)
|
||||||
|
end
|
||||||
|
```
|
||||||
19
doc/events/peripheral_detach.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] peripheral_detach
|
||||||
|
see: peripheral For the event fired when a peripheral is attached.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{peripheral_detach} event is fired when a peripheral is detached from a side or from a modem.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The side the peripheral was detached from.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a peripheral is detached:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, side = os.pullEvent("peripheral_detach")
|
||||||
|
print("A peripheral was detached on side " .. side)
|
||||||
|
end
|
||||||
|
```
|
||||||
30
doc/events/rednet_message.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] rednet_message
|
||||||
|
see: modem_message For raw modem messages sent outside of Rednet.
|
||||||
|
see: rednet.receive To wait for a Rednet message with an optional timeout and protocol filter.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{rednet_message} event is fired when a message is sent over Rednet.
|
||||||
|
|
||||||
|
This event is usually handled by @{rednet.receive}, but it can also be pulled manually.
|
||||||
|
|
||||||
|
@{rednet_message} events are sent by @{rednet.run} in the top-level coroutine in response to @{modem_message} events. A @{rednet_message} event is always preceded by a @{modem_message} event. They are generated inside CraftOS rather than being sent by the ComputerCraft machine.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{number}: The ID of the sending computer.
|
||||||
|
3. @{any}: The message sent.
|
||||||
|
4. @{string|nil}: The protocol of the message, if provided.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when one is sent:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event, sender, message, protocol = os.pullEvent("rednet_message")
|
||||||
|
if protocol ~= nil then
|
||||||
|
print("Received message from " .. sender .. " with protocol " .. protocol .. " and message " .. tostring(message))
|
||||||
|
else
|
||||||
|
print("Received message from " .. sender .. " with message " .. tostring(message))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
14
doc/events/redstone.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] redstone
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{redstone} event is fired whenever any redstone inputs on the computer change.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a redstone input changes:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
os.pullEvent("redstone")
|
||||||
|
print("A redstone input has changed!")
|
||||||
|
end
|
||||||
|
```
|
||||||
28
doc/events/task_complete.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] task_complete
|
||||||
|
see: commands.execAsync To run a command which fires a task_complete event.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{task_complete} event is fired when an asynchronous task completes. This is usually handled inside the function call that queued the task; however, functions such as @{commands.execAsync} return immediately so the user can wait for completion.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{number}: The ID of the task that completed.
|
||||||
|
3. @{boolean}: Whether the command succeeded.
|
||||||
|
4. @{string}: If the command failed, an error message explaining the failure. (This is not present if the command succeeded.)
|
||||||
|
...: Any parameters returned from the command.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints the results of an asynchronous command:
|
||||||
|
```lua
|
||||||
|
local taskID = commands.execAsync("say Hello")
|
||||||
|
local event
|
||||||
|
repeat
|
||||||
|
event = {os.pullEvent("task_complete")}
|
||||||
|
until event[2] == taskID
|
||||||
|
if event[3] == true then
|
||||||
|
print("Task " .. event[2] .. " succeeded:", table.unpack(event, 4))
|
||||||
|
else
|
||||||
|
print("Task " .. event[2] .. " failed: " .. event[4])
|
||||||
|
end
|
||||||
|
```
|
||||||
15
doc/events/term_resize.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] term_resize
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{term_resize} event is fired when the main terminal is resized, mainly when a new tab is opened or closed in @{multishell}.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints :
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
os.pullEvent("term_resize")
|
||||||
|
local w, h = term.getSize()
|
||||||
|
print("The term was resized to (" .. w .. ", " .. h .. ")")
|
||||||
|
end
|
||||||
|
```
|
||||||
25
doc/events/terminate.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] terminate
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{terminate} event is fired when <kbd>Ctrl-T</kbd> is held down.
|
||||||
|
|
||||||
|
This event is normally handled by @{os.pullEvent}, and will not be returned. However, @{os.pullEventRaw} will return this event when fired.
|
||||||
|
|
||||||
|
@{terminate} will be sent even when a filter is provided to @{os.pullEventRaw}. When using @{os.pullEventRaw} with a filter, make sure to check that the event is not @{terminate}.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when Ctrl-T is held:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
local event = os.pullEventRaw("terminate")
|
||||||
|
if event == "terminate" then print("Terminate requested!") end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Exits when Ctrl-T is held:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
os.pullEvent()
|
||||||
|
end
|
||||||
|
```
|
||||||
21
doc/events/timer.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] timer
|
||||||
|
see: os.startTimer To start a timer.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{timer} event is fired when a timer started with @{os.startTimer} completes.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{number}: The ID of the timer that finished.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Starts a timer and then prints its ID:
|
||||||
|
```lua
|
||||||
|
local timerID = os.startTimer(2)
|
||||||
|
local event, id
|
||||||
|
repeat
|
||||||
|
event, id = os.pullEvent("timer")
|
||||||
|
until id == timerID
|
||||||
|
print("Timer with ID " .. id .. " was fired")
|
||||||
|
```
|
||||||
14
doc/events/turtle_inventory.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] turtle_inventory
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{turtle_inventory} event is fired when a turtle's inventory is changed.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when the inventory is changed:
|
||||||
|
```lua
|
||||||
|
while true do
|
||||||
|
os.pullEvent("turtle_inventory")
|
||||||
|
print("The inventory was changed.")
|
||||||
|
end
|
||||||
|
```
|
||||||
21
doc/events/websocket_closed.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] websocket_closed
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{websocket_closed} event is fired when an open WebSocket connection is closed.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The URL of the WebSocket that was closed.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message when a WebSocket is closed (this may take a minute):
|
||||||
|
```lua
|
||||||
|
local myURL = "wss://example.tweaked.cc/echo"
|
||||||
|
local ws = http.websocket(myURL)
|
||||||
|
local event, url
|
||||||
|
repeat
|
||||||
|
event, url = os.pullEvent("websocket_closed")
|
||||||
|
until url == myURL
|
||||||
|
print("The WebSocket at " .. url .. " was closed.")
|
||||||
|
```
|
||||||
25
doc/events/websocket_failure.md
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] websocket_failure
|
||||||
|
see: http.websocketAsync To send an HTTP request.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{websocket_failure} event is fired when a WebSocket connection request fails.
|
||||||
|
|
||||||
|
This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The URL of the site requested.
|
||||||
|
3. @{string}: An error describing the failure.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints an error why the website cannot be contacted:
|
||||||
|
```lua
|
||||||
|
local myURL = "wss://example.tweaked.cc/not-a-websocket"
|
||||||
|
http.websocketAsync(myURL)
|
||||||
|
local event, url, err
|
||||||
|
repeat
|
||||||
|
event, url, err = os.pullEvent("websocket_failure")
|
||||||
|
until url == myURL
|
||||||
|
print("The URL " .. url .. " could not be reached: " .. err)
|
||||||
|
```
|
||||||
26
doc/events/websocket_message.md
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] websocket_message
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{websocket_message} event is fired when a message is received on an open WebSocket connection.
|
||||||
|
|
||||||
|
This event is normally handled by @{http.Websocket.receive}, but it can also be pulled manually.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The URL of the WebSocket.
|
||||||
|
3. @{string}: The contents of the message.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints a message sent by a WebSocket:
|
||||||
|
```lua
|
||||||
|
local myURL = "wss://example.tweaked.cc/echo"
|
||||||
|
local ws = http.websocket(myURL)
|
||||||
|
ws.send("Hello!")
|
||||||
|
local event, url, message
|
||||||
|
repeat
|
||||||
|
event, url, message = os.pullEvent("websocket_message")
|
||||||
|
until url == myURL
|
||||||
|
print("Received message from " .. url .. " with contents " .. message)
|
||||||
|
ws.close()
|
||||||
|
```
|
||||||
28
doc/events/websocket_success.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
module: [kind=event] websocket_success
|
||||||
|
see: http.websocketAsync To open a WebSocket asynchronously.
|
||||||
|
---
|
||||||
|
|
||||||
|
The @{websocket_success} event is fired when a WebSocket connection request returns successfully.
|
||||||
|
|
||||||
|
This event is normally handled inside @{http.websocket}, but it can still be seen when using @{http.websocketAsync}.
|
||||||
|
|
||||||
|
## Return Values
|
||||||
|
1. @{string}: The event name.
|
||||||
|
2. @{string}: The URL of the site.
|
||||||
|
3. @{http.Websocket}: The handle for the WebSocket.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
Prints the content of a website (this may fail if the request fails):
|
||||||
|
```lua
|
||||||
|
local myURL = "wss://example.tweaked.cc/echo"
|
||||||
|
http.websocketAsync(myURL)
|
||||||
|
local event, url, handle
|
||||||
|
repeat
|
||||||
|
event, url, handle = os.pullEvent("websocket_success")
|
||||||
|
until url == myURL
|
||||||
|
print("Connected to " .. url)
|
||||||
|
handle.send("Hello!")
|
||||||
|
print(handle.receive())
|
||||||
|
handle.close()
|
||||||
|
```
|
||||||
@@ -58,10 +58,10 @@ function request(...) end
|
|||||||
-- @treturn string A message detailing why the request failed.
|
-- @treturn string A message detailing why the request failed.
|
||||||
-- @treturn Response|nil The failing http response, if available.
|
-- @treturn Response|nil The failing http response, if available.
|
||||||
--
|
--
|
||||||
-- @usage Make a request to [example.computercraft.cc](https://example.computercraft.cc),
|
-- @usage Make a request to [example.tweaked.cc](https://example.tweaked.cc),
|
||||||
-- and print the returned page.
|
-- and print the returned page.
|
||||||
-- ```lua
|
-- ```lua
|
||||||
-- local request = http.get("https://example.computercraft.cc")
|
-- local request = http.get("https://example.tweaked.cc")
|
||||||
-- print(request.readAll())
|
-- print(request.readAll())
|
||||||
-- -- => HTTP is working!
|
-- -- => HTTP is working!
|
||||||
-- request.close()
|
-- request.close()
|
||||||
@@ -123,7 +123,7 @@ function checkURLAsync(url) end
|
|||||||
--
|
--
|
||||||
-- @usage
|
-- @usage
|
||||||
-- ```lua
|
-- ```lua
|
||||||
-- print(http.checkURL("https://example.computercraft.cc/"))
|
-- print(http.checkURL("https://example.tweaked.cc/"))
|
||||||
-- -- => true
|
-- -- => true
|
||||||
-- print(http.checkURL("http://localhost/"))
|
-- print(http.checkURL("http://localhost/"))
|
||||||
-- -- => false Domain not permitted
|
-- -- => false Domain not permitted
|
||||||
|
|||||||
@@ -1 +1,13 @@
|
|||||||
|
--[[- Craft a recipe based on the turtle's inventory.
|
||||||
|
|
||||||
|
The turtle's inventory should set up like a crafting grid. For instance, to
|
||||||
|
craft sticks, slots 1 and 5 should contain sticks. _All_ other slots should be
|
||||||
|
empty, including those outside the crafting "grid".
|
||||||
|
|
||||||
|
@tparam[opt=64] number limit The maximum number of crafting steps to run.
|
||||||
|
@throws When limit is less than 1 or greater than 64.
|
||||||
|
@treturn[1] true If crafting succeeds.
|
||||||
|
@treturn[2] false If crafting fails.
|
||||||
|
@treturn string A string describing why crafting failed.
|
||||||
|
]]
|
||||||
function craft(limit) end
|
function craft(limit) end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Mod properties
|
# Mod properties
|
||||||
mod_version=1.95.2
|
mod_version=1.96.0
|
||||||
|
|
||||||
# Minecraft properties (update mods.toml when changing)
|
# Minecraft properties (update mods.toml when changing)
|
||||||
mc_version=1.15.2
|
mc_version=1.15.2
|
||||||
|
|||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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-4.9-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
53
gradlew
vendored
@@ -1,5 +1,21 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2015 the original author or authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
##
|
||||||
## Gradle start up script for UN*X
|
## Gradle start up script for UN*X
|
||||||
@@ -28,7 +44,7 @@ APP_NAME="Gradle"
|
|||||||
APP_BASE_NAME=`basename "$0"`
|
APP_BASE_NAME=`basename "$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=""
|
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"
|
||||||
@@ -66,6 +82,7 @@ esac
|
|||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
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
|
||||||
@@ -109,10 +126,11 @@ if $darwin; then
|
|||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if $cygwin ; then
|
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
@@ -138,19 +156,19 @@ if $cygwin ; then
|
|||||||
else
|
else
|
||||||
eval `echo args$i`="\"$arg\""
|
eval `echo args$i`="\"$arg\""
|
||||||
fi
|
fi
|
||||||
i=$((i+1))
|
i=`expr $i + 1`
|
||||||
done
|
done
|
||||||
case $i in
|
case $i in
|
||||||
(0) set -- ;;
|
0) set -- ;;
|
||||||
(1) set -- "$args0" ;;
|
1) set -- "$args0" ;;
|
||||||
(2) set -- "$args0" "$args1" ;;
|
2) set -- "$args0" "$args1" ;;
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -159,14 +177,9 @@ save () {
|
|||||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||||
echo " "
|
echo " "
|
||||||
}
|
}
|
||||||
APP_ARGS=$(save "$@")
|
APP_ARGS=`save "$@"`
|
||||||
|
|
||||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||||
|
|
||||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
|
||||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
exec "$JAVACMD" "$@"
|
||||||
|
|||||||
43
gradlew.bat
vendored
@@ -1,3 +1,19 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
@if "%DEBUG%" == "" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
|||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS=
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
@@ -35,7 +54,7 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
@@ -45,28 +64,14 @@ echo location of your Java installation.
|
|||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windows variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -88,27 +88,16 @@
|
|||||||
|
|
||||||
;; Suppress warnings for currently undocumented modules.
|
;; Suppress warnings for currently undocumented modules.
|
||||||
(at
|
(at
|
||||||
(; Java APIs
|
(; Lua APIs
|
||||||
/doc/stub/http.lua
|
|
||||||
/doc/stub/os.lua
|
|
||||||
/doc/stub/turtle.lua
|
|
||||||
/doc/stub/global.lua
|
|
||||||
; Java generated APIs
|
|
||||||
/build/docs/luaJavadoc/turtle.lua
|
|
||||||
; Peripherals
|
|
||||||
/build/docs/luaJavadoc/drive.lua
|
|
||||||
/build/docs/luaJavadoc/speaker.lua
|
|
||||||
/build/docs/luaJavadoc/printer.lua
|
|
||||||
; Generic peripherals
|
|
||||||
/build/docs/luaJavadoc/fluid_storage.lua
|
|
||||||
; Lua APIs
|
|
||||||
/src/main/resources/*/computercraft/lua/rom/apis/io.lua
|
/src/main/resources/*/computercraft/lua/rom/apis/io.lua
|
||||||
/src/main/resources/*/computercraft/lua/rom/apis/window.lua)
|
/src/main/resources/*/computercraft/lua/rom/apis/window.lua)
|
||||||
|
|
||||||
(linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return))
|
(linters -doc:undocumented -doc:undocumented-arg -doc:undocumented-return))
|
||||||
|
|
||||||
;; Suppress warnings for the BIOS using its own deprecated members for now.
|
;; Suppress warnings for various APIs using its own deprecated members.
|
||||||
(at /src/main/resources/*/computercraft/lua/bios.lua
|
(at
|
||||||
|
(/src/main/resources/*/computercraft/lua/bios.lua
|
||||||
|
/src/main/resources/*/computercraft/lua/rom/apis/turtle/turtle.lua)
|
||||||
(linters -var:deprecated))
|
(linters -var:deprecated))
|
||||||
|
|
||||||
(at /src/test/resources/test-rom
|
(at /src/test/resources/test-rom
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ package dan200.computercraft;
|
|||||||
import dan200.computercraft.api.turtle.event.TurtleAction;
|
import dan200.computercraft.api.turtle.event.TurtleAction;
|
||||||
import dan200.computercraft.core.apis.http.options.Action;
|
import dan200.computercraft.core.apis.http.options.Action;
|
||||||
import dan200.computercraft.core.apis.http.options.AddressRule;
|
import dan200.computercraft.core.apis.http.options.AddressRule;
|
||||||
import dan200.computercraft.core.asm.GenericSource;
|
|
||||||
import dan200.computercraft.shared.Config;
|
import dan200.computercraft.shared.Config;
|
||||||
import dan200.computercraft.shared.Registry;
|
import dan200.computercraft.shared.Registry;
|
||||||
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
|
import dan200.computercraft.shared.computer.core.ClientComputerRegistry;
|
||||||
@@ -17,7 +16,6 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer;
|
|||||||
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
|
import dan200.computercraft.shared.pocket.peripherals.PocketModem;
|
||||||
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
|
import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker;
|
||||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
import dan200.computercraft.shared.turtle.upgrades.*;
|
||||||
import dan200.computercraft.shared.util.ServiceUtil;
|
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@@ -117,6 +115,5 @@ public final class ComputerCraft
|
|||||||
{
|
{
|
||||||
Config.setup();
|
Config.setup();
|
||||||
Registry.setup();
|
Registry.setup();
|
||||||
GenericSource.setup( () -> ServiceUtil.loadServicesForge( GenericSource.class ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package dan200.computercraft;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI.IComputerCraftAPI;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.GenericSource;
|
||||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
import dan200.computercraft.api.media.IMediaProvider;
|
import dan200.computercraft.api.media.IMediaProvider;
|
||||||
import dan200.computercraft.api.network.IPacketNetwork;
|
import dan200.computercraft.api.network.IPacketNetwork;
|
||||||
@@ -18,9 +19,11 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
|
|||||||
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.core.apis.ApiFactories;
|
import dan200.computercraft.core.apis.ApiFactories;
|
||||||
|
import dan200.computercraft.core.asm.GenericMethod;
|
||||||
import dan200.computercraft.core.filesystem.FileMount;
|
import dan200.computercraft.core.filesystem.FileMount;
|
||||||
import dan200.computercraft.core.filesystem.ResourceMount;
|
import dan200.computercraft.core.filesystem.ResourceMount;
|
||||||
import dan200.computercraft.shared.*;
|
import dan200.computercraft.shared.*;
|
||||||
|
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
||||||
import dan200.computercraft.shared.util.IDAssigner;
|
import dan200.computercraft.shared.util.IDAssigner;
|
||||||
import dan200.computercraft.shared.wired.WiredNode;
|
import dan200.computercraft.shared.wired.WiredNode;
|
||||||
@@ -31,6 +34,7 @@ import net.minecraft.util.ResourceLocation;
|
|||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
import net.minecraftforge.fml.ModList;
|
import net.minecraftforge.fml.ModList;
|
||||||
import net.minecraftforge.fml.server.ServerLifecycleHooks;
|
import net.minecraftforge.fml.server.ServerLifecycleHooks;
|
||||||
@@ -108,6 +112,18 @@ public final class ComputerCraftAPIImpl implements IComputerCraftAPI
|
|||||||
Peripherals.register( provider );
|
Peripherals.register( provider );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerGenericSource( @Nonnull GenericSource source )
|
||||||
|
{
|
||||||
|
GenericMethod.register( source );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerGenericCapability( @Nonnull Capability<?> capability )
|
||||||
|
{
|
||||||
|
GenericPeripheralProvider.addCapability( capability );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
|
public void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ package dan200.computercraft.api;
|
|||||||
|
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||||
|
import dan200.computercraft.api.lua.GenericSource;
|
||||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
import dan200.computercraft.api.media.IMedia;
|
import dan200.computercraft.api.media.IMedia;
|
||||||
import dan200.computercraft.api.media.IMediaProvider;
|
import dan200.computercraft.api.media.IMediaProvider;
|
||||||
@@ -23,6 +24,7 @@ import net.minecraft.util.Direction;
|
|||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.IBlockReader;
|
import net.minecraft.world.IBlockReader;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@@ -98,7 +100,9 @@ public final class ComputerCraftAPI
|
|||||||
* resource folder onto a computer's file system.
|
* resource folder onto a computer's file system.
|
||||||
*
|
*
|
||||||
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
|
* The files in this mount will be a combination of files in all mod jar, and data packs that contain
|
||||||
* resources with the same domain and path.
|
* resources with the same domain and path. For instance, ComputerCraft's resources are stored in
|
||||||
|
* "/data/computercraft/lua/rom". We construct a mount for that with
|
||||||
|
* {@code createResourceMount("computercraft", "lua/rom")}.
|
||||||
*
|
*
|
||||||
* @param domain The domain under which to look for resources. eg: "mymod".
|
* @param domain The domain under which to look for resources. eg: "mymod".
|
||||||
* @param subPath The subPath under which to look for resources. eg: "lua/myfiles".
|
* @param subPath The subPath under which to look for resources. eg: "lua/myfiles".
|
||||||
@@ -114,7 +118,7 @@ public final class ComputerCraftAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
|
* rers a peripheral provider to convert blocks into {@link IPeripheral} implementations.
|
||||||
*
|
*
|
||||||
* @param provider The peripheral provider to register.
|
* @param provider The peripheral provider to register.
|
||||||
* @see IPeripheral
|
* @see IPeripheral
|
||||||
@@ -125,6 +129,28 @@ public final class ComputerCraftAPI
|
|||||||
getInstance().registerPeripheralProvider( provider );
|
getInstance().registerPeripheralProvider( provider );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a method source for generic peripherals.
|
||||||
|
*
|
||||||
|
* @param source The method source to register.
|
||||||
|
* @see GenericSource
|
||||||
|
*/
|
||||||
|
public static void registerGenericSource( @Nonnull GenericSource source )
|
||||||
|
{
|
||||||
|
getInstance().registerGenericSource( source );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a capability that can be used by generic peripherals.
|
||||||
|
*
|
||||||
|
* @param capability The capability to register.
|
||||||
|
* @see GenericSource
|
||||||
|
*/
|
||||||
|
public static void registerGenericCapability( @Nonnull Capability<?> capability )
|
||||||
|
{
|
||||||
|
getInstance().registerGenericCapability( capability );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a new turtle turtle for use in ComputerCraft. After calling this,
|
* Registers a new turtle turtle for use in ComputerCraft. After calling this,
|
||||||
* users should be able to craft Turtles with your new turtle. It is recommended to call
|
* users should be able to craft Turtles with your new turtle. It is recommended to call
|
||||||
@@ -256,6 +282,10 @@ public final class ComputerCraftAPI
|
|||||||
|
|
||||||
void registerPeripheralProvider( @Nonnull IPeripheralProvider provider );
|
void registerPeripheralProvider( @Nonnull IPeripheralProvider provider );
|
||||||
|
|
||||||
|
void registerGenericSource( @Nonnull GenericSource source );
|
||||||
|
|
||||||
|
void registerGenericCapability( @Nonnull Capability<?> capability );
|
||||||
|
|
||||||
void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade );
|
void registerTurtleUpgrade( @Nonnull ITurtleUpgrade upgrade );
|
||||||
|
|
||||||
void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider );
|
void registerBundledRedstoneProvider( @Nonnull IBundledRedstoneProvider provider );
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2021. This API may be redistributed unmodified and in full only.
|
||||||
|
* For help using the API, and posting your mods, visit the forums at computercraft.info.
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.api.peripheral.IPeripheralProvider;
|
||||||
|
import dan200.computercraft.core.asm.LuaMethod;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
|
import net.minecraftforge.items.IItemHandler;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic source of {@link LuaMethod} functions.
|
||||||
|
*
|
||||||
|
* Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but
|
||||||
|
* instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject
|
||||||
|
* methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a
|
||||||
|
* {@link Capability}).
|
||||||
|
*
|
||||||
|
* Currently the "generic peripheral" system is incompatible with normal peripherals. Normal {@link IPeripheralProvider}
|
||||||
|
* or {@link IPeripheral} implementations take priority. Tile entities which use this system are given a peripheral name
|
||||||
|
* determined by their id, rather than any peripheral provider. This will hopefully change in the future, once a suitable
|
||||||
|
* design has been established.
|
||||||
|
*
|
||||||
|
* For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link IItemHandler}s:
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* public class InventoryMethods implements GenericSource {
|
||||||
|
* \@LuaFunction( mainThread = true )
|
||||||
|
* public static int size(IItemHandler inventory) {
|
||||||
|
* return inventory.getSlots();
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // ...
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @see ComputerCraftAPI#registerGenericSource(GenericSource)
|
||||||
|
* @see ComputerCraftAPI#registerGenericCapability(Capability) New capabilities (those not built into Forge) must be
|
||||||
|
* explicitly given to the generic peripheral system, as there is no way to enumerate all capabilities.
|
||||||
|
*/
|
||||||
|
public interface GenericSource
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A unique identifier for this generic source.
|
||||||
|
*
|
||||||
|
* This is currently unused, but may be used in the future to allow disabling specific sources. It is recommended
|
||||||
|
* to return an identifier using your mod's ID.
|
||||||
|
*
|
||||||
|
* @return This source's identifier.
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
ResourceLocation id();
|
||||||
|
}
|
||||||
@@ -47,7 +47,10 @@ public class ComputerBorderRenderer
|
|||||||
private static final int CORNER_LEFT_X = BORDER;
|
private static final int CORNER_LEFT_X = BORDER;
|
||||||
private static final int CORNER_RIGHT_X = CORNER_LEFT_X + BORDER;
|
private static final int CORNER_RIGHT_X = CORNER_LEFT_X + BORDER;
|
||||||
private static final int BORDER_RIGHT_X = 36;
|
private static final int BORDER_RIGHT_X = 36;
|
||||||
private static final int GAP = 4;
|
private static final int LIGHT_BORDER_Y = 56;
|
||||||
|
private static final int LIGHT_CORNER_Y = 80;
|
||||||
|
|
||||||
|
public static final int LIGHT_HEIGHT = 8;
|
||||||
|
|
||||||
private static final float TEX_SCALE = 1 / 256.0f;
|
private static final float TEX_SCALE = 1 / 256.0f;
|
||||||
|
|
||||||
@@ -101,15 +104,15 @@ public class ComputerBorderRenderer
|
|||||||
|
|
||||||
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, float r, float g, float b )
|
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, float r, float g, float b )
|
||||||
{
|
{
|
||||||
render( transform, buffer, x, y, z, width, height, 0, r, g, b );
|
render( transform, buffer, x, y, z, width, height, false, r, g, b );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, int borderHeight, float r, float g, float b )
|
public static void render( Matrix4f transform, IVertexBuilder buffer, int x, int y, int z, int width, int height, boolean withLight, float r, float g, float b )
|
||||||
{
|
{
|
||||||
new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, borderHeight );
|
new ComputerBorderRenderer( transform, buffer, z, r, g, b ).doRender( x, y, width, height, withLight );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doRender( int x, int y, int width, int height, int bottomHeight )
|
public void doRender( int x, int y, int width, int height, boolean withLight )
|
||||||
{
|
{
|
||||||
int endX = x + width;
|
int endX = x + width;
|
||||||
int endY = y + height;
|
int endY = y + height;
|
||||||
@@ -125,28 +128,18 @@ public class ComputerBorderRenderer
|
|||||||
|
|
||||||
// Bottom bar. We allow for drawing a stretched version, which allows for additional elements (such as the
|
// Bottom bar. We allow for drawing a stretched version, which allows for additional elements (such as the
|
||||||
// pocket computer's lights).
|
// pocket computer's lights).
|
||||||
if( bottomHeight <= 0 )
|
if( withLight )
|
||||||
|
{
|
||||||
|
renderTexture( x, endY, 0, LIGHT_BORDER_Y, endX - x, BORDER + LIGHT_HEIGHT, BORDER, BORDER + LIGHT_HEIGHT );
|
||||||
|
renderTexture( x - BORDER, endY, CORNER_LEFT_X, LIGHT_CORNER_Y, BORDER, BORDER + LIGHT_HEIGHT );
|
||||||
|
renderTexture( endX, endY, CORNER_RIGHT_X, LIGHT_CORNER_Y, BORDER, BORDER + LIGHT_HEIGHT );
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
renderLine( x, endY, 0, BORDER, endX - x, BORDER );
|
renderLine( x, endY, 0, BORDER, endX - x, BORDER );
|
||||||
renderCorner( x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y );
|
renderCorner( x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y );
|
||||||
renderCorner( endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y );
|
renderCorner( endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Bottom left, middle, right. We do this in three portions: the top inner corners, an extended region for
|
|
||||||
// lights, and then the bottom outer corners.
|
|
||||||
renderTexture( x - BORDER, endY, CORNER_LEFT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2 );
|
|
||||||
renderTexture( x, endY, 0, BORDER, width, BORDER / 2, BORDER, BORDER / 2 );
|
|
||||||
renderTexture( endX, endY, CORNER_RIGHT_X, CORNER_BOTTOM_Y, BORDER, BORDER / 2 );
|
|
||||||
|
|
||||||
renderTexture( x - BORDER, endY + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP );
|
|
||||||
renderTexture( x, endY + BORDER / 2, 0, BORDER + GAP, width, bottomHeight, BORDER, GAP );
|
|
||||||
renderTexture( endX, endY + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + GAP, BORDER, bottomHeight, BORDER, GAP );
|
|
||||||
|
|
||||||
renderTexture( x - BORDER, endY + bottomHeight + BORDER / 2, CORNER_LEFT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2 );
|
|
||||||
renderTexture( x, endY + bottomHeight + BORDER / 2, 0, BORDER + BORDER / 2, width, BORDER / 2 );
|
|
||||||
renderTexture( endX, endY + bottomHeight + BORDER / 2, CORNER_RIGHT_X, CORNER_BOTTOM_Y + BORDER / 2, BORDER, BORDER / 2 );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderCorner( int x, int y, int u, int v )
|
private void renderCorner( int x, int y, int u, int v )
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ import org.lwjgl.opengl.GL11;
|
|||||||
|
|
||||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||||
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
|
import static dan200.computercraft.client.render.ComputerBorderRenderer.*;
|
||||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emulates map rendering for pocket computers.
|
* Emulates map rendering for pocket computers.
|
||||||
@@ -35,8 +34,6 @@ import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
|||||||
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
|
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
|
||||||
public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
||||||
{
|
{
|
||||||
private static final int LIGHT_HEIGHT = 8;
|
|
||||||
|
|
||||||
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
|
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
|
||||||
|
|
||||||
private ItemPocketRenderer()
|
private ItemPocketRenderer()
|
||||||
@@ -127,7 +124,7 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
|||||||
BufferBuilder buffer = tessellator.getBuilder();
|
BufferBuilder buffer = tessellator.getBuilder();
|
||||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
|
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR_TEX );
|
||||||
|
|
||||||
ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, LIGHT_HEIGHT, r, g, b );
|
ComputerBorderRenderer.render( transform, buffer, 0, 0, 0, width, height, true, r, g, b );
|
||||||
|
|
||||||
tessellator.end();
|
tessellator.end();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import dan200.computercraft.core.apis.http.*;
|
|||||||
import dan200.computercraft.core.apis.http.request.HttpRequest;
|
import dan200.computercraft.core.apis.http.request.HttpRequest;
|
||||||
import dan200.computercraft.core.apis.http.websocket.Websocket;
|
import dan200.computercraft.core.apis.http.websocket.Websocket;
|
||||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
import io.netty.handler.codec.http.HttpHeaders;
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpMethod;
|
import io.netty.handler.codec.http.HttpMethod;
|
||||||
|
|
||||||
@@ -179,7 +180,7 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private static HttpHeaders getHeaders( @Nonnull Map<?, ?> headerTable ) throws LuaException
|
private HttpHeaders getHeaders( @Nonnull Map<?, ?> headerTable ) throws LuaException
|
||||||
{
|
{
|
||||||
HttpHeaders headers = new DefaultHttpHeaders();
|
HttpHeaders headers = new DefaultHttpHeaders();
|
||||||
for( Map.Entry<?, ?> entry : headerTable.entrySet() )
|
for( Map.Entry<?, ?> entry : headerTable.entrySet() )
|
||||||
@@ -197,6 +198,11 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( !headers.contains( HttpHeaderNames.USER_AGENT ) )
|
||||||
|
{
|
||||||
|
headers.set( HttpHeaderNames.USER_AGENT, apiEnvironment.getComputerEnvironment().getUserAgent() );
|
||||||
|
}
|
||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ final class LuaDateTime
|
|||||||
formatter.appendValue( ChronoField.HOUR_OF_DAY, 2 );
|
formatter.appendValue( ChronoField.HOUR_OF_DAY, 2 );
|
||||||
break;
|
break;
|
||||||
case 'I':
|
case 'I':
|
||||||
formatter.appendValue( ChronoField.HOUR_OF_AMPM );
|
formatter.appendValue( ChronoField.HOUR_OF_AMPM, 2 );
|
||||||
break;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
formatter.appendValue( ChronoField.DAY_OF_YEAR, 3 );
|
formatter.appendValue( ChronoField.DAY_OF_YEAR, 3 );
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final int getBundledInput( ComputerSide side )
|
public final int getBundledInput( ComputerSide side )
|
||||||
{
|
{
|
||||||
return environment.getBundledOutput( side );
|
return environment.getBundledInput( side );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -80,10 +80,6 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
|
|||||||
{
|
{
|
||||||
request.headers().set( HttpHeaderNames.ACCEPT_CHARSET, "UTF-8" );
|
request.headers().set( HttpHeaderNames.ACCEPT_CHARSET, "UTF-8" );
|
||||||
}
|
}
|
||||||
if( !request.headers().contains( HttpHeaderNames.USER_AGENT ) )
|
|
||||||
{
|
|
||||||
request.headers().set( HttpHeaderNames.USER_AGENT, this.request.environment().getComputerEnvironment().getUserAgent() );
|
|
||||||
}
|
|
||||||
request.headers().set( HttpHeaderNames.HOST, uri.getPort() < 0 ? uri.getHost() : uri.getHost() + ":" + uri.getPort() );
|
request.headers().set( HttpHeaderNames.HOST, uri.getPort() < 0 ? uri.getHost() : uri.getHost() + ":" + uri.getPort() );
|
||||||
request.headers().set( HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE );
|
request.headers().set( HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE );
|
||||||
|
|
||||||
|
|||||||
@@ -58,10 +58,10 @@ public class HttpResponseHandle implements ObjectSource
|
|||||||
* If multiple headers are sent with the same name, they will be combined with a comma.
|
* If multiple headers are sent with the same name, they will be combined with a comma.
|
||||||
*
|
*
|
||||||
* @return The response's headers.
|
* @return The response's headers.
|
||||||
* @cc.usage Make a request to [example.computercraft.cc](https://example.computercraft.cc), and print the
|
* @cc.usage Make a request to [example.tweaked.cc](https://example.tweaked.cc), and print the
|
||||||
* returned headers.
|
* returned headers.
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* local request = http.get("https://example.computercraft.cc")
|
* local request = http.get("https://example.tweaked.cc")
|
||||||
* print(textutils.serialize(request.getResponseHeaders()))
|
* print(textutils.serialize(request.getResponseHeaders()))
|
||||||
* -- => {
|
* -- => {
|
||||||
* -- [ "Content-Type" ] = "text/plain; charset=utf8",
|
* -- [ "Content-Type" ] = "text/plain; charset=utf8",
|
||||||
|
|||||||
@@ -11,10 +11,7 @@ import com.google.common.cache.LoadingCache;
|
|||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
import com.google.common.reflect.TypeToken;
|
import com.google.common.reflect.TypeToken;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.lua.IArguments;
|
import dan200.computercraft.api.lua.*;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
|
||||||
import dan200.computercraft.api.lua.LuaFunction;
|
|
||||||
import dan200.computercraft.api.lua.MethodResult;
|
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
@@ -111,7 +108,7 @@ public final class Generator<T>
|
|||||||
addMethod( methods, method, annotation, instance );
|
addMethod( methods, method, annotation, instance );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( GenericSource.GenericMethod method : GenericSource.GenericMethod.all() )
|
for( GenericMethod method : GenericMethod.all() )
|
||||||
{
|
{
|
||||||
if( !method.target.isAssignableFrom( klass ) ) continue;
|
if( !method.target.isAssignableFrom( klass ) ) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* 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.core.asm;
|
||||||
|
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.lua.GenericSource;
|
||||||
|
import dan200.computercraft.api.lua.LuaFunction;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic method is a method belonging to a {@link GenericSource} with a known target.
|
||||||
|
*/
|
||||||
|
public class GenericMethod
|
||||||
|
{
|
||||||
|
final Method method;
|
||||||
|
final LuaFunction annotation;
|
||||||
|
final Class<?> target;
|
||||||
|
|
||||||
|
private static final List<GenericSource> sources = new ArrayList<>();
|
||||||
|
private static List<GenericMethod> cache;
|
||||||
|
|
||||||
|
GenericMethod( Method method, LuaFunction annotation, Class<?> target )
|
||||||
|
{
|
||||||
|
this.method = method;
|
||||||
|
this.annotation = annotation;
|
||||||
|
this.target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}.
|
||||||
|
*
|
||||||
|
* @return All available generic methods.
|
||||||
|
*/
|
||||||
|
static List<GenericMethod> all()
|
||||||
|
{
|
||||||
|
if( cache != null ) return cache;
|
||||||
|
return cache = sources.stream()
|
||||||
|
.flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) )
|
||||||
|
.map( method ->
|
||||||
|
{
|
||||||
|
LuaFunction annotation = method.getAnnotation( LuaFunction.class );
|
||||||
|
if( annotation == null ) return null;
|
||||||
|
|
||||||
|
if( !Modifier.isStatic( method.getModifiers() ) )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type[] types = method.getGenericParameterTypes();
|
||||||
|
if( types.length == 0 )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() );
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class<?> target = Reflect.getRawType( method, types[0], false );
|
||||||
|
if( target == null ) return null;
|
||||||
|
|
||||||
|
return new GenericMethod( method, annotation, target );
|
||||||
|
} )
|
||||||
|
.filter( Objects::nonNull )
|
||||||
|
.collect( Collectors.toList() );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static synchronized void register( @Nonnull GenericSource source )
|
||||||
|
{
|
||||||
|
Objects.requireNonNull( source, "Source cannot be null" );
|
||||||
|
|
||||||
|
if( cache != null )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache );
|
||||||
|
}
|
||||||
|
|
||||||
|
sources.add( source );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.core.asm;
|
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
|
||||||
import dan200.computercraft.api.lua.LuaFunction;
|
|
||||||
import dan200.computercraft.shared.peripheral.generic.GenericPeripheralProvider;
|
|
||||||
import dan200.computercraft.shared.util.ServiceUtil;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A generic source of {@link LuaMethod} functions. This allows for injecting methods onto objects you do not own.
|
|
||||||
*
|
|
||||||
* Unlike conventional Lua objects, the annotated methods should be {@code static}, with their target as the first
|
|
||||||
* parameter.
|
|
||||||
*
|
|
||||||
* This is used by the generic peripheral system ({@link GenericPeripheralProvider}) to provide methods for arbitrary
|
|
||||||
* tile entities. Eventually this'll be be exposed in the public API. Until it is stabilised, it will remain in this
|
|
||||||
* package - do not use it in external mods!
|
|
||||||
*/
|
|
||||||
public interface GenericSource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* A unique identifier for this generic source. This may be used in the future to allow disabling specific sources.
|
|
||||||
*
|
|
||||||
* @return This source's identifier.
|
|
||||||
*/
|
|
||||||
@Nonnull
|
|
||||||
ResourceLocation id();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a stream of generic sources.
|
|
||||||
*
|
|
||||||
* @param sources The source of generic methods.
|
|
||||||
* @see ServiceUtil For ways to load this. Sadly {@link java.util.ServiceLoader} is broken under Forge, but we don't
|
|
||||||
* want to add a hard-dep on Forge within core either.
|
|
||||||
*/
|
|
||||||
static void setup( Supplier<Stream<GenericSource>> sources )
|
|
||||||
{
|
|
||||||
GenericMethod.sources = sources;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A generic method is a method belonging to a {@link GenericSource} with a known target.
|
|
||||||
*/
|
|
||||||
class GenericMethod
|
|
||||||
{
|
|
||||||
final Method method;
|
|
||||||
final LuaFunction annotation;
|
|
||||||
final Class<?> target;
|
|
||||||
|
|
||||||
static Supplier<Stream<GenericSource>> sources;
|
|
||||||
private static List<GenericMethod> cache;
|
|
||||||
|
|
||||||
GenericMethod( Method method, LuaFunction annotation, Class<?> target )
|
|
||||||
{
|
|
||||||
this.method = method;
|
|
||||||
this.annotation = annotation;
|
|
||||||
this.target = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find all public static methods annotated with {@link LuaFunction} which belong to a {@link GenericSource}.
|
|
||||||
*
|
|
||||||
* @return All available generic methods.
|
|
||||||
*/
|
|
||||||
static List<GenericMethod> all()
|
|
||||||
{
|
|
||||||
if( cache != null ) return cache;
|
|
||||||
if( sources == null )
|
|
||||||
{
|
|
||||||
ComputerCraft.log.warn( "Getting GenericMethods without a provider" );
|
|
||||||
return cache = Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return cache = sources.get()
|
|
||||||
.flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) )
|
|
||||||
.map( method ->
|
|
||||||
{
|
|
||||||
LuaFunction annotation = method.getAnnotation( LuaFunction.class );
|
|
||||||
if( annotation == null ) return null;
|
|
||||||
|
|
||||||
if( !Modifier.isStatic( method.getModifiers() ) )
|
|
||||||
{
|
|
||||||
ComputerCraft.log.error( "GenericSource method {}.{} should be static.", method.getDeclaringClass(), method.getName() );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type[] types = method.getGenericParameterTypes();
|
|
||||||
if( types.length == 0 )
|
|
||||||
{
|
|
||||||
ComputerCraft.log.error( "GenericSource method {}.{} has no parameters.", method.getDeclaringClass(), method.getName() );
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<?> target = Reflect.getRawType( method, types[0], false );
|
|
||||||
if( target == null ) return null;
|
|
||||||
|
|
||||||
return new GenericMethod( method, annotation, target );
|
|
||||||
} )
|
|
||||||
.filter( Objects::nonNull )
|
|
||||||
.collect( Collectors.toList() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,6 +12,7 @@ import com.google.common.io.ByteStreams;
|
|||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.filesystem.IMount;
|
import dan200.computercraft.api.filesystem.IMount;
|
||||||
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
|
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
|
||||||
|
import dan200.computercraft.shared.util.IoUtil;
|
||||||
import net.minecraft.resources.IReloadableResourceManager;
|
import net.minecraft.resources.IReloadableResourceManager;
|
||||||
import net.minecraft.resources.IResource;
|
import net.minecraft.resources.IResource;
|
||||||
import net.minecraft.resources.IResourceManager;
|
import net.minecraft.resources.IResourceManager;
|
||||||
@@ -103,9 +104,13 @@ public final class ResourceMount implements IMount
|
|||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
boolean hasAny = false;
|
boolean hasAny = false;
|
||||||
|
String existingNamespace = null;
|
||||||
|
|
||||||
FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
|
FileEntry newRoot = new FileEntry( new ResourceLocation( namespace, subPath ) );
|
||||||
for( ResourceLocation file : manager.listResources( subPath, s -> true ) )
|
for( ResourceLocation file : manager.listResources( subPath, s -> true ) )
|
||||||
{
|
{
|
||||||
|
existingNamespace = file.getNamespace();
|
||||||
|
|
||||||
if( !file.getNamespace().equals( namespace ) ) continue;
|
if( !file.getNamespace().equals( namespace ) ) continue;
|
||||||
|
|
||||||
String localPath = FileSystem.toLocal( file.getPath(), subPath );
|
String localPath = FileSystem.toLocal( file.getPath(), subPath );
|
||||||
@@ -114,6 +119,15 @@ public final class ResourceMount implements IMount
|
|||||||
}
|
}
|
||||||
|
|
||||||
root = hasAny ? newRoot : null;
|
root = hasAny ? newRoot : null;
|
||||||
|
|
||||||
|
if( !hasAny )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.warn( "Cannot find any files under /data/{}/{} for resource mount.", namespace, subPath );
|
||||||
|
if( existingNamespace != null )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.warn( "There are files under /data/{}/{} though. Did you get the wrong namespace?", existingNamespace, subPath );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileEntry get( String path )
|
private FileEntry get( String path )
|
||||||
@@ -231,11 +245,20 @@ public final class ResourceMount implements IMount
|
|||||||
byte[] contents = CONTENTS_CACHE.getIfPresent( file );
|
byte[] contents = CONTENTS_CACHE.getIfPresent( file );
|
||||||
if( contents != null ) return new ArrayByteChannel( contents );
|
if( contents != null ) return new ArrayByteChannel( contents );
|
||||||
|
|
||||||
try( InputStream stream = manager.getResource( file.identifier ).getInputStream() )
|
try
|
||||||
{
|
{
|
||||||
|
InputStream stream = manager.getResource( file.identifier ).getInputStream();
|
||||||
if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream );
|
if( stream.available() > MAX_CACHED_SIZE ) return Channels.newChannel( stream );
|
||||||
|
|
||||||
contents = ByteStreams.toByteArray( stream );
|
try
|
||||||
|
{
|
||||||
|
contents = ByteStreams.toByteArray( stream );
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IoUtil.closeQuietly( stream );
|
||||||
|
}
|
||||||
|
|
||||||
CONTENTS_CACHE.put( file, contents );
|
CONTENTS_CACHE.put( file, contents );
|
||||||
return new ArrayByteChannel( contents );
|
return new ArrayByteChannel( contents );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,46 +12,12 @@ public class TextBuffer
|
|||||||
public TextBuffer( char c, int length )
|
public TextBuffer( char c, int length )
|
||||||
{
|
{
|
||||||
text = new char[length];
|
text = new char[length];
|
||||||
for( int i = 0; i < length; i++ )
|
this.fill( c );
|
||||||
{
|
|
||||||
text[i] = c;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TextBuffer( String text )
|
public TextBuffer( String text )
|
||||||
{
|
{
|
||||||
this( text, 1 );
|
this.text = text.toCharArray();
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer( String text, int repetitions )
|
|
||||||
{
|
|
||||||
int textLength = text.length();
|
|
||||||
this.text = new char[textLength * repetitions];
|
|
||||||
for( int i = 0; i < repetitions; i++ )
|
|
||||||
{
|
|
||||||
for( int j = 0; j < textLength; j++ )
|
|
||||||
{
|
|
||||||
this.text[j + i * textLength] = text.charAt( j );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer( TextBuffer text )
|
|
||||||
{
|
|
||||||
this( text, 1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
public TextBuffer( TextBuffer text, int repetitions )
|
|
||||||
{
|
|
||||||
int textLength = text.length();
|
|
||||||
this.text = new char[textLength * repetitions];
|
|
||||||
for( int i = 0; i < repetitions; i++ )
|
|
||||||
{
|
|
||||||
for( int j = 0; j < textLength; j++ )
|
|
||||||
{
|
|
||||||
this.text[j + i * textLength] = text.charAt( j );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int length()
|
public int length()
|
||||||
@@ -59,39 +25,16 @@ public class TextBuffer
|
|||||||
return text.length;
|
return text.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String read()
|
|
||||||
{
|
|
||||||
return read( 0, text.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String read( int start )
|
|
||||||
{
|
|
||||||
return read( start, text.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public String read( int start, int end )
|
|
||||||
{
|
|
||||||
start = Math.max( start, 0 );
|
|
||||||
end = Math.min( end, text.length );
|
|
||||||
int textLength = Math.max( end - start, 0 );
|
|
||||||
return new String( text, start, textLength );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write( String text )
|
public void write( String text )
|
||||||
{
|
{
|
||||||
write( text, 0, text.length() );
|
write( text, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write( String text, int start )
|
public void write( String text, int start )
|
||||||
{
|
|
||||||
write( text, start, start + text.length() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write( String text, int start, int end )
|
|
||||||
{
|
{
|
||||||
int pos = start;
|
int pos = start;
|
||||||
start = Math.max( start, 0 );
|
start = Math.max( start, 0 );
|
||||||
end = Math.min( end, pos + text.length() );
|
int end = Math.min( start + text.length(), pos + text.length() );
|
||||||
end = Math.min( end, this.text.length );
|
end = Math.min( end, this.text.length );
|
||||||
for( int i = start; i < end; i++ )
|
for( int i = start; i < end; i++ )
|
||||||
{
|
{
|
||||||
@@ -101,23 +44,10 @@ public class TextBuffer
|
|||||||
|
|
||||||
public void write( TextBuffer text )
|
public void write( TextBuffer text )
|
||||||
{
|
{
|
||||||
write( text, 0, text.length() );
|
int end = Math.min( text.length(), this.text.length );
|
||||||
}
|
for( int i = 0; i < end; i++ )
|
||||||
|
|
||||||
public void write( TextBuffer text, int start )
|
|
||||||
{
|
|
||||||
write( text, start, start + text.length() );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write( TextBuffer text, int start, int end )
|
|
||||||
{
|
|
||||||
int pos = start;
|
|
||||||
start = Math.max( start, 0 );
|
|
||||||
end = Math.min( end, pos + text.length() );
|
|
||||||
end = Math.min( end, this.text.length );
|
|
||||||
for( int i = start; i < end; i++ )
|
|
||||||
{
|
{
|
||||||
this.text[i] = text.charAt( i - pos );
|
this.text[i] = text.charAt( i );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,11 +56,6 @@ public class TextBuffer
|
|||||||
fill( c, 0, text.length );
|
fill( c, 0, text.length );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fill( char c, int start )
|
|
||||||
{
|
|
||||||
fill( c, start, text.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( char c, int start, int end )
|
public void fill( char c, int start, int end )
|
||||||
{
|
{
|
||||||
start = Math.max( start, 0 );
|
start = Math.max( start, 0 );
|
||||||
@@ -141,52 +66,6 @@ public class TextBuffer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fill( String text )
|
|
||||||
{
|
|
||||||
fill( text, 0, this.text.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( String text, int start )
|
|
||||||
{
|
|
||||||
fill( text, start, this.text.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( String text, int start, int end )
|
|
||||||
{
|
|
||||||
int pos = start;
|
|
||||||
start = Math.max( start, 0 );
|
|
||||||
end = Math.min( end, this.text.length );
|
|
||||||
|
|
||||||
int textLength = text.length();
|
|
||||||
for( int i = start; i < end; i++ )
|
|
||||||
{
|
|
||||||
this.text[i] = text.charAt( (i - pos) % textLength );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( TextBuffer text )
|
|
||||||
{
|
|
||||||
fill( text, 0, this.text.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( TextBuffer text, int start )
|
|
||||||
{
|
|
||||||
fill( text, start, this.text.length );
|
|
||||||
}
|
|
||||||
|
|
||||||
public void fill( TextBuffer text, int start, int end )
|
|
||||||
{
|
|
||||||
int pos = start;
|
|
||||||
start = Math.max( start, 0 );
|
|
||||||
end = Math.min( end, this.text.length );
|
|
||||||
|
|
||||||
int textLength = text.length();
|
|
||||||
for( int i = start; i < end; i++ )
|
|
||||||
{
|
|
||||||
this.text[i] = text.charAt( (i - pos) % textLength );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public char charAt( int i )
|
public char charAt( int i )
|
||||||
{
|
{
|
||||||
return text[i];
|
return text[i];
|
||||||
|
|||||||
@@ -21,14 +21,12 @@ import javax.annotation.Nonnull;
|
|||||||
|
|
||||||
public class BlockModelProvider extends BlockStateProvider
|
public class BlockModelProvider extends BlockStateProvider
|
||||||
{
|
{
|
||||||
private final ModelFile monitorBase;
|
private ModelFile monitorBase;
|
||||||
private final ModelFile orientable;
|
private ModelFile orientable;
|
||||||
|
|
||||||
public BlockModelProvider( DataGenerator generator, ExistingFileHelper existingFileHelper )
|
public BlockModelProvider( DataGenerator generator, ExistingFileHelper existingFileHelper )
|
||||||
{
|
{
|
||||||
super( generator, ComputerCraft.MOD_ID, existingFileHelper );
|
super( generator, ComputerCraft.MOD_ID, existingFileHelper );
|
||||||
monitorBase = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) );
|
|
||||||
orientable = models().getExistingFile( new ResourceLocation( "block/orientable" ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@@ -41,6 +39,9 @@ public class BlockModelProvider extends BlockStateProvider
|
|||||||
@Override
|
@Override
|
||||||
protected void registerStatesAndModels()
|
protected void registerStatesAndModels()
|
||||||
{
|
{
|
||||||
|
monitorBase = models().getExistingFile( new ResourceLocation( ComputerCraft.MOD_ID, "block/monitor_base" ) );
|
||||||
|
orientable = models().getExistingFile( new ResourceLocation( "block/orientable" ) );
|
||||||
|
|
||||||
registerMonitors( Registry.ModBlocks.MONITOR_NORMAL.get() );
|
registerMonitors( Registry.ModBlocks.MONITOR_NORMAL.get() );
|
||||||
registerMonitors( Registry.ModBlocks.MONITOR_ADVANCED.get() );
|
registerMonitors( Registry.ModBlocks.MONITOR_ADVANCED.get() );
|
||||||
|
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ public final class Registry
|
|||||||
{
|
{
|
||||||
// Upgrades
|
// Upgrades
|
||||||
ComputerCraft.TurtleUpgrades.wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) );
|
ComputerCraft.TurtleUpgrades.wirelessModemNormal = new TurtleModem( false, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_normal" ) );
|
||||||
TurtleUpgrades.register( ComputerCraft.TurtleUpgrades.wirelessModemNormal );
|
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemNormal );
|
||||||
|
|
||||||
ComputerCraft.TurtleUpgrades.wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) );
|
ComputerCraft.TurtleUpgrades.wirelessModemAdvanced = new TurtleModem( true, new ResourceLocation( ComputerCraft.MOD_ID, "wireless_modem_advanced" ) );
|
||||||
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced );
|
ComputerCraftAPI.registerTurtleUpgrade( ComputerCraft.TurtleUpgrades.wirelessModemAdvanced );
|
||||||
|
|||||||
@@ -79,7 +79,10 @@ public final class ColourableRecipe extends SpecialRecipe
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( colourable.isEmpty() ) return ItemStack.EMPTY;
|
if( colourable.isEmpty() ) return ItemStack.EMPTY;
|
||||||
return ((IColouredItem) colourable.getItem()).withColour( colourable, tracker.getColour() );
|
|
||||||
|
ItemStack stack = ((IColouredItem) colourable.getItem()).withColour( colourable, tracker.getColour() );
|
||||||
|
stack.setCount( 1 );
|
||||||
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -114,10 +114,10 @@ public class JEIComputerCraft implements IModPlugin
|
|||||||
*/
|
*/
|
||||||
private static final ISubtypeInterpreter turtleSubtype = stack -> {
|
private static final ISubtypeInterpreter turtleSubtype = stack -> {
|
||||||
Item item = stack.getItem();
|
Item item = stack.getItem();
|
||||||
if( !(item instanceof ITurtleItem) ) return "";
|
if( !(item instanceof ITurtleItem) ) return ISubtypeInterpreter.NONE;
|
||||||
|
|
||||||
ITurtleItem turtle = (ITurtleItem) item;
|
ITurtleItem turtle = (ITurtleItem) item;
|
||||||
StringBuilder name = new StringBuilder();
|
StringBuilder name = new StringBuilder( "turtle:" );
|
||||||
|
|
||||||
// Add left and right upgrades to the identifier
|
// Add left and right upgrades to the identifier
|
||||||
ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.LEFT );
|
ITurtleUpgrade left = turtle.getUpgrade( stack, TurtleSide.LEFT );
|
||||||
@@ -134,9 +134,9 @@ public class JEIComputerCraft implements IModPlugin
|
|||||||
*/
|
*/
|
||||||
private static final ISubtypeInterpreter pocketSubtype = stack -> {
|
private static final ISubtypeInterpreter pocketSubtype = stack -> {
|
||||||
Item item = stack.getItem();
|
Item item = stack.getItem();
|
||||||
if( !(item instanceof ItemPocketComputer) ) return "";
|
if( !(item instanceof ItemPocketComputer) ) return ISubtypeInterpreter.NONE;
|
||||||
|
|
||||||
StringBuilder name = new StringBuilder();
|
StringBuilder name = new StringBuilder( "pocket:" );
|
||||||
|
|
||||||
// Add the upgrade to the identifier
|
// Add the upgrade to the identifier
|
||||||
IPocketUpgrade upgrade = ItemPocketComputer.getUpgrade( stack );
|
IPocketUpgrade upgrade = ItemPocketComputer.getUpgrade( stack );
|
||||||
@@ -150,11 +150,11 @@ public class JEIComputerCraft implements IModPlugin
|
|||||||
*/
|
*/
|
||||||
private static final ISubtypeInterpreter diskSubtype = stack -> {
|
private static final ISubtypeInterpreter diskSubtype = stack -> {
|
||||||
Item item = stack.getItem();
|
Item item = stack.getItem();
|
||||||
if( !(item instanceof ItemDisk) ) return "";
|
if( !(item instanceof ItemDisk) ) return ISubtypeInterpreter.NONE;
|
||||||
|
|
||||||
ItemDisk disk = (ItemDisk) item;
|
ItemDisk disk = (ItemDisk) item;
|
||||||
|
|
||||||
int colour = disk.getColour( stack );
|
int colour = disk.getColour( stack );
|
||||||
return colour == -1 ? "" : String.format( "%06x", colour );
|
return colour == -1 ? ISubtypeInterpreter.NONE : String.format( "%06x", colour );
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ class RecipeResolver implements IRecipeManagerPlugin
|
|||||||
for( UpgradeInfo upgrade : upgrades )
|
for( UpgradeInfo upgrade : upgrades )
|
||||||
{
|
{
|
||||||
ItemStack craftingStack = upgrade.stack;
|
ItemStack craftingStack = upgrade.stack;
|
||||||
if( !craftingStack.isEmpty() && craftingStack.getItem() == stack.getItem() && upgrade.upgrade.isItemSuitable( stack ) )
|
if( craftingStack.isEmpty() || craftingStack.getItem() != stack.getItem() || !upgrade.upgrade.isItemSuitable( stack ) )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -319,13 +319,6 @@ class RecipeResolver implements IRecipeManagerPlugin
|
|||||||
super( ID, null, width, height, input, output );
|
super( ID, null, width, height, input, output );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public ResourceLocation getId()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public IRecipeSerializer<?> getSerializer()
|
public IRecipeSerializer<?> getSerializer()
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public final class RecordMedia implements IMedia
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return ObfuscationReflectionHelper.getPrivateValue( MusicDiscItem.class, (MusicDiscItem) item, "sound" );
|
return ObfuscationReflectionHelper.getPrivateValue( MusicDiscItem.class, (MusicDiscItem) item, "field_185076_b" );
|
||||||
}
|
}
|
||||||
catch( UnableToAccessFieldException | UnableToFindFieldException e )
|
catch( UnableToAccessFieldException | UnableToFindFieldException e )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,22 +15,22 @@ import net.minecraft.world.World;
|
|||||||
import net.minecraftforge.common.capabilities.Capability;
|
import net.minecraftforge.common.capabilities.Capability;
|
||||||
import net.minecraftforge.common.util.LazyOptional;
|
import net.minecraftforge.common.util.LazyOptional;
|
||||||
import net.minecraftforge.common.util.NonNullConsumer;
|
import net.minecraftforge.common.util.NonNullConsumer;
|
||||||
import net.minecraftforge.energy.CapabilityEnergy;
|
|
||||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
|
||||||
import net.minecraftforge.items.CapabilityItemHandler;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class GenericPeripheralProvider
|
public class GenericPeripheralProvider
|
||||||
{
|
{
|
||||||
private static final Capability<?>[] CAPABILITIES = new Capability<?>[] {
|
private static final ArrayList<Capability<?>> capabilities = new ArrayList<>();
|
||||||
CapabilityItemHandler.ITEM_HANDLER_CAPABILITY,
|
|
||||||
CapabilityEnergy.ENERGY,
|
public static synchronized void addCapability( Capability<?> capability )
|
||||||
CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY,
|
{
|
||||||
};
|
Objects.requireNonNull( capability, "Capability cannot be null" );
|
||||||
|
if( !capabilities.contains( capability ) ) capabilities.add( capability );
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate )
|
public static IPeripheral getPeripheral( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side, NonNullConsumer<LazyOptional<IPeripheral>> invalidate )
|
||||||
@@ -43,7 +43,7 @@ public class GenericPeripheralProvider
|
|||||||
List<NamedMethod<PeripheralMethod>> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() );
|
List<NamedMethod<PeripheralMethod>> tileMethods = PeripheralMethod.GENERATOR.getMethods( tile.getClass() );
|
||||||
if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods );
|
if( !tileMethods.isEmpty() ) addSaturated( saturated, tile, tileMethods );
|
||||||
|
|
||||||
for( Capability<?> capability : CAPABILITIES )
|
for( Capability<?> capability : capabilities )
|
||||||
{
|
{
|
||||||
LazyOptional<?> wrapper = tile.getCapability( capability );
|
LazyOptional<?> wrapper = tile.getCapability( capability );
|
||||||
wrapper.ifPresent( contents -> {
|
wrapper.ifPresent( contents -> {
|
||||||
|
|||||||
@@ -5,12 +5,11 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
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.core.asm.GenericSource;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraftforge.energy.IEnergyStorage;
|
import net.minecraftforge.energy.IEnergyStorage;
|
||||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@@ -26,14 +25,13 @@ import javax.annotation.Nonnull;
|
|||||||
*
|
*
|
||||||
* @cc.module energy_storage
|
* @cc.module energy_storage
|
||||||
*/
|
*/
|
||||||
@AutoService( GenericSource.class )
|
|
||||||
public class EnergyMethods implements GenericSource
|
public class EnergyMethods implements GenericSource
|
||||||
{
|
{
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation id()
|
public ResourceLocation id()
|
||||||
{
|
{
|
||||||
return new ResourceLocation( ForgeVersion.MOD_ID, "energy" );
|
return new ResourceLocation( ComputerCraft.MOD_ID, "energy" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
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.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.asm.GenericSource;
|
|
||||||
import dan200.computercraft.shared.peripheral.generic.data.FluidData;
|
import dan200.computercraft.shared.peripheral.generic.data.FluidData;
|
||||||
import net.minecraft.fluid.Fluid;
|
import net.minecraft.fluid.Fluid;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
@@ -20,7 +20,6 @@ import net.minecraftforge.fluids.FluidStack;
|
|||||||
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler;
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
import net.minecraftforge.registries.ForgeRegistries;
|
import net.minecraftforge.registries.ForgeRegistries;
|
||||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -35,16 +34,28 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
|
|||||||
*
|
*
|
||||||
* @cc.module fluid_storage
|
* @cc.module fluid_storage
|
||||||
*/
|
*/
|
||||||
@AutoService( GenericSource.class )
|
|
||||||
public class FluidMethods implements GenericSource
|
public class FluidMethods implements GenericSource
|
||||||
{
|
{
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation id()
|
public ResourceLocation id()
|
||||||
{
|
{
|
||||||
return new ResourceLocation( ForgeVersion.MOD_ID, "fluid" );
|
return new ResourceLocation( ComputerCraft.MOD_ID, "fluid" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all "tanks" in this fluid storage.
|
||||||
|
*
|
||||||
|
* Each tank either contains some amount of fluid or is empty. Tanks with fluids inside will return some basic
|
||||||
|
* information about the fluid, including its name and amount.
|
||||||
|
*
|
||||||
|
* The returned table is sparse, and so empty tanks will be `nil` - it is recommended to loop over using `pairs`
|
||||||
|
* rather than `ipairs`.
|
||||||
|
*
|
||||||
|
* @param fluids The current fluid handler.
|
||||||
|
* @return All tanks.
|
||||||
|
* @cc.treturn { (table|nil)... } All tanks in this fluid storage.
|
||||||
|
*/
|
||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static Map<Integer, Map<String, ?>> tanks( IFluidHandler fluids )
|
public static Map<Integer, Map<String, ?>> tanks( IFluidHandler fluids )
|
||||||
{
|
{
|
||||||
@@ -59,6 +70,22 @@ public class FluidMethods implements GenericSource
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a fluid from one fluid container to another connected one.
|
||||||
|
*
|
||||||
|
* This allows you to pull fluid in the current fluid container to another container <em>on the same wired
|
||||||
|
* network</em>. Both containers must attached to wired modems which are connected via a cable.
|
||||||
|
*
|
||||||
|
* @param from Container to move fluid from.
|
||||||
|
* @param computer The current computer.
|
||||||
|
* @param toName The name of the peripheral/container to push to. This is the string given to @{peripheral.wrap},
|
||||||
|
* and displayed by the wired modem.
|
||||||
|
* @param limit The maximum amount of fluid to move.
|
||||||
|
* @param fluidName The fluid to move. If not given, an arbitrary fluid will be chosen.
|
||||||
|
* @return The amount of moved fluid.
|
||||||
|
* @throws LuaException If the peripheral to transfer to doesn't exist or isn't an fluid container.
|
||||||
|
* @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
|
||||||
|
*/
|
||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static int pushFluid(
|
public static int pushFluid(
|
||||||
IFluidHandler from, IComputerAccess computer,
|
IFluidHandler from, IComputerAccess computer,
|
||||||
@@ -84,6 +111,22 @@ public class FluidMethods implements GenericSource
|
|||||||
: moveFluid( from, new FluidStack( fluid, actualLimit ), to );
|
: moveFluid( from, new FluidStack( fluid, actualLimit ), to );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move a fluid from a connected fluid container into this oneone.
|
||||||
|
*
|
||||||
|
* This allows you to pull fluid in the current fluid container from another container <em>on the same wired
|
||||||
|
* network</em>. Both containers must attached to wired modems which are connected via a cable.
|
||||||
|
*
|
||||||
|
* @param to Container to move fluid to.
|
||||||
|
* @param computer The current computer.
|
||||||
|
* @param fromName The name of the peripheral/container to push to. This is the string given to @{peripheral.wrap},
|
||||||
|
* and displayed by the wired modem.
|
||||||
|
* @param limit The maximum amount of fluid to move.
|
||||||
|
* @param fluidName The fluid to move. If not given, an arbitrary fluid will be chosen.
|
||||||
|
* @return The amount of moved fluid.
|
||||||
|
* @throws LuaException If the peripheral to transfer to doesn't exist or isn't an fluid container.
|
||||||
|
* @cc.see peripheral.getName Allows you to get the name of a @{peripheral.wrap|wrapped} peripheral.
|
||||||
|
*/
|
||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static int pullFluid(
|
public static int pullFluid(
|
||||||
IFluidHandler to, IComputerAccess computer,
|
IFluidHandler to, IComputerAccess computer,
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.peripheral.generic.methods;
|
package dan200.computercraft.shared.peripheral.generic.methods;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
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.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.core.asm.GenericSource;
|
|
||||||
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
||||||
import net.minecraft.inventory.IInventory;
|
import net.minecraft.inventory.IInventory;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
@@ -21,7 +21,6 @@ import net.minecraftforge.items.CapabilityItemHandler;
|
|||||||
import net.minecraftforge.items.IItemHandler;
|
import net.minecraftforge.items.IItemHandler;
|
||||||
import net.minecraftforge.items.ItemHandlerHelper;
|
import net.minecraftforge.items.ItemHandlerHelper;
|
||||||
import net.minecraftforge.items.wrapper.InvWrapper;
|
import net.minecraftforge.items.wrapper.InvWrapper;
|
||||||
import net.minecraftforge.versions.forge.ForgeVersion;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -36,14 +35,13 @@ import static dan200.computercraft.shared.peripheral.generic.methods.ArgumentHel
|
|||||||
*
|
*
|
||||||
* @cc.module inventory
|
* @cc.module inventory
|
||||||
*/
|
*/
|
||||||
@AutoService( GenericSource.class )
|
|
||||||
public class InventoryMethods implements GenericSource
|
public class InventoryMethods implements GenericSource
|
||||||
{
|
{
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation id()
|
public ResourceLocation id()
|
||||||
{
|
{
|
||||||
return new ResourceLocation( ForgeVersion.MOD_ID, "inventory" );
|
return new ResourceLocation( ComputerCraft.MOD_ID, "inventory" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,14 +61,23 @@ public class InventoryMethods implements GenericSource
|
|||||||
*
|
*
|
||||||
* Each item in the inventory is represented by a table containing some basic information, much like
|
* Each item in the inventory is represented by a table containing some basic information, much like
|
||||||
* {@link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail} includes. More information can be fetched
|
* {@link dan200.computercraft.shared.turtle.apis.TurtleAPI#getItemDetail} includes. More information can be fetched
|
||||||
* with {@link #getItemDetail}.
|
* with {@link #getItemDetail}. The table contains the item `name`, the `count` and an a (potentially nil) hash of
|
||||||
|
* the item's `nbt.` This NBT data doesn't contain anything useful, but allows you to distinguish identical items.
|
||||||
*
|
*
|
||||||
* The table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs` rather than
|
* The returned table is sparse, and so empty slots will be `nil` - it is recommended to loop over using `pairs`
|
||||||
* `ipairs`.
|
* rather than `ipairs`.
|
||||||
*
|
*
|
||||||
* @param inventory The current inventory.
|
* @param inventory The current inventory.
|
||||||
* @return All items in this inventory.
|
* @return All items in this inventory.
|
||||||
* @cc.treturn { (table|nil)... } All items in this inventory.
|
* @cc.treturn { (table|nil)... } All items in this inventory.
|
||||||
|
* @cc.usage Find an adjacent chest and print all items in it.
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* local chest = peripheral.find("minecraft:chest")
|
||||||
|
* for slot, item in pairs(chest.list()) do
|
||||||
|
* print(("%d x %s in slot %d"):format(item.count, item.name, slot))
|
||||||
|
* end
|
||||||
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
public static Map<Integer, Map<String, ?>> list( IItemHandler inventory )
|
public static Map<Integer, Map<String, ?>> list( IItemHandler inventory )
|
||||||
@@ -89,11 +96,32 @@ public class InventoryMethods implements GenericSource
|
|||||||
/**
|
/**
|
||||||
* Get detailed information about an item.
|
* Get detailed information about an item.
|
||||||
*
|
*
|
||||||
|
* The returned information contains the same information as each item in
|
||||||
|
* {@link #list}, as well as additional details like the display name
|
||||||
|
* (`displayName`) and item durability (`damage`, `maxDamage`, `durability`).
|
||||||
|
*
|
||||||
|
* Some items include more information (such as enchantments) - it is
|
||||||
|
* recommended to print it out using @{textutils.serialize} or in the Lua
|
||||||
|
* REPL, to explore what is available.
|
||||||
|
*
|
||||||
* @param inventory The current inventory.
|
* @param inventory The current inventory.
|
||||||
* @param slot The slot to get information about.
|
* @param slot The slot to get information about.
|
||||||
* @return Information about the item in this slot, or {@code nil} if not present.
|
* @return Information about the item in this slot, or {@code nil} if not present.
|
||||||
* @throws LuaException If the slot is out of range.
|
* @throws LuaException If the slot is out of range.
|
||||||
* @cc.treturn table Information about the item in this slot, or {@code nil} if not present.
|
* @cc.treturn table Information about the item in this slot, or {@code nil} if not present.
|
||||||
|
* @cc.usage Print some information about the first in a chest.
|
||||||
|
*
|
||||||
|
* <pre>{@code
|
||||||
|
* local chest = peripheral.find("minecraft:chest")
|
||||||
|
* local item = chest.getItemDetail(1)
|
||||||
|
* if not item then print("No item") return end
|
||||||
|
*
|
||||||
|
* print(("%s (%s)"):format(item.displayName, item.name))
|
||||||
|
* print(("Count: %d/%d"):format(item.count, item.maxCount))
|
||||||
|
* if item.damage then
|
||||||
|
* print(("Damage: %d/%d"):format(item.damage, item.maxDamage))
|
||||||
|
* end
|
||||||
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
@LuaFunction( mainThread = true )
|
@LuaFunction( mainThread = true )
|
||||||
@@ -105,6 +133,33 @@ public class InventoryMethods implements GenericSource
|
|||||||
return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack );
|
return stack.isEmpty() ? null : ItemData.fill( new HashMap<>(), stack );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum number of items which can be stored in this slot.
|
||||||
|
*
|
||||||
|
* Typically this will be limited to 64 items. However, some inventories (such as barrels or caches) can store
|
||||||
|
* hundreds or thousands of items in one slot.
|
||||||
|
*
|
||||||
|
* @param inventory Inventory to probe.
|
||||||
|
* @param slot The slot
|
||||||
|
* @return The maximum number of items in this slot.
|
||||||
|
* @throws LuaException If the slot is out of range.
|
||||||
|
* @cc.usage Count the maximum number of items an adjacent chest can hold.
|
||||||
|
* <pre>{@code
|
||||||
|
* local chest = peripheral.find("minecraft:chest")
|
||||||
|
* local total = 0
|
||||||
|
* for i = 1, chest.size() do
|
||||||
|
* total = total + chest.getItemLimit(i)
|
||||||
|
* end
|
||||||
|
* print(total)
|
||||||
|
* }</pre>
|
||||||
|
*/
|
||||||
|
@LuaFunction( mainThread = true )
|
||||||
|
public static int getItemLimit( IItemHandler inventory, int slot ) throws LuaException
|
||||||
|
{
|
||||||
|
assertBetween( slot, 1, inventory.getSlots(), "Slot out of range (%s)" );
|
||||||
|
return inventory.getSlotLimit( slot );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push items from one inventory to another connected one.
|
* Push items from one inventory to another connected one.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import net.minecraft.tileentity.TileEntityType;
|
|||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
import net.minecraftforge.fml.RegistryObject;
|
import net.minecraftforge.fml.RegistryObject;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@@ -85,9 +86,14 @@ public class BlockMonitor extends BlockGeneric
|
|||||||
if( entity instanceof TileMonitor && !world.isClientSide )
|
if( entity instanceof TileMonitor && !world.isClientSide )
|
||||||
{
|
{
|
||||||
TileMonitor monitor = (TileMonitor) entity;
|
TileMonitor monitor = (TileMonitor) entity;
|
||||||
monitor.contractNeighbours();
|
// Defer the block update if we're being placed by another TE. See #691
|
||||||
monitor.contract();
|
if ( livingEntity == null || livingEntity instanceof FakePlayer )
|
||||||
monitor.expand();
|
{
|
||||||
|
monitor.updateNeighborsDeferred();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monitor.updateNeighbors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import dan200.computercraft.ComputerCraft;
|
|||||||
import dan200.computercraft.shared.network.NetworkHandler;
|
import dan200.computercraft.shared.network.NetworkHandler;
|
||||||
import dan200.computercraft.shared.network.client.MonitorClientMessage;
|
import dan200.computercraft.shared.network.client.MonitorClientMessage;
|
||||||
import dan200.computercraft.shared.network.client.TerminalState;
|
import dan200.computercraft.shared.network.client.TerminalState;
|
||||||
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.ChunkPos;
|
import net.minecraft.util.math.ChunkPos;
|
||||||
@@ -28,6 +29,7 @@ import java.util.Queue;
|
|||||||
public final class MonitorWatcher
|
public final class MonitorWatcher
|
||||||
{
|
{
|
||||||
private static final Queue<TileMonitor> watching = new ArrayDeque<>();
|
private static final Queue<TileMonitor> watching = new ArrayDeque<>();
|
||||||
|
private static final Queue<PlayerUpdate> playerUpdates = new ArrayDeque<>();
|
||||||
|
|
||||||
private MonitorWatcher()
|
private MonitorWatcher()
|
||||||
{
|
{
|
||||||
@@ -58,10 +60,8 @@ public final class MonitorWatcher
|
|||||||
ServerMonitor serverMonitor = getMonitor( monitor );
|
ServerMonitor serverMonitor = getMonitor( monitor );
|
||||||
if( serverMonitor == null || monitor.enqueued ) continue;
|
if( serverMonitor == null || monitor.enqueued ) continue;
|
||||||
|
|
||||||
// We use the cached terminal state if available - this is guaranteed to
|
// The chunk hasn't been sent to the client yet, so we can't send an update. Do it on tick end.
|
||||||
TerminalState state = monitor.cached;
|
playerUpdates.add( new PlayerUpdate( event.getPlayer(), monitor ) );
|
||||||
if( state == null ) state = monitor.cached = serverMonitor.write();
|
|
||||||
NetworkHandler.sendToPlayer( event.getPlayer(), new MonitorClientMessage( monitor.getBlockPos(), state ) );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,6 +70,23 @@ public final class MonitorWatcher
|
|||||||
{
|
{
|
||||||
if( event.phase != TickEvent.Phase.END ) return;
|
if( event.phase != TickEvent.Phase.END ) return;
|
||||||
|
|
||||||
|
PlayerUpdate playerUpdate;
|
||||||
|
while( (playerUpdate = playerUpdates.poll()) != null )
|
||||||
|
{
|
||||||
|
TileMonitor tile = playerUpdate.monitor;
|
||||||
|
if( tile.enqueued || tile.isRemoved() ) continue;
|
||||||
|
|
||||||
|
ServerMonitor monitor = getMonitor( tile );
|
||||||
|
if( monitor == null ) continue;
|
||||||
|
|
||||||
|
// Some basic sanity checks to the player. It's possible they're no longer within range, but that's harder
|
||||||
|
// to track efficiently.
|
||||||
|
ServerPlayerEntity player = playerUpdate.player;
|
||||||
|
if( !player.isAlive() || player.getLevel() != tile.getLevel() ) continue;
|
||||||
|
|
||||||
|
NetworkHandler.sendToPlayer( playerUpdate.player, new MonitorClientMessage( tile.getBlockPos(), getState( tile, monitor ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
long limit = ComputerCraft.monitorBandwidth;
|
long limit = ComputerCraft.monitorBandwidth;
|
||||||
boolean obeyLimit = limit > 0;
|
boolean obeyLimit = limit > 0;
|
||||||
|
|
||||||
@@ -90,7 +107,7 @@ public final class MonitorWatcher
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminalState state = tile.cached = monitor.write();
|
TerminalState state = getState( tile, monitor );
|
||||||
NetworkHandler.sendToAllTracking( new MonitorClientMessage( pos, state ), chunk );
|
NetworkHandler.sendToAllTracking( new MonitorClientMessage( pos, state ), chunk );
|
||||||
|
|
||||||
limit -= state.size();
|
limit -= state.size();
|
||||||
@@ -101,4 +118,23 @@ public final class MonitorWatcher
|
|||||||
{
|
{
|
||||||
return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null;
|
return !monitor.isRemoved() && monitor.getXIndex() == 0 && monitor.getYIndex() == 0 ? monitor.getCachedServerMonitor() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static TerminalState getState( TileMonitor tile, ServerMonitor monitor )
|
||||||
|
{
|
||||||
|
TerminalState state = tile.cached;
|
||||||
|
if( state == null ) state = tile.cached = monitor.write();
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class PlayerUpdate
|
||||||
|
{
|
||||||
|
final ServerPlayerEntity player;
|
||||||
|
final TileMonitor monitor;
|
||||||
|
|
||||||
|
private PlayerUpdate( ServerPlayerEntity player, TileMonitor monitor )
|
||||||
|
{
|
||||||
|
this.player = player;
|
||||||
|
this.monitor = monitor;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ public class TileMonitor extends TileGeneric
|
|||||||
private LazyOptional<IPeripheral> peripheralCap;
|
private LazyOptional<IPeripheral> peripheralCap;
|
||||||
private final Set<IComputerAccess> computers = new HashSet<>();
|
private final Set<IComputerAccess> computers = new HashSet<>();
|
||||||
|
|
||||||
|
private boolean needsUpdate = false;
|
||||||
private boolean destroyed = false;
|
private boolean destroyed = false;
|
||||||
private boolean visiting = false;
|
private boolean visiting = false;
|
||||||
|
|
||||||
@@ -147,6 +148,12 @@ public class TileMonitor extends TileGeneric
|
|||||||
@Override
|
@Override
|
||||||
public void blockTick()
|
public void blockTick()
|
||||||
{
|
{
|
||||||
|
if ( needsUpdate )
|
||||||
|
{
|
||||||
|
needsUpdate = false;
|
||||||
|
updateNeighbors();
|
||||||
|
}
|
||||||
|
|
||||||
if( xIndex != 0 || yIndex != 0 || serverMonitor == null ) return;
|
if( xIndex != 0 || yIndex != 0 || serverMonitor == null ) return;
|
||||||
|
|
||||||
serverMonitor.clearChanged();
|
serverMonitor.clearChanged();
|
||||||
@@ -525,6 +532,18 @@ public class TileMonitor extends TileGeneric
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateNeighborsDeferred()
|
||||||
|
{
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateNeighbors()
|
||||||
|
{
|
||||||
|
contractNeighbours();
|
||||||
|
contract();
|
||||||
|
expand();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings( "StatementWithEmptyBody" )
|
@SuppressWarnings( "StatementWithEmptyBody" )
|
||||||
void expand()
|
void expand()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ import dan200.computercraft.shared.data.HasComputerIdLootCondition;
|
|||||||
import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
|
import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
|
||||||
import dan200.computercraft.shared.media.items.RecordMedia;
|
import dan200.computercraft.shared.media.items.RecordMedia;
|
||||||
import dan200.computercraft.shared.network.NetworkHandler;
|
import dan200.computercraft.shared.network.NetworkHandler;
|
||||||
|
import dan200.computercraft.shared.peripheral.generic.methods.EnergyMethods;
|
||||||
|
import dan200.computercraft.shared.peripheral.generic.methods.FluidMethods;
|
||||||
|
import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
|
||||||
import dan200.computercraft.shared.util.NullStorage;
|
import dan200.computercraft.shared.util.NullStorage;
|
||||||
import net.minecraft.inventory.container.Container;
|
import net.minecraft.inventory.container.Container;
|
||||||
@@ -36,15 +39,19 @@ import net.minecraft.world.storage.loot.LootTables;
|
|||||||
import net.minecraft.world.storage.loot.TableLootEntry;
|
import net.minecraft.world.storage.loot.TableLootEntry;
|
||||||
import net.minecraft.world.storage.loot.conditions.LootConditionManager;
|
import net.minecraft.world.storage.loot.conditions.LootConditionManager;
|
||||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||||
|
import net.minecraftforge.energy.CapabilityEnergy;
|
||||||
import net.minecraftforge.event.LootTableLoadEvent;
|
import net.minecraftforge.event.LootTableLoadEvent;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
|
import net.minecraftforge.event.entity.player.PlayerContainerEvent;
|
||||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
|
import net.minecraftforge.fml.DeferredWorkQueue;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||||
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
|
import net.minecraftforge.fml.event.server.FMLServerStartedEvent;
|
||||||
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
|
||||||
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
|
import net.minecraftforge.fml.event.server.FMLServerStoppedEvent;
|
||||||
|
import net.minecraftforge.items.CapabilityItemHandler;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -59,11 +66,15 @@ public final class ComputerCraftProxyCommon
|
|||||||
{
|
{
|
||||||
NetworkHandler.setup();
|
NetworkHandler.setup();
|
||||||
|
|
||||||
net.minecraftforge.fml.DeferredWorkQueue.runLater( () -> {
|
DeferredWorkQueue.runLater( () -> {
|
||||||
registerProviders();
|
registerProviders();
|
||||||
ArgumentSerializers.register();
|
ArgumentSerializers.register();
|
||||||
registerLoot();
|
registerLoot();
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
ComputerCraftAPI.registerGenericSource( new InventoryMethods() );
|
||||||
|
ComputerCraftAPI.registerGenericSource( new FluidMethods() );
|
||||||
|
ComputerCraftAPI.registerGenericSource( new EnergyMethods() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerLoot()
|
public static void registerLoot()
|
||||||
@@ -103,6 +114,12 @@ public final class ComputerCraftProxyCommon
|
|||||||
// Register capabilities
|
// Register capabilities
|
||||||
CapabilityManager.INSTANCE.register( IWiredElement.class, new NullStorage<>(), () -> null );
|
CapabilityManager.INSTANCE.register( IWiredElement.class, new NullStorage<>(), () -> null );
|
||||||
CapabilityManager.INSTANCE.register( IPeripheral.class, new NullStorage<>(), () -> null );
|
CapabilityManager.INSTANCE.register( IPeripheral.class, new NullStorage<>(), () -> null );
|
||||||
|
|
||||||
|
// Register generic capabilities. This can technically be done off-thread, but we need it to happen
|
||||||
|
// after Forge's common setup, so this is easiest.
|
||||||
|
ComputerCraftAPI.registerGenericCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY );
|
||||||
|
ComputerCraftAPI.registerGenericCapability( CapabilityEnergy.ENERGY );
|
||||||
|
ComputerCraftAPI.registerGenericCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
|
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID )
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import dan200.computercraft.core.apis.IAPIEnvironment;
|
|||||||
import dan200.computercraft.core.asm.TaskCallback;
|
import dan200.computercraft.core.asm.TaskCallback;
|
||||||
import dan200.computercraft.core.tracking.TrackingField;
|
import dan200.computercraft.core.tracking.TrackingField;
|
||||||
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
import dan200.computercraft.shared.peripheral.generic.data.ItemData;
|
||||||
|
import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods;
|
||||||
import dan200.computercraft.shared.turtle.core.*;
|
import dan200.computercraft.shared.turtle.core.*;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
@@ -182,6 +183,10 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
/**
|
/**
|
||||||
* Place a block or item into the world in front of the turtle.
|
* Place a block or item into the world in front of the turtle.
|
||||||
*
|
*
|
||||||
|
* "Placing" an item allows it to interact with blocks and entities in front of the turtle. For instance, buckets
|
||||||
|
* can pick up and place down fluids, and wheat can be used to breed cows. However, you cannot use {@link #place} to
|
||||||
|
* perform arbitrary block interactions, such as clicking buttons or flipping levers.
|
||||||
|
*
|
||||||
* @param args Arguments to place.
|
* @param args Arguments to place.
|
||||||
* @return The turtle command result.
|
* @return The turtle command result.
|
||||||
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
||||||
@@ -202,6 +207,7 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
||||||
* @cc.treturn boolean Whether the block could be placed.
|
* @cc.treturn boolean Whether the block could be placed.
|
||||||
* @cc.treturn string|nil The reason the block was not placed.
|
* @cc.treturn string|nil The reason the block was not placed.
|
||||||
|
* @see #place For more information about placing items.
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult placeUp( IArguments args )
|
public final MethodResult placeUp( IArguments args )
|
||||||
@@ -217,6 +223,7 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
* @cc.tparam [opt] string text When placing a sign, set its contents to this text.
|
||||||
* @cc.treturn boolean Whether the block could be placed.
|
* @cc.treturn boolean Whether the block could be placed.
|
||||||
* @cc.treturn string|nil The reason the block was not placed.
|
* @cc.treturn string|nil The reason the block was not placed.
|
||||||
|
* @see #place For more information about placing items.
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult placeDown( IArguments args )
|
public final MethodResult placeDown( IArguments args )
|
||||||
@@ -365,18 +372,36 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
return trackCommand( new TurtleDetectCommand( InteractDirection.DOWN ) );
|
return trackCommand( new TurtleDetectCommand( InteractDirection.DOWN ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the block in front of the turtle is equal to the item in the currently selected slot.
|
||||||
|
*
|
||||||
|
* @return If the block and item are equal.
|
||||||
|
* @cc.treturn boolean If the block and item are equal.
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult compare()
|
public final MethodResult compare()
|
||||||
{
|
{
|
||||||
return trackCommand( new TurtleCompareCommand( InteractDirection.FORWARD ) );
|
return trackCommand( new TurtleCompareCommand( InteractDirection.FORWARD ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the block above the turtle is equal to the item in the currently selected slot.
|
||||||
|
*
|
||||||
|
* @return If the block and item are equal.
|
||||||
|
* @cc.treturn boolean If the block and item are equal.
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult compareUp()
|
public final MethodResult compareUp()
|
||||||
{
|
{
|
||||||
return trackCommand( new TurtleCompareCommand( InteractDirection.UP ) );
|
return trackCommand( new TurtleCompareCommand( InteractDirection.UP ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the block below the turtle is equal to the item in the currently selected slot.
|
||||||
|
*
|
||||||
|
* @return If the block and item are equal.
|
||||||
|
* @cc.treturn boolean If the block and item are equal.
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult compareDown()
|
public final MethodResult compareDown()
|
||||||
{
|
{
|
||||||
@@ -472,12 +497,57 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
return trackCommand( new TurtleSuckCommand( InteractDirection.DOWN, checkCount( count ) ) );
|
return trackCommand( new TurtleSuckCommand( InteractDirection.DOWN, checkCount( count ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum amount of fuel this turtle currently holds.
|
||||||
|
*
|
||||||
|
* @return The fuel level, or "unlimited".
|
||||||
|
* @cc.treturn [1] number The current amount of fuel a turtle this turtle has.
|
||||||
|
* @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving.
|
||||||
|
* @see #getFuelLimit()
|
||||||
|
* @see #refuel(Optional)
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final Object getFuelLevel()
|
public final Object getFuelLevel()
|
||||||
{
|
{
|
||||||
return turtle.isFuelNeeded() ? turtle.getFuelLevel() : "unlimited";
|
return turtle.isFuelNeeded() ? turtle.getFuelLevel() : "unlimited";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refuel this turtle.
|
||||||
|
*
|
||||||
|
* While most actions a turtle can perform (such as digging or placing blocks), moving consumes fuel from the
|
||||||
|
* turtle's internal buffer. If a turtle has no fuel, it will not move.
|
||||||
|
*
|
||||||
|
* {@link #refuel} refuels the turtle, consuming fuel items (such as coal or lava buckets) from the currently
|
||||||
|
* selected slot and converting them into energy. This finishes once the turtle is fully refuelled or all items have
|
||||||
|
* been consumed.
|
||||||
|
*
|
||||||
|
* @param countA The maximum number of items to consume. One can pass `0` to check if an item is combustable or not.
|
||||||
|
* @return If this turtle could be refuelled.
|
||||||
|
* @throws LuaException If the refuel count is out of range.
|
||||||
|
* @cc.treturn [1] true If the turtle was refuelled.
|
||||||
|
* @cc.treturn [2] false If the turtle was not refuelled.
|
||||||
|
* @cc.treturn [2] string The reason the turtle was not refuelled (
|
||||||
|
* @cc.usage Refuel a turtle from the currently selected slot.
|
||||||
|
* <pre>{@code
|
||||||
|
* local level = turtle.getFuelLevel()
|
||||||
|
* if new_level == "unlimited" then error("Turtle does not need fuel", 0) end
|
||||||
|
*
|
||||||
|
* local ok, err = turtle.refuel()
|
||||||
|
* if ok then
|
||||||
|
* local new_level = turtle.getFuelLevel()
|
||||||
|
* print(("Refuelled %d, current level is %d"):format(new_level - level, new_level))
|
||||||
|
* else
|
||||||
|
* printError(err)
|
||||||
|
* end}</pre>
|
||||||
|
* @cc.usage Check if the current item is a valid fuel source.
|
||||||
|
* <pre>{@code
|
||||||
|
* local is_fuel, reason = turtle.refuel(0)
|
||||||
|
* if not is_fuel then printError(reason) end
|
||||||
|
* }</pre>
|
||||||
|
* @see #getFuelLevel()
|
||||||
|
* @see #getFuelLimit()
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult refuel( Optional<Integer> countA ) throws LuaException
|
public final MethodResult refuel( Optional<Integer> countA ) throws LuaException
|
||||||
{
|
{
|
||||||
@@ -486,12 +556,30 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
return trackCommand( new TurtleRefuelCommand( count ) );
|
return trackCommand( new TurtleRefuelCommand( count ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare the item in the currently selected slot to the item in another slot.
|
||||||
|
*
|
||||||
|
* @param slot The slot to compare to.
|
||||||
|
* @return If the items are the same.
|
||||||
|
* @throws LuaException If the slot is out of range.
|
||||||
|
* @cc.treturn boolean If the two items are equal.
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult compareTo( int slot ) throws LuaException
|
public final MethodResult compareTo( int slot ) throws LuaException
|
||||||
{
|
{
|
||||||
return trackCommand( new TurtleCompareToCommand( checkSlot( slot ) ) );
|
return trackCommand( new TurtleCompareToCommand( checkSlot( slot ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move an item from the selected slot to another one.
|
||||||
|
*
|
||||||
|
* @param slotArg The slot to move this item to.
|
||||||
|
* @param countArg The maximum number of items to move.
|
||||||
|
* @return If the item was moved or not.
|
||||||
|
* @throws LuaException If the slot is out of range.
|
||||||
|
* @throws LuaException If the number of items is out of range.
|
||||||
|
* @cc.treturn boolean If some items were successfully moved.
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult transferTo( int slotArg, Optional<Integer> countArg ) throws LuaException
|
public final MethodResult transferTo( int slotArg, Optional<Integer> countArg ) throws LuaException
|
||||||
{
|
{
|
||||||
@@ -512,18 +600,55 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
return turtle.getSelectedSlot() + 1;
|
return turtle.getSelectedSlot() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the maximum amount of fuel this turtle can hold.
|
||||||
|
*
|
||||||
|
* By default, normal turtles have a limit of 20,000 and advanced turtles of 100,000.
|
||||||
|
*
|
||||||
|
* @return The limit, or "unlimited".
|
||||||
|
* @cc.treturn [1] number The maximum amount of fuel a turtle can hold.
|
||||||
|
* @cc.treturn [2] "unlimited" If turtles do not consume fuel when moving.
|
||||||
|
* @see #getFuelLevel()
|
||||||
|
* @see #refuel(Optional)
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final Object getFuelLimit()
|
public final Object getFuelLimit()
|
||||||
{
|
{
|
||||||
return turtle.isFuelNeeded() ? turtle.getFuelLimit() : "unlimited";
|
return turtle.isFuelNeeded() ? turtle.getFuelLimit() : "unlimited";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equip (or unequip) an item on the left side of this turtle.
|
||||||
|
*
|
||||||
|
* This finds the item in the currently selected slot and attempts to equip it to the left side of the turtle. The
|
||||||
|
* previous upgrade is removed and placed into the turtle's inventory. If there is no item in the slot, the previous
|
||||||
|
* upgrade is removed, but no new one is equipped.
|
||||||
|
*
|
||||||
|
* @return Whether an item was equiped or not.
|
||||||
|
* @cc.treturn [1] true If the item was equipped.
|
||||||
|
* @cc.treturn [2] false If we could not equip the item.
|
||||||
|
* @cc.treturn [2] string The reason equipping this item failed.
|
||||||
|
* @see #equipRight()
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult equipLeft()
|
public final MethodResult equipLeft()
|
||||||
{
|
{
|
||||||
return trackCommand( new TurtleEquipCommand( TurtleSide.LEFT ) );
|
return trackCommand( new TurtleEquipCommand( TurtleSide.LEFT ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equip (or unequip) an item on the right side of this turtle.
|
||||||
|
*
|
||||||
|
* This finds the item in the currently selected slot and attempts to equip it to the right side of the turtle. The
|
||||||
|
* previous upgrade is removed and placed into the turtle's inventory. If there is no item in the slot, the previous
|
||||||
|
* upgrade is removed, but no new one is equipped.
|
||||||
|
*
|
||||||
|
* @return Whether an item was equiped or not.
|
||||||
|
* @cc.treturn [1] true If the item was equipped.
|
||||||
|
* @cc.treturn [2] false If we could not equip the item.
|
||||||
|
* @cc.treturn [2] string The reason equipping this item failed.
|
||||||
|
* @see #equipRight()
|
||||||
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult equipRight()
|
public final MethodResult equipRight()
|
||||||
{
|
{
|
||||||
@@ -536,6 +661,18 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
* @return The turtle command result.
|
* @return The turtle command result.
|
||||||
* @cc.treturn boolean Whether there is a block in front of the turtle.
|
* @cc.treturn boolean Whether there is a block in front of the turtle.
|
||||||
* @cc.treturn table|string Information about the block in front, or a message explaining that there is no block.
|
* @cc.treturn table|string Information about the block in front, or a message explaining that there is no block.
|
||||||
|
* @cc.usage <pre>{@code
|
||||||
|
* local has_block, data = turtle.inspect()
|
||||||
|
* if has_block then
|
||||||
|
* print(textutils.serialize(data))
|
||||||
|
* -- {
|
||||||
|
* -- name = "minecraft:oak_log",
|
||||||
|
* -- state = { axis = "x" },
|
||||||
|
* -- tags = { ["minecraft:logs"] = true, ... },
|
||||||
|
* -- }
|
||||||
|
* else
|
||||||
|
* print("No block in front of the turtle")
|
||||||
|
* end}</pre>
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult inspect()
|
public final MethodResult inspect()
|
||||||
@@ -578,6 +715,7 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
* more information about the item at the cost of taking longer to run.
|
* more information about the item at the cost of taking longer to run.
|
||||||
* @return The command result.
|
* @return The command result.
|
||||||
* @throws LuaException If the slot is out of range.
|
* @throws LuaException If the slot is out of range.
|
||||||
|
* @see InventoryMethods#getItemDetail Describes the information returned by a detailed query.
|
||||||
* @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty.
|
* @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty.
|
||||||
* @cc.usage Print the current slot, assuming it contains 13 dirt.
|
* @cc.usage Print the current slot, assuming it contains 13 dirt.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -15,10 +15,8 @@ import net.minecraft.util.Direction;
|
|||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TurtleCompareCommand implements ITurtleCommand
|
public class TurtleCompareCommand implements ITurtleCommand
|
||||||
@@ -52,19 +50,6 @@ public class TurtleCompareCommand implements ITurtleCommand
|
|||||||
Block lookAtBlock = lookAtState.getBlock();
|
Block lookAtBlock = lookAtState.getBlock();
|
||||||
if( !lookAtBlock.isAir( lookAtState, world, newPosition ) )
|
if( !lookAtBlock.isAir( lookAtState, world, newPosition ) )
|
||||||
{
|
{
|
||||||
// Try getSilkTouchDrop first
|
|
||||||
if( !lookAtBlock.hasTileEntity( lookAtState ) )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Method method = ObfuscationReflectionHelper.findMethod( Block.class, "func_180643_i", BlockState.class );
|
|
||||||
lookAtStack = (ItemStack) method.invoke( lookAtBlock, lookAtState );
|
|
||||||
}
|
|
||||||
catch( ReflectiveOperationException | RuntimeException ignored )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// See if the block drops anything with the same ID as itself
|
// See if the block drops anything with the same ID as itself
|
||||||
// (try 5 times to try and beat random number generators)
|
// (try 5 times to try and beat random number generators)
|
||||||
for( int i = 0; i < 5 && lookAtStack.isEmpty(); i++ )
|
for( int i = 0; i < 5 && lookAtStack.isEmpty(); i++ )
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
*/
|
*/
|
||||||
package dan200.computercraft.shared.util;
|
package dan200.computercraft.shared.util;
|
||||||
|
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.inventory.IInventory;
|
import net.minecraft.inventory.IInventory;
|
||||||
import net.minecraft.inventory.ISidedInventory;
|
import net.minecraft.inventory.ISidedInventory;
|
||||||
|
import net.minecraft.inventory.ISidedInventoryProvider;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
@@ -23,6 +25,7 @@ import net.minecraftforge.items.wrapper.SidedInvWrapper;
|
|||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public final class InventoryUtil
|
public final class InventoryUtil
|
||||||
{
|
{
|
||||||
@@ -41,7 +44,8 @@ public final class InventoryUtil
|
|||||||
|
|
||||||
// Methods for finding inventories:
|
// Methods for finding inventories:
|
||||||
|
|
||||||
public static IItemHandler getInventory( World world, BlockPos pos, Direction side )
|
@Nullable
|
||||||
|
public static IItemHandler getInventory( @Nonnull World world, @Nonnull BlockPos pos, @Nonnull Direction side )
|
||||||
{
|
{
|
||||||
// Look for tile with inventory
|
// Look for tile with inventory
|
||||||
TileEntity tileEntity = world.getBlockEntity( pos );
|
TileEntity tileEntity = world.getBlockEntity( pos );
|
||||||
@@ -52,7 +56,7 @@ public final class InventoryUtil
|
|||||||
{
|
{
|
||||||
return itemHandler.orElseThrow( NullPointerException::new );
|
return itemHandler.orElseThrow( NullPointerException::new );
|
||||||
}
|
}
|
||||||
else if( side != null && tileEntity instanceof ISidedInventory )
|
else if( tileEntity instanceof ISidedInventory )
|
||||||
{
|
{
|
||||||
return new SidedInvWrapper( (ISidedInventory) tileEntity, side );
|
return new SidedInvWrapper( (ISidedInventory) tileEntity, side );
|
||||||
}
|
}
|
||||||
@@ -62,6 +66,13 @@ public final class InventoryUtil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockState block = world.getBlockState( pos );
|
||||||
|
if( block.getBlock() instanceof ISidedInventoryProvider )
|
||||||
|
{
|
||||||
|
ISidedInventory inventory = ((ISidedInventoryProvider) block.getBlock()).getContainer( block, world, pos );
|
||||||
|
return new SidedInvWrapper( inventory, side );
|
||||||
|
}
|
||||||
|
|
||||||
// Look for entity with inventory
|
// Look for entity with inventory
|
||||||
Vec3d vecStart = new Vec3d(
|
Vec3d vecStart = new Vec3d(
|
||||||
pos.getX() + 0.5 + 0.6 * side.getStepX(),
|
pos.getX() + 0.5 + 0.6 * side.getStepX(),
|
||||||
|
|||||||
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
|
||||||
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
|
||||||
* Send enquiries to dratcliffe@gmail.com
|
|
||||||
*/
|
|
||||||
package dan200.computercraft.shared.util;
|
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
|
||||||
import net.minecraftforge.fml.ModList;
|
|
||||||
import org.objectweb.asm.Type;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ServiceLoader;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import java.util.stream.StreamSupport;
|
|
||||||
|
|
||||||
public final class ServiceUtil
|
|
||||||
{
|
|
||||||
private static final Type AUTO_SERVICE = Type.getType( "Lcom/google/auto/service/AutoService;" );
|
|
||||||
|
|
||||||
private ServiceUtil()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Stream<T> loadServices( Class<T> target )
|
|
||||||
{
|
|
||||||
return StreamSupport.stream( ServiceLoader.load( target, ServiceUtil.class.getClassLoader() ).spliterator(), false );
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Stream<T> loadServicesForge( Class<T> target )
|
|
||||||
{
|
|
||||||
Type type = Type.getType( target );
|
|
||||||
ClassLoader loader = ComputerCraftAPI.class.getClassLoader();
|
|
||||||
return ModList.get().getAllScanData().stream()
|
|
||||||
.flatMap( x -> x.getAnnotations().stream() )
|
|
||||||
.filter( x -> x.getAnnotationType().equals( AUTO_SERVICE ) )
|
|
||||||
.filter( x -> {
|
|
||||||
Object value = x.getAnnotationData().get( "value" );
|
|
||||||
return value instanceof List<?> && ((List<?>) value).contains( type );
|
|
||||||
} )
|
|
||||||
.flatMap( x -> {
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Class<?> klass = loader.loadClass( x.getClassType().getClassName() );
|
|
||||||
if( !target.isAssignableFrom( klass ) )
|
|
||||||
{
|
|
||||||
ComputerCraft.log.error( "{} is not a subtype of {}", x.getClassType().getClassName(), target.getName() );
|
|
||||||
return Stream.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
Class<? extends T> casted = klass.asSubclass( target );
|
|
||||||
return Stream.of( casted.newInstance() );
|
|
||||||
}
|
|
||||||
catch( ReflectiveOperationException e )
|
|
||||||
{
|
|
||||||
ComputerCraft.log.error( "Cannot load {}", x.getClassType(), e );
|
|
||||||
return Stream.empty();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -38,5 +38,21 @@
|
|||||||
"upgrade.computercraft.speaker.adjective": "(Alto-Falante)",
|
"upgrade.computercraft.speaker.adjective": "(Alto-Falante)",
|
||||||
"chat.computercraft.wired_modem.peripheral_connected": "Periférico \"%s\" conectado à rede",
|
"chat.computercraft.wired_modem.peripheral_connected": "Periférico \"%s\" conectado à rede",
|
||||||
"chat.computercraft.wired_modem.peripheral_disconnected": "Periférico \"%s\" desconectado da rede",
|
"chat.computercraft.wired_modem.peripheral_disconnected": "Periférico \"%s\" desconectado da rede",
|
||||||
"gui.computercraft.tooltip.copy": "Copiar para a área de transferência"
|
"gui.computercraft.tooltip.copy": "Copiar para a área de transferência",
|
||||||
|
"commands.computercraft.tp.synopsis": "Teleprota para um computador específico.",
|
||||||
|
"commands.computercraft.turn_on.done": "Ligou %s/%s computadores",
|
||||||
|
"commands.computercraft.turn_on.desc": "Liga os computadores em escuta. Você pode especificar o id de instância do computador (ex.: 123), id do computador (ex.: #123) ou o rótulo (ex.: \"@MeuComputador\").",
|
||||||
|
"commands.computercraft.turn_on.synopsis": "Liga computadores remotamente.",
|
||||||
|
"commands.computercraft.shutdown.done": "Desliga %s/%s computadores",
|
||||||
|
"commands.computercraft.shutdown.desc": "Desliga os computadores em escuta ou todos caso não tenha sido especificado. Você pode especificar o id de instância do computador (ex.: 123), id do computador (ex.: #123) ou o rótulo (ex.: \"@MeuComputador\").",
|
||||||
|
"commands.computercraft.shutdown.synopsis": "Desliga computadores remotamente.",
|
||||||
|
"commands.computercraft.dump.action": "Ver mais informação sobre este computador",
|
||||||
|
"commands.computercraft.dump.desc": "Mostra o status de todos os computadores ou uma informação específica sobre um computador. Você pode especificar o id de instância do computador (ex.: 123), id do computador (ex.: #123) ou o rótulo (ex.: \"@MeuComputador\").",
|
||||||
|
"commands.computercraft.dump.synopsis": "Mostra status de computadores.",
|
||||||
|
"commands.computercraft.help.no_command": "Comando '%s' não existe",
|
||||||
|
"commands.computercraft.help.no_children": "%s não tem sub-comandos",
|
||||||
|
"commands.computercraft.help.desc": "Mostra essa mensagem de ajuda",
|
||||||
|
"commands.computercraft.help.synopsis": "Providencia ajuda para um comando específico",
|
||||||
|
"commands.computercraft.desc": "O comando /computercraft providencia várias ferramentas de depuração e administração para controle e interação com computadores.",
|
||||||
|
"commands.computercraft.synopsis": "Vários comandos para controlar computadores."
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 534 B After Width: | Height: | Size: 476 B |
|
Before Width: | Height: | Size: 475 B After Width: | Height: | Size: 417 B |
|
Before Width: | Height: | Size: 584 B After Width: | Height: | Size: 526 B |
|
Before Width: | Height: | Size: 575 B After Width: | Height: | Size: 517 B |
|
Before Width: | Height: | Size: 503 B After Width: | Height: | Size: 404 B |
|
Before Width: | Height: | Size: 633 B After Width: | Height: | Size: 534 B |
|
Before Width: | Height: | Size: 525 B After Width: | Height: | Size: 426 B |
|
Before Width: | Height: | Size: 641 B After Width: | Height: | Size: 560 B |
|
Before Width: | Height: | Size: 635 B After Width: | Height: | Size: 554 B |
|
Before Width: | Height: | Size: 421 B After Width: | Height: | Size: 193 B |
|
Before Width: | Height: | Size: 501 B After Width: | Height: | Size: 214 B |
|
Before Width: | Height: | Size: 439 B After Width: | Height: | Size: 199 B |
|
Before Width: | Height: | Size: 327 B After Width: | Height: | Size: 217 B |
|
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 195 B |
|
Before Width: | Height: | Size: 327 B After Width: | Height: | Size: 218 B |
|
Before Width: | Height: | Size: 327 B After Width: | Height: | Size: 217 B |
|
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 195 B |
|
Before Width: | Height: | Size: 546 B After Width: | Height: | Size: 488 B |
|
Before Width: | Height: | Size: 548 B After Width: | Height: | Size: 490 B |
|
Before Width: | Height: | Size: 416 B After Width: | Height: | Size: 358 B |