mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-07 08:52:59 +00:00
Compare commits
84 Commits
v1.12.2-1.
...
v1.12.2-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46d78af068 | ||
|
|
eb5cff1045 | ||
|
|
35c7792aa2 | ||
|
|
521688d630 | ||
|
|
75e2845c01 | ||
|
|
2f96283286 | ||
|
|
cbe6e9b5f5 | ||
|
|
2ab79cf474 | ||
|
|
6ce34aba79 | ||
|
|
5eeb320b60 | ||
|
|
93310850d2 | ||
|
|
a2880b12ca | ||
|
|
303b57779a | ||
|
|
6279816ecc | ||
|
|
4ae77261fa | ||
|
|
4b7d843b78 | ||
|
|
1c28df65c3 | ||
|
|
85b740f484 | ||
|
|
f9929cb27d | ||
|
|
bafab1ac07 | ||
|
|
e05c262468 | ||
|
|
7a3f7d3bba | ||
|
|
95aa48c456 | ||
|
|
904a168d5c | ||
|
|
724441eddc | ||
|
|
f68ab3edd1 | ||
|
|
29dce26bf6 | ||
|
|
717ab69093 | ||
|
|
138a2cf08f | ||
|
|
81daf82647 | ||
|
|
f3798bfb63 | ||
|
|
bc07dfad2e | ||
|
|
309cbdb8be | ||
|
|
a0e7c4a74c | ||
|
|
7d428030df | ||
|
|
00c395f689 | ||
|
|
d8e1c73d26 | ||
|
|
ffa4cc241b | ||
|
|
6f1b740c8f | ||
|
|
3406ba3ebf | ||
|
|
6b81bcf334 | ||
|
|
acac70675d | ||
|
|
56434259c1 | ||
|
|
da7e4b9016 | ||
|
|
d4b8650d21 | ||
|
|
17645a79f0 | ||
|
|
ce1f14a010 | ||
|
|
43050426de | ||
|
|
b05f60c98b | ||
|
|
c44c560f96 | ||
|
|
e839ef54af | ||
|
|
0cb659d78c | ||
|
|
9048deeb95 | ||
|
|
5592ebae7d | ||
|
|
b076c32fd1 | ||
|
|
a48f1e310f | ||
|
|
19aca001d7 | ||
|
|
114f913bf8 | ||
|
|
1c9810890a | ||
|
|
b11beb508b | ||
|
|
af8d4da594 | ||
|
|
a81db2cda6 | ||
|
|
99bdff0f92 | ||
|
|
5b0ce7410d | ||
|
|
d5ea22d1a0 | ||
|
|
210f3fa9e2 | ||
|
|
d661cfa88b | ||
|
|
68bf3a71dc | ||
|
|
3cdb12d293 | ||
|
|
ad33acd7d1 | ||
|
|
0ec3884e98 | ||
|
|
7f2471d6b2 | ||
|
|
8fafec4915 | ||
|
|
b9fd690ecb | ||
|
|
2f2ada4416 | ||
|
|
9c951c58d9 | ||
|
|
4b4b47e231 | ||
|
|
978c28a686 | ||
|
|
b867ada5e5 | ||
|
|
7071cc972b | ||
|
|
6898f932a0 | ||
|
|
2e0ef6385d | ||
|
|
f93da7ea51 | ||
|
|
1210bb8a4d |
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Report some misbehaviour in the mod
|
||||
|
||||
labels: bug
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
4
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea or improvement
|
||||
|
||||
labels: enhancement
|
||||
---
|
||||
|
||||
<!--
|
||||
@@ -11,4 +11,4 @@ about: Suggest an idea or improvement
|
||||
|
||||
## Useful information to include:
|
||||
- Explanation of how the feature/change should work.
|
||||
- Some rationale/use case for a feature. I'd like to keep CC:T as minimal as possible, so I like have a solid justification for each feature.
|
||||
- Some rationale/use case for a feature. My general approach to designing new features is to ask yourself "what issue are we trying to solve" and _then_ "is this the best way to solve this issue?".
|
||||
|
||||
3
.github/pull_request_template.md
vendored
Normal file
3
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
## A quick checklist
|
||||
- If there's a existing issue, please link to it. If not, provide fill out the same information you would in a normal issue - reproduction steps for bugs, rationale for use-case.
|
||||
- If you're working on CraftOS, try to write a few test cases so we can ensure everything continues to work in the future. Tests live in `src/test/resources/test-rom/spec` and can be run with `./gradlew check`.
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -15,3 +15,9 @@
|
||||
.idea
|
||||
.gradle
|
||||
*.DS_Store
|
||||
|
||||
.classpath
|
||||
.project
|
||||
.settings/
|
||||
bin/
|
||||
*.launch
|
||||
|
||||
@@ -17,7 +17,8 @@ ignore = {
|
||||
-- are largely unsupported.
|
||||
include_files = {
|
||||
'src/main/resources/assets/computercraft/lua/rom',
|
||||
'src/main/resources/assets/computercraft/lua/bios.lua'
|
||||
'src/main/resources/assets/computercraft/lua/bios.lua',
|
||||
'src/test/resources/test-rom',
|
||||
}
|
||||
|
||||
files['src/main/resources/assets/computercraft/lua/bios.lua'] = {
|
||||
|
||||
@@ -11,4 +11,4 @@ cache:
|
||||
- $HOME/.gradle/wrapper/s
|
||||
|
||||
jdk:
|
||||
- oraclejdk8
|
||||
- openjdk8
|
||||
|
||||
15
README.md
15
README.md
@@ -1,5 +1,5 @@
|
||||
# 
|
||||
[](https://travis-ci.org/SquidDev-CC/CC-Tweaked)
|
||||
[](https://travis-ci.org/SquidDev-CC/CC-Tweaked "Current build status") [](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge")
|
||||
|
||||
CC: Tweaked is a fork of [ComputerCraft](https://github.com/dan200/ComputerCraft), adding programmable computers,
|
||||
turtles and more to Minecraft.
|
||||
@@ -9,7 +9,7 @@ ComputerCraft has always held a fond place in my heart: it's the mod which reall
|
||||
mod which has kept me playing it for many years. However, development of the original mod has slowed, as the original
|
||||
developers have had less time to work on the mod, and moved onto other projects and commitments.
|
||||
|
||||
CC:Tweaked (or CC:T for short) is an attempt to continue ComputerCraft's legacy. It's not intended to be a competitor
|
||||
CC: Tweaked (or CC:T for short) is an attempt to continue ComputerCraft's legacy. It's not intended to be a competitor
|
||||
to CC, nor do I want to take it in a vastly different direction to the original mod. Instead, CC:T focuses on making the
|
||||
ComputerCraft experience as _solid_ as possible, ironing out any wrinkles that may have developed over time.
|
||||
|
||||
@@ -46,8 +46,17 @@ develop CC:T, you'll need to follow these steps:
|
||||
|
||||
If you want to run CC:T in a normal Minecraft instance, run `./gradlew build` and copy the `.jar` from `build/libs`.
|
||||
|
||||
## Community
|
||||
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
||||
ComputerCraft we have a [forum](https://forums.computercraft.cc/) and [Discord guild](https://discord.gg/H2UyJXe)!
|
||||
There's also a fairly populated, albeit quiet [IRC channel](http://webchat.esper.net/?channels=#computercraft), if
|
||||
that's more your cup of tea.
|
||||
|
||||
I'd generally recommend you don't contact me directly (email, DM, etc...) unless absolutely necessary (i.e. in order to
|
||||
report exploits). You'll get a far quicker response if you ask the whole community!
|
||||
|
||||
## Using
|
||||
If you want to depend on CC:Tweaked, we have a maven repo. However, you should be wary that some functionality is only
|
||||
If you want to depend on CC: Tweaked, we have a maven repo. However, you should be wary that some functionality is only
|
||||
exposed by CC:T's API and not vanilla ComputerCraft. If you wish to support all variations of ComputerCraft, I recommend
|
||||
using [cc.crzd.me's maven](https://cc.crzd.me/maven/) instead.
|
||||
|
||||
|
||||
152
build.gradle
152
build.gradle
@@ -5,7 +5,7 @@ buildscript {
|
||||
jcenter()
|
||||
maven {
|
||||
name = "forge"
|
||||
url = "http://files.minecraftforge.net/maven"
|
||||
url = "https://files.minecraftforge.net/maven"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
@@ -17,7 +17,9 @@ buildscript {
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.matthewprenger.cursegradle' version '1.0.10'
|
||||
id "checkstyle"
|
||||
id "com.github.hierynomus.license" version "0.15.0"
|
||||
id "com.matthewprenger.cursegradle" version "1.3.0"
|
||||
id "com.github.breadmoirai.github-release" version "2.2.4"
|
||||
}
|
||||
|
||||
@@ -43,7 +45,7 @@ minecraft {
|
||||
repositories {
|
||||
maven {
|
||||
name "JEI"
|
||||
url "http://dvs1.progwml6.com/files/maven"
|
||||
url "https://dvs1.progwml6.com/files/maven"
|
||||
}
|
||||
maven {
|
||||
name "SquidDev"
|
||||
@@ -55,7 +57,7 @@ repositories {
|
||||
}
|
||||
maven {
|
||||
name "Amadornes"
|
||||
url "http://maven.amadornes.com/"
|
||||
url "https://maven.amadornes.com/"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +68,8 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
checkstyle "com.puppycrawl.tools:checkstyle:8.21"
|
||||
|
||||
deobfProvided "mezz.jei:jei_1.12.2:4.15.0.269:api"
|
||||
deobfProvided "pl.asie:Charset-Lib:0.5.4.6"
|
||||
deobfProvided "MCMultiPart2:MCMultiPart:2.5.3"
|
||||
@@ -74,12 +78,14 @@ dependencies {
|
||||
|
||||
shade 'org.squiddev:Cobalt:0.5.0-SNAPSHOT'
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.1.0'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.1.0'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2'
|
||||
|
||||
deployerJars "org.apache.maven.wagon:wagon-ssh:3.0.0"
|
||||
}
|
||||
|
||||
// Compile tasks
|
||||
|
||||
javadoc {
|
||||
include "dan200/computercraft/api/**/*.java"
|
||||
}
|
||||
@@ -98,12 +104,22 @@ jar {
|
||||
from configurations.shade.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
}
|
||||
|
||||
[compileJava, compileTestJava].forEach {
|
||||
it.configure {
|
||||
options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.*
|
||||
import java.util.zip.*
|
||||
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonElement
|
||||
import com.hierynomus.gradle.license.tasks.LicenseCheck
|
||||
import com.hierynomus.gradle.license.tasks.LicenseFormat
|
||||
import org.ajoberstar.grgit.Grgit
|
||||
import proguard.gradle.ProGuardTask
|
||||
|
||||
@@ -199,6 +215,7 @@ task compressJson(dependsOn: extractAnnotationsJar) {
|
||||
// Copy over all files in the current jar to the new one, running json files from GSON. As pretty printing
|
||||
// is turned off, they should be minified.
|
||||
new ZipFile(jarPath).withCloseable { inJar ->
|
||||
tempPath.getParentFile().mkdirs()
|
||||
new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(tempPath))).withCloseable { outJar ->
|
||||
inJar.entries().each { entry ->
|
||||
if(entry.directory) {
|
||||
@@ -226,12 +243,105 @@ task compressJson(dependsOn: extractAnnotationsJar) {
|
||||
|
||||
assemble.dependsOn compressJson
|
||||
|
||||
// Check tasks
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "skipped", "failed"
|
||||
}
|
||||
}
|
||||
|
||||
license {
|
||||
mapping("java", "SLASHSTAR_STYLE")
|
||||
strictCheck true
|
||||
|
||||
ext.year = Calendar.getInstance().get(Calendar.YEAR)
|
||||
}
|
||||
|
||||
[licenseMain, licenseFormatMain].forEach {
|
||||
it.configure {
|
||||
include("**/*.java")
|
||||
exclude("dan200/computercraft/api/**")
|
||||
header rootProject.file('config/license/main.txt')
|
||||
}
|
||||
}
|
||||
|
||||
[licenseTest, licenseFormatTest].forEach {
|
||||
it.configure {
|
||||
include("**/*.java")
|
||||
header rootProject.file('config/license/main.txt')
|
||||
}
|
||||
}
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
tasks.withType(LicenseFormat) {
|
||||
outputs.upToDateWhen { false }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task licenseAPI(type: LicenseCheck);
|
||||
task licenseFormatAPI(type: LicenseFormat);
|
||||
[licenseAPI, licenseFormatAPI].forEach {
|
||||
it.configure {
|
||||
source = sourceSets.main.java
|
||||
include("dan200/computercraft/api/**")
|
||||
header rootProject.file('config/license/api.txt')
|
||||
}
|
||||
}
|
||||
|
||||
// Upload tasks
|
||||
|
||||
task checkRelease {
|
||||
group "upload"
|
||||
description "Verifies that everything is ready for a release"
|
||||
|
||||
inputs.property "version", mod_version
|
||||
inputs.file("src/main/resources/assets/computercraft/lua/rom/help/changelog.txt")
|
||||
inputs.file("src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt")
|
||||
|
||||
doLast {
|
||||
def ok = true
|
||||
|
||||
// Check we're targetting the current version
|
||||
def whatsnew = new File("src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt").readLines()
|
||||
if (whatsnew[0] != "New features in CC: Tweaked $mod_version") {
|
||||
ok = false
|
||||
project.logger.error("Expected `whatsnew.txt' to target $mod_version.")
|
||||
}
|
||||
|
||||
// Check "read more" exists and trim it
|
||||
def idx = whatsnew.findIndexOf { it == 'Type "help changelog" to see the full version history.' }
|
||||
if (idx == -1) {
|
||||
ok = false
|
||||
project.logger.error("Must mention the changelog in whatsnew.txt")
|
||||
} else {
|
||||
whatsnew = whatsnew.getAt(0 ..< idx)
|
||||
}
|
||||
|
||||
// Check whatsnew and changelog match.
|
||||
def versionChangelog = "# " + whatsnew.join("\n")
|
||||
def changelog = new File("src/main/resources/assets/computercraft/lua/rom/help/changelog.txt").getText()
|
||||
if (!changelog.startsWith(versionChangelog)) {
|
||||
ok = false
|
||||
project.logger.error("whatsnew and changelog are not in sync")
|
||||
}
|
||||
|
||||
if (!ok) throw new IllegalStateException("Could not check release")
|
||||
}
|
||||
}
|
||||
|
||||
curseforge {
|
||||
apiKey = project.hasProperty('curseForgeApiKey') ? project.curseForgeApiKey : ''
|
||||
project {
|
||||
id = '282001'
|
||||
releaseType = 'release'
|
||||
changelog = "Release notes can be found on the GitHub repository (https://github.com/SquidDev-CC/CC-Tweaked/releases/tag/v${mc_version}-${mod_version})."
|
||||
|
||||
relations {
|
||||
incompatible "computercraft"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,33 +402,25 @@ githubRelease {
|
||||
token project.hasProperty('githubApiKey') ? project.githubApiKey : ''
|
||||
owner 'SquidDev-CC'
|
||||
repo 'CC-Tweaked'
|
||||
targetCommitish (mc_version == "1.12.2" ? "master" : mc_version)
|
||||
targetCommitish { Grgit.open(dir: '.').branch.current().name }
|
||||
|
||||
tagName "v${mc_version}-${mod_version}"
|
||||
releaseName "[${mc_version}] ${mod_version}"
|
||||
body ''
|
||||
body {
|
||||
"## " + new File("src/main/resources/assets/computercraft/lua/rom/help/whatsnew.txt")
|
||||
.readLines()
|
||||
.takeWhile { it != 'Type "help changelog" to see the full version history.' }
|
||||
.join("\n").trim()
|
||||
}
|
||||
prerelease false
|
||||
|
||||
releaseAssets.from(jar.archivePath)
|
||||
}
|
||||
|
||||
task uploadAll(dependsOn: proguard) {
|
||||
def uploadTasks = ["uploadArchives", "curseforge", "githubRelease"]
|
||||
uploadTasks.forEach { tasks.getByName(it).dependsOn checkRelease }
|
||||
|
||||
task uploadAll(dependsOn: uploadTasks) {
|
||||
group "upload"
|
||||
description "Uploads to all repositories (Maven, Curse, GitHub release)"
|
||||
dependsOn uploadArchives, curseforge, githubRelease
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
testLogging {
|
||||
events "passed", "skipped", "failed"
|
||||
}
|
||||
}
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
tasks.withType(JavaCompile) {
|
||||
options.compilerArgs << "-Xlint" << "-Xlint:-processing" << "-Werror"
|
||||
}
|
||||
}
|
||||
|
||||
runClient.outputs.upToDateWhen { false }
|
||||
|
||||
159
config/checkstyle/checkstyle.xml
Normal file
159
config/checkstyle/checkstyle.xml
Normal file
@@ -0,0 +1,159 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
|
||||
"https://checkstyle.org/dtds/configuration_1_3.dtd">
|
||||
<module name="Checker">
|
||||
<property name="tabWidth" value="4"/>
|
||||
<property name="charset" value="UTF-8" />
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="config/checkstyle/suppressions.xml" />
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<!-- Annotations -->
|
||||
<module name="AnnotationLocation" />
|
||||
<module name="AnnotationUseStyle" />
|
||||
<module name="MissingDeprecated">
|
||||
<property name="skipNoJavadoc" value="true" />
|
||||
</module>
|
||||
<module name="MissingOverride" />
|
||||
|
||||
<!-- Blocks -->
|
||||
<module name="EmptyBlock" />
|
||||
<module name="EmptyCatchBlock">
|
||||
<property name="exceptionVariableName" value="ignored" />
|
||||
</module>
|
||||
<module name="LeftCurly">
|
||||
<property name="option" value="nl" />
|
||||
<!-- The defaults, minus lambdas. -->
|
||||
<property name="tokens" value="ANNOTATION_DEF,CLASS_DEF,CTOR_DEF,ENUM_CONSTANT_DEF,ENUM_DEF,INTERFACE_DEF,LITERAL_CASE,LITERAL_CATCH,LITERAL_DEFAULT,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_SWITCH,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,METHOD_DEF,OBJBLOCK,STATIC_INIT" />
|
||||
</module>
|
||||
<module name="NeedBraces">
|
||||
<property name="allowSingleLineStatement" value="true"/>
|
||||
</module>
|
||||
<module name="RightCurly">
|
||||
<property name="option" value="alone" />
|
||||
</module>
|
||||
|
||||
<!-- Class design. As if we've ever followed good practice here. -->
|
||||
<module name="FinalClass" />
|
||||
<module name="InterfaceIsType" />
|
||||
<module name="MutableException" />
|
||||
<module name="OneTopLevelClass" />
|
||||
|
||||
<!-- Coding -->
|
||||
<module name="ArrayTrailingComma" />
|
||||
<module name="EqualsHashCode" />
|
||||
<!-- FallThrough does not handle unreachable code well -->
|
||||
<module name="IllegalInstantiation" />
|
||||
<module name="IllegalThrows" />
|
||||
<module name="ModifiedControlVariable" />
|
||||
<module name="NoClone" />
|
||||
<module name="NoFinalizer" />
|
||||
<module name="OneStatementPerLine" />
|
||||
<module name="PackageDeclaration" />
|
||||
<module name="SimplifyBooleanExpression" />
|
||||
<module name="SimplifyBooleanReturn" />
|
||||
<module name="StringLiteralEquality" />
|
||||
<module name="UnnecessaryParentheses" />
|
||||
|
||||
<!-- Imports -->
|
||||
<module name="CustomImportOrder" />
|
||||
<module name="IllegalImport" />
|
||||
<module name="RedundantImport" />
|
||||
<module name="UnusedImports" />
|
||||
|
||||
<!-- Javadoc -->
|
||||
<module name="AtclauseOrder" />
|
||||
<!-- TODO: Cleanup our documentation before enabling JavadocMethod, JavadocStyle, JavadocType and SummaryJavadoc. -->
|
||||
<module name="NonEmptyAtclauseDescription" />
|
||||
<module name="SingleLineJavadoc" />
|
||||
|
||||
<!-- Misc -->
|
||||
<module name="ArrayTypeStyle" />
|
||||
<module name="CommentsIndentation" />
|
||||
<module name="Indentation" />
|
||||
<module name="OuterTypeFilename" />
|
||||
|
||||
<!-- Modifiers -->
|
||||
<module name="ModifierOrder" />
|
||||
<module name="RedundantModifier" />
|
||||
|
||||
<!-- Naming -->
|
||||
<module name="ClassTypeParameterName" />
|
||||
<module name="InterfaceTypeParameterName" />
|
||||
<module name="LambdaParameterName" />
|
||||
<module name="LocalFinalVariableName" />
|
||||
<module name="LocalVariableName" />
|
||||
<!-- Allow an optional m_ on private members -->
|
||||
<module name="MemberName">
|
||||
<property name="applyToPrivate" value="false" />
|
||||
<property name="applyToPackage" value="false" />
|
||||
</module>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^(m_)?[a-z][a-zA-Z0-9]*$" />
|
||||
<property name="applyToPrivate" value="true" />
|
||||
<property name="applyToPackage" value="true" />
|
||||
</module>
|
||||
<module name="MethodName" />
|
||||
<module name="MethodTypeParameterName" />
|
||||
<module name="PackageName">
|
||||
<property name="format" value="^dan200\.computercraf(\.[a-z][a-z0-9]*)*" />
|
||||
</module>
|
||||
<module name="ParameterName" />
|
||||
<module name="StaticVariableName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z]+)?$" />
|
||||
<property name="applyToPrivate" value="false" />
|
||||
</module>
|
||||
<module name="StaticVariableName">
|
||||
<property name="format" value="^(s_)?[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z]+)?$" />
|
||||
<property name="applyToPrivate" value="true" />
|
||||
</module>
|
||||
<module name="TypeName" />
|
||||
|
||||
<!-- Whitespace -->
|
||||
<module name="EmptyForInitializerPad"/>
|
||||
<module name="EmptyForIteratorPad">
|
||||
<property name="option" value="space"/>
|
||||
</module>
|
||||
<module name="GenericWhitespace" />
|
||||
<module name="MethodParamPad" />
|
||||
<module name="NoLineWrap" />
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP" />
|
||||
</module>
|
||||
<module name="NoWhitespaceBefore" />
|
||||
<!-- TODO: Decide on an OperatorWrap style. -->
|
||||
<module name="ParenPad">
|
||||
<property name="option" value="space" />
|
||||
<property name="tokens" value="ANNOTATION,ANNOTATION_FIELD_DEF,CTOR_CALL,CTOR_DEF,ENUM_CONSTANT_DEF,LITERAL_CATCH,LITERAL_DO,LITERAL_FOR,LITERAL_IF,LITERAL_NEW,LITERAL_SWITCH,LITERAL_SYNCHRONIZED,LITERAL_WHILE,METHOD_CALL,METHOD_DEF,RESOURCE_SPECIFICATION,SUPER_CTOR_CALL,LAMBDA" />
|
||||
</module>
|
||||
<module name="ParenPad">
|
||||
<property name="option" value="nospace" />
|
||||
<property name="tokens" value="DOT,EXPR,QUESTION" />
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="option" value="eol" />
|
||||
<property name="tokens" value="COMMA,SEMI,ELLIPSIS,ARRAY_DECLARATOR,RBRACK,METHOD_REF" />
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="option" value="nl" />
|
||||
<property name="tokens" value="DOT,AT" />
|
||||
</module>
|
||||
<module name="SingleSpaceSeparator" />
|
||||
<module name="TypecastParenPad" />
|
||||
<module name="WhitespaceAfter">
|
||||
<property name="tokens" value="COMMA" />
|
||||
</module>
|
||||
<module name="WhitespaceAround">
|
||||
<property name="allowEmptyConstructors" value="true" />
|
||||
<property name="ignoreEnhancedForColon" value="false" />
|
||||
<property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,DO_WHILE,EQUAL,GE,GT,LAMBDA,LAND,LCURLY,LE,LITERAL_RETURN,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,RCURLY,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND" />
|
||||
</module>
|
||||
</module>
|
||||
|
||||
<module name="FileTabCharacter" />
|
||||
<module name="NewlineAtEndOfFile" />
|
||||
</module>
|
||||
|
||||
9
config/checkstyle/suppressions.xml
Normal file
9
config/checkstyle/suppressions.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
|
||||
"https://checkstyle.org/dtds/suppressions_1_2.dtd">
|
||||
<suppressions>
|
||||
<!-- All the config options and method fields. -->
|
||||
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraft.java" />
|
||||
<suppress checks="StaticVariableName" files=".*[\\/]ComputerCraftAPI.java" />
|
||||
</suppressions>
|
||||
3
config/license/api.txt
Normal file
3
config/license/api.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||
Copyright Daniel Ratcliffe, 2011-${year}. 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.
|
||||
3
config/license/main.txt
Normal file
3
config/license/main.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
This file is part of ComputerCraft - http://www.computercraft.info
|
||||
Copyright Daniel Ratcliffe, 2011-${year}. Do not distribute without permission.
|
||||
Send enquiries to dratcliffe@gmail.com
|
||||
@@ -1,5 +1,5 @@
|
||||
# Mod properties
|
||||
mod_version=1.82.2
|
||||
mod_version=1.84.0
|
||||
|
||||
# Minecraft properties
|
||||
mc_version=1.12.2
|
||||
|
||||
@@ -72,9 +72,7 @@ import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.SidedProxy;
|
||||
import net.minecraftforge.fml.common.*;
|
||||
import net.minecraftforge.fml.common.event.*;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -83,9 +81,7 @@ import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
@@ -394,6 +390,27 @@ public class ComputerCraft
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadFromFile( List<IMount> mounts, File file, String path, boolean allowMissing )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( file.isFile() )
|
||||
{
|
||||
mounts.add( new JarMount( file, path ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
File subResource = new File( file, path );
|
||||
if( subResource.exists() ) mounts.add( new FileMount( subResource, 0 ) );
|
||||
}
|
||||
}
|
||||
catch( IOException | RuntimeException e )
|
||||
{
|
||||
if( allowMissing && e instanceof FileNotFoundException ) return;
|
||||
ComputerCraft.log.error( "Could not load mount '" + path + " 'from '" + file.getName() + "'", e );
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static IMount createResourceMount( Class<?> modClass, String domain, String subPath )
|
||||
{
|
||||
@@ -413,18 +430,26 @@ public class ComputerCraft
|
||||
}
|
||||
}
|
||||
|
||||
// Mount from mod jar
|
||||
// Mount from mod jars, preferring the specified one.
|
||||
File modJar = getContainingJar( modClass );
|
||||
Set<File> otherMods = new HashSet<>();
|
||||
for( ModContainer container : Loader.instance().getActiveModList() )
|
||||
{
|
||||
File modFile = container.getSource();
|
||||
if( modFile != null && !modFile.equals( modJar ) && modFile.exists() )
|
||||
{
|
||||
otherMods.add( container.getSource() );
|
||||
}
|
||||
}
|
||||
|
||||
for( File file : otherMods )
|
||||
{
|
||||
loadFromFile( mounts, file, subPath, true );
|
||||
}
|
||||
|
||||
if( modJar != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
mounts.add( new JarMount( modJar, subPath ) );
|
||||
}
|
||||
catch( IOException | RuntimeException e )
|
||||
{
|
||||
ComputerCraft.log.error( "Could not load mount from mod jar", e );
|
||||
}
|
||||
loadFromFile( mounts, modJar, subPath, false );
|
||||
}
|
||||
|
||||
// Mount from resource packs
|
||||
@@ -434,28 +459,8 @@ public class ComputerCraft
|
||||
String[] resourcePacks = resourcePackDir.list();
|
||||
for( String resourcePackName : resourcePacks )
|
||||
{
|
||||
try
|
||||
{
|
||||
File resourcePack = new File( resourcePackDir, resourcePackName );
|
||||
if( !resourcePack.isDirectory() )
|
||||
{
|
||||
// Mount a resource pack from a jar
|
||||
mounts.add( new JarMount( resourcePack, subPath ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mount a resource pack from a folder
|
||||
File subResource = new File( resourcePack, subPath );
|
||||
if( subResource.exists() ) mounts.add( new FileMount( subResource, 0 ) );
|
||||
}
|
||||
}
|
||||
catch( FileNotFoundException ignored )
|
||||
{
|
||||
}
|
||||
catch( IOException | RuntimeException e )
|
||||
{
|
||||
ComputerCraft.log.error( "Could not load resource pack '" + resourcePackName + "'", e );
|
||||
}
|
||||
File resourcePack = new File( resourcePackDir, resourcePackName );
|
||||
loadFromFile( mounts, resourcePack, subPath, true );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. 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;
|
||||
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
|
||||
@@ -438,45 +438,45 @@ public final class ComputerCraftAPI
|
||||
computerCraft_getVersion = findCCMethod( "getVersion", new Class<?>[] {
|
||||
} );
|
||||
computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class<?>[] {
|
||||
World.class, String.class
|
||||
World.class, String.class,
|
||||
} );
|
||||
computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class<?>[] {
|
||||
World.class, String.class, Long.TYPE
|
||||
World.class, String.class, Long.TYPE,
|
||||
} );
|
||||
computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class<?>[] {
|
||||
Class.class, String.class, String.class
|
||||
Class.class, String.class, String.class,
|
||||
} );
|
||||
computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class<?>[] {
|
||||
IPeripheralProvider.class
|
||||
IPeripheralProvider.class,
|
||||
} );
|
||||
computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class<?>[] {
|
||||
ITurtleUpgrade.class
|
||||
ITurtleUpgrade.class,
|
||||
} );
|
||||
computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class<?>[] {
|
||||
IBundledRedstoneProvider.class
|
||||
IBundledRedstoneProvider.class,
|
||||
} );
|
||||
computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class<?>[] {
|
||||
World.class, BlockPos.class, EnumFacing.class
|
||||
World.class, BlockPos.class, EnumFacing.class,
|
||||
} );
|
||||
computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class<?>[] {
|
||||
IMediaProvider.class
|
||||
IMediaProvider.class,
|
||||
} );
|
||||
computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class<?>[] {
|
||||
ITurtlePermissionProvider.class
|
||||
ITurtlePermissionProvider.class,
|
||||
} );
|
||||
computerCraft_registerPocketUpgrade = findCCMethod( "registerPocketUpgrade", new Class<?>[] {
|
||||
IPocketUpgrade.class
|
||||
IPocketUpgrade.class,
|
||||
} );
|
||||
computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class<?>[] {
|
||||
} );
|
||||
computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class<?>[] {
|
||||
ILuaAPIFactory.class
|
||||
ILuaAPIFactory.class,
|
||||
} );
|
||||
computerCraft_createWiredNodeForElement = findCCMethod( "createWiredNodeForElement", new Class<?>[] {
|
||||
IWiredElement.class
|
||||
IWiredElement.class,
|
||||
} );
|
||||
computerCraft_getWiredElementAt = findCCMethod( "getWiredElementAt", new Class<?>[] {
|
||||
IBlockAccess.class, BlockPos.class, EnumFacing.class
|
||||
IBlockAccess.class, BlockPos.class, EnumFacing.class,
|
||||
} );
|
||||
}
|
||||
catch( Exception e )
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. 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.filesystem;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* An {@link IOException} which occurred on a specific file.
|
||||
*
|
||||
* This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure.
|
||||
*/
|
||||
public class FileOperationException extends IOException
|
||||
{
|
||||
private static final long serialVersionUID = -8809108200853029849L;
|
||||
|
||||
private final String filename;
|
||||
|
||||
public FileOperationException( @Nullable String filename, @Nonnull String message )
|
||||
{
|
||||
super( Objects.requireNonNull( message, "message cannot be null" ) );
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public FileOperationException( String message )
|
||||
{
|
||||
super( Objects.requireNonNull( message, "message cannot be null" ) );
|
||||
this.filename = null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getFilename()
|
||||
{
|
||||
return filename;
|
||||
}
|
||||
}
|
||||
@@ -90,7 +90,6 @@ public interface IMount
|
||||
* @throws IOException If the file does not exist, or could not be opened.
|
||||
*/
|
||||
@Nonnull
|
||||
@SuppressWarnings( "deprecation" )
|
||||
default ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
|
||||
{
|
||||
return Channels.newChannel( openForRead( path ) );
|
||||
|
||||
@@ -67,7 +67,6 @@ public interface IWritableMount extends IMount
|
||||
* @throws IOException If the file could not be opened for writing.
|
||||
*/
|
||||
@Nonnull
|
||||
@SuppressWarnings( "deprecation" )
|
||||
default WritableByteChannel openChannelForWrite( @Nonnull String path ) throws IOException
|
||||
{
|
||||
return Channels.newChannel( openForWrite( path ) );
|
||||
@@ -94,7 +93,6 @@ public interface IWritableMount extends IMount
|
||||
* @throws IOException If the file could not be opened for writing.
|
||||
*/
|
||||
@Nonnull
|
||||
@SuppressWarnings( "deprecation" )
|
||||
default WritableByteChannel openChannelForAppend( @Nonnull String path ) throws IOException
|
||||
{
|
||||
return Channels.newChannel( openForAppend( path ) );
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. 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.peripheral;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. 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.pocket;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
@@ -145,7 +145,9 @@ public interface ITurtleAccess
|
||||
GameProfile getOwningPlayer();
|
||||
|
||||
/**
|
||||
* Get the inventory of this turtle
|
||||
* Get the inventory of this turtle.
|
||||
*
|
||||
* Note: this inventory should only be accessed and modified on the server thread.
|
||||
*
|
||||
* @return This turtle's inventory
|
||||
* @see #getItemHandler()
|
||||
@@ -156,6 +158,8 @@ public interface ITurtleAccess
|
||||
/**
|
||||
* Get the inventory of this turtle as an {@link IItemHandlerModifiable}.
|
||||
*
|
||||
* Note: this inventory should only be accessed and modified on the server thread.
|
||||
*
|
||||
* @return This turtle's inventory
|
||||
* @see #getInventory()
|
||||
* @see IItemHandlerModifiable
|
||||
|
||||
@@ -109,8 +109,8 @@ public interface ITurtleUpgrade
|
||||
* Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called
|
||||
* by the turtle, and the tool is required to do some work.
|
||||
*
|
||||
* Conforming implementations should fire {@link BlockEvent.BreakEvent} and {@link TurtleBlockEvent.Dig}for digging,
|
||||
* {@link AttackEntityEvent} and {@link TurtleAttackEvent} for attacking.
|
||||
* Conforming implementations should fire {@link BlockEvent.BreakEvent} and {@link TurtleBlockEvent.Dig} for
|
||||
* digging, {@link AttackEntityEvent} and {@link TurtleAttackEvent} for attacking.
|
||||
*
|
||||
* @param turtle Access to the turtle that the tool resides on.
|
||||
* @param side Which side of the turtle (left or right) the tool resides on.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. 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.turtle.event;
|
||||
|
||||
import dan200.computercraft.api.lua.ILuaContext;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
* This file is part of the public ComputerCraft API - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. 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.turtle.event;
|
||||
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
|
||||
@@ -24,9 +24,10 @@ import java.io.IOException;
|
||||
|
||||
public class GuiComputer extends GuiContainer
|
||||
{
|
||||
private static final ResourceLocation BACKGROUND = new ResourceLocation( "computercraft", "textures/gui/corners.png" );
|
||||
private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( "computercraft", "textures/gui/corners_advanced.png" );
|
||||
private static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( "computercraft", "textures/gui/corners_command.png" );
|
||||
public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners.png" );
|
||||
public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_advanced.png" );
|
||||
public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_command.png" );
|
||||
public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation( ComputerCraft.MOD_ID, "textures/gui/corners_colour.png" );
|
||||
|
||||
private final ComputerFamily m_family;
|
||||
private final ClientComputer m_computer;
|
||||
@@ -158,7 +159,7 @@ public class GuiComputer extends GuiContainer
|
||||
{
|
||||
case Normal:
|
||||
default:
|
||||
mc.getTextureManager().bindTexture( BACKGROUND );
|
||||
mc.getTextureManager().bindTexture( BACKGROUND_NORMAL );
|
||||
break;
|
||||
case Advanced:
|
||||
mc.getTextureManager().bindTexture( BACKGROUND_ADVANCED );
|
||||
@@ -169,12 +170,12 @@ public class GuiComputer extends GuiContainer
|
||||
}
|
||||
|
||||
drawTexturedModalRect( startX - 12, startY - 12, 12, 28, 12, 12 );
|
||||
drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 16 );
|
||||
drawTexturedModalRect( startX - 12, endY, 12, 40, 12, 12 );
|
||||
drawTexturedModalRect( endX, startY - 12, 24, 28, 12, 12 );
|
||||
drawTexturedModalRect( endX, endY, 24, 40, 12, 16 );
|
||||
drawTexturedModalRect( endX, endY, 24, 40, 12, 12 );
|
||||
|
||||
drawTexturedModalRect( startX, startY - 12, 0, 0, endX - startX, 12 );
|
||||
drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 16 );
|
||||
drawTexturedModalRect( startX, endY, 0, 12, endX - startX, 12 );
|
||||
|
||||
drawTexturedModalRect( startX - 12, startY, 0, 28, 12, endY - startY );
|
||||
drawTexturedModalRect( endX, startY, 36, 28, 12, endY - startY );
|
||||
|
||||
@@ -120,7 +120,7 @@ public class GuiTurtle extends GuiContainer
|
||||
int slotX = slot % 4;
|
||||
int slotY = slot / 4;
|
||||
mc.getTextureManager().bindTexture( advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL );
|
||||
drawTexturedModalRect( guiLeft + m_container.m_turtleInvStartX - 2 + slotX * 18, guiTop + m_container.m_playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 );
|
||||
drawTexturedModalRect( guiLeft + m_container.turtleInvStartX - 2 + slotX * 18, guiTop + m_container.playerInvStartY - 2 + slotY * 18, 0, 217, 24, 24 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,13 @@ import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
|
||||
public final class RenderOverlayCable
|
||||
public final class CableHighlightRenderer
|
||||
{
|
||||
private static final float EXPAND = 0.002f;
|
||||
private static final double MIN = CableBounds.MIN - EXPAND;
|
||||
private static final double MAX = CableBounds.MAX + EXPAND;
|
||||
|
||||
private RenderOverlayCable()
|
||||
private CableHighlightRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -12,25 +12,24 @@ import dan200.computercraft.client.gui.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.computer.core.ClientComputer;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.pocket.items.ItemPocketComputer;
|
||||
import dan200.computercraft.shared.util.Colour;
|
||||
import dan200.computercraft.shared.util.Palette;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.RenderItem;
|
||||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.renderer.texture.TextureMap;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.event.RenderSpecificHandEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
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.*;
|
||||
import static dan200.computercraft.client.gui.GuiComputer.*;
|
||||
|
||||
/**
|
||||
* Emulates map rendering for pocket computers
|
||||
@@ -38,6 +37,10 @@ import static dan200.computercraft.client.gui.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
|
||||
public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
||||
{
|
||||
private static final int MARGIN = 2;
|
||||
private static final int FRAME = 12;
|
||||
private static final int LIGHT_HEIGHT = 8;
|
||||
|
||||
private static final ItemPocketRenderer INSTANCE = new ItemPocketRenderer();
|
||||
|
||||
private ItemPocketRenderer()
|
||||
@@ -57,115 +60,194 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer
|
||||
@Override
|
||||
protected void renderItem( ItemStack stack )
|
||||
{
|
||||
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
|
||||
Terminal terminal = computer == null ? null : computer.getTerminal();
|
||||
|
||||
int termWidth, termHeight;
|
||||
if( terminal == null )
|
||||
{
|
||||
termWidth = ComputerCraft.terminalWidth_pocketComputer;
|
||||
termHeight = ComputerCraft.terminalHeight_pocketComputer;
|
||||
}
|
||||
else
|
||||
{
|
||||
termWidth = terminal.getWidth();
|
||||
termHeight = terminal.getHeight();
|
||||
}
|
||||
|
||||
int width = termWidth * FONT_WIDTH + MARGIN * 2;
|
||||
int height = termHeight * FONT_HEIGHT + MARGIN * 2;
|
||||
|
||||
// Setup various transformations. Note that these are partially adapted from the corresponding method
|
||||
// in ItemRenderer
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
GlStateManager.disableLighting();
|
||||
GlStateManager.disableDepth();
|
||||
|
||||
GlStateManager.rotate( 180f, 0f, 1f, 0f );
|
||||
GlStateManager.rotate( 180f, 0f, 0f, 1f );
|
||||
GlStateManager.scale( 0.5, 0.5, 0.5 );
|
||||
|
||||
ClientComputer computer = ItemPocketComputer.createClientComputer( stack );
|
||||
double scale = 0.75 / Math.max( width + FRAME * 2, height + FRAME * 2 + LIGHT_HEIGHT );
|
||||
GlStateManager.scale( scale, scale, 0 );
|
||||
GlStateManager.translate( -0.5 * width, -0.5 * height, 0 );
|
||||
|
||||
// Render the main frame
|
||||
ComputerFamily family = ComputerCraft.Items.pocketComputer.getFamily( stack );
|
||||
int frameColour = ComputerCraft.Items.pocketComputer.getColour( stack );
|
||||
renderFrame( family, frameColour, width, height );
|
||||
|
||||
// Render the light
|
||||
int lightColour = ItemPocketComputer.getLightState( stack );
|
||||
if( lightColour == -1 ) lightColour = Colour.Black.getHex();
|
||||
renderLight( lightColour, width, height );
|
||||
|
||||
if( computer != null && terminal != null )
|
||||
{
|
||||
// First render the background item. We use the item's model rather than a direct texture as this ensures
|
||||
// we display the pocket light and other such decorations.
|
||||
GlStateManager.pushMatrix();
|
||||
// If we've a computer and terminal then attempt to render it.
|
||||
renderTerminal( terminal, !computer.isColour(), width, height );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise render a plain background
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture( BACKGROUND );
|
||||
|
||||
GlStateManager.scale( 1.0f, -1.0f, 1.0f );
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
|
||||
Minecraft minecraft = Minecraft.getMinecraft();
|
||||
TextureManager textureManager = minecraft.getTextureManager();
|
||||
RenderItem renderItem = minecraft.getRenderItem();
|
||||
|
||||
// Copy of RenderItem#renderItemModelIntoGUI but without the translation or scaling
|
||||
textureManager.bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
|
||||
textureManager.getTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ).setBlurMipmap( false, false );
|
||||
|
||||
GlStateManager.enableRescaleNormal();
|
||||
GlStateManager.enableAlpha();
|
||||
GlStateManager.alphaFunc( GL11.GL_GREATER, 0.1F );
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.blendFunc( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA );
|
||||
GlStateManager.color( 1.0F, 1.0F, 1.0F, 1.0F );
|
||||
|
||||
IBakedModel baked = renderItem.getItemModelWithOverrides( stack, null, null );
|
||||
baked = ForgeHooksClient.handleCameraTransforms( baked, ItemCameraTransforms.TransformType.GUI, false );
|
||||
renderItem.renderItem( stack, baked );
|
||||
|
||||
GlStateManager.disableAlpha();
|
||||
GlStateManager.disableRescaleNormal();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
Colour black = Colour.Black;
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION );
|
||||
renderTexture( buffer, 0, 0, 0, 0, width, height, black.getR(), black.getG(), black.getB() );
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
// If we've a computer and terminal then attempt to render it.
|
||||
if( computer != null )
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.enableLighting();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
|
||||
private static void renderFrame( ComputerFamily family, int colour, int width, int height )
|
||||
{
|
||||
|
||||
Minecraft.getMinecraft().getTextureManager().bindTexture( colour != -1
|
||||
? BACKGROUND_COLOUR
|
||||
: family == ComputerFamily.Normal ? BACKGROUND_NORMAL : BACKGROUND_ADVANCED
|
||||
);
|
||||
|
||||
float r = ((colour >>> 16) & 0xFF) / 255.0f;
|
||||
float g = ((colour >>> 8) & 0xFF) / 255.0f;
|
||||
float b = (colour & 0xFF) / 255.0f;
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR );
|
||||
|
||||
// Top left, middle, right
|
||||
renderTexture( buffer, -FRAME, -FRAME, 12, 28, FRAME, FRAME, r, g, b );
|
||||
renderTexture( buffer, 0, -FRAME, 0, 0, width, FRAME, r, g, b );
|
||||
renderTexture( buffer, width, -FRAME, 24, 28, FRAME, FRAME, r, g, b );
|
||||
|
||||
// Left and bright border
|
||||
renderTexture( buffer, -FRAME, 0, 0, 28, FRAME, height, r, g, b );
|
||||
renderTexture( buffer, width, 0, 36, 28, FRAME, height, r, g, b );
|
||||
|
||||
// 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( buffer, -FRAME, height, 12, 40, FRAME, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, 0, height, 0, 12, width, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, width, height, 24, 40, FRAME, FRAME / 2, r, g, b );
|
||||
|
||||
renderTexture( buffer, -FRAME, height + FRAME / 2, 12, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
|
||||
renderTexture( buffer, 0, height + FRAME / 2, 0, 16, width, LIGHT_HEIGHT, FRAME, 4, r, g, b );
|
||||
renderTexture( buffer, width, height + FRAME / 2, 24, 44, FRAME, LIGHT_HEIGHT, FRAME, 4, r, g, b );
|
||||
|
||||
renderTexture( buffer, -FRAME, height + LIGHT_HEIGHT + FRAME / 2, 12, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, 0, height + LIGHT_HEIGHT + FRAME / 2, 0, 12 + FRAME / 2, width, FRAME / 2, r, g, b );
|
||||
renderTexture( buffer, width, height + LIGHT_HEIGHT + FRAME / 2, 24, 40 + FRAME / 2, FRAME, FRAME / 2, r, g, b );
|
||||
|
||||
tessellator.draw();
|
||||
}
|
||||
|
||||
private static void renderLight( int colour, int width, int height )
|
||||
{
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.disableTexture2D();
|
||||
|
||||
float r = ((colour >>> 16) & 0xFF) / 255.0f;
|
||||
float g = ((colour >>> 8) & 0xFF) / 255.0f;
|
||||
float b = (colour & 0xFF) / 255.0f;
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin( GL11.GL_QUADS, DefaultVertexFormats.POSITION_COLOR );
|
||||
buffer.pos( width - LIGHT_HEIGHT * 2, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.pos( width, height + LIGHT_HEIGHT + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.pos( width, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
buffer.pos( width - LIGHT_HEIGHT * 2, height + FRAME / 2.0f, 0.0D ).color( r, g, b, 1.0f ).endVertex();
|
||||
|
||||
tessellator.draw();
|
||||
GlStateManager.enableTexture2D();
|
||||
}
|
||||
|
||||
private static void renderTerminal( Terminal terminal, boolean greyscale, int width, int height )
|
||||
{
|
||||
synchronized( terminal )
|
||||
{
|
||||
Terminal terminal = computer.getTerminal();
|
||||
if( terminal != null )
|
||||
int termWidth = terminal.getWidth();
|
||||
int termHeight = terminal.getHeight();
|
||||
|
||||
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
|
||||
Palette palette = terminal.getPalette();
|
||||
|
||||
// Render top/bottom borders
|
||||
TextBuffer emptyLine = new TextBuffer( ' ', termWidth );
|
||||
fontRenderer.drawString(
|
||||
emptyLine, MARGIN, 0,
|
||||
terminal.getTextColourLine( 0 ), terminal.getBackgroundColourLine( 0 ), MARGIN, MARGIN, greyscale, palette
|
||||
);
|
||||
fontRenderer.drawString(
|
||||
emptyLine, MARGIN, 2 * MARGIN + (termHeight - 1) * FixedWidthFontRenderer.FONT_HEIGHT,
|
||||
terminal.getTextColourLine( termHeight - 1 ), terminal.getBackgroundColourLine( termHeight - 1 ), MARGIN, MARGIN, greyscale, palette
|
||||
);
|
||||
|
||||
// Render the actual text
|
||||
for( int line = 0; line < termWidth; line++ )
|
||||
{
|
||||
synchronized( terminal )
|
||||
{
|
||||
GlStateManager.pushMatrix();
|
||||
GlStateManager.disableDepth();
|
||||
TextBuffer text = terminal.getLine( line );
|
||||
TextBuffer colour = terminal.getTextColourLine( line );
|
||||
TextBuffer backgroundColour = terminal.getBackgroundColourLine( line );
|
||||
fontRenderer.drawString(
|
||||
text, MARGIN, MARGIN + line * FONT_HEIGHT,
|
||||
colour, backgroundColour, MARGIN, MARGIN, greyscale, palette
|
||||
);
|
||||
}
|
||||
|
||||
// Reset the position to be at the top left corner of the pocket computer
|
||||
// Note we translate towards the screen slightly too.
|
||||
GlStateManager.translate( -8 / 16.0, -8 / 16.0, 0.5 / 16.0 );
|
||||
// Translate to the top left of the screen.
|
||||
GlStateManager.translate( 4 / 16.0, 3 / 16.0, 0 );
|
||||
|
||||
// Work out the scaling required to resize the terminal in order to fit on the computer
|
||||
final int margin = 2;
|
||||
int tw = terminal.getWidth();
|
||||
int th = terminal.getHeight();
|
||||
int width = tw * FONT_WIDTH + margin * 2;
|
||||
int height = th * FONT_HEIGHT + margin * 2;
|
||||
int max = Math.max( height, width );
|
||||
|
||||
// The grid is 8 * 8 wide, so we start with a base of 1/2 (8 / 16).
|
||||
double scale = 1.0 / 2.0 / max;
|
||||
GlStateManager.scale( scale, scale, scale );
|
||||
|
||||
// The margin/start positions are determined in order for the terminal to be centred.
|
||||
int startX = (max - width) / 2 + margin;
|
||||
int startY = (max - height) / 2 + margin;
|
||||
|
||||
FixedWidthFontRenderer fontRenderer = FixedWidthFontRenderer.instance();
|
||||
boolean greyscale = !computer.isColour();
|
||||
Palette palette = terminal.getPalette();
|
||||
|
||||
// Render the actual text
|
||||
for( int line = 0; line < th; line++ )
|
||||
{
|
||||
TextBuffer text = terminal.getLine( line );
|
||||
TextBuffer colour = terminal.getTextColourLine( line );
|
||||
TextBuffer backgroundColour = terminal.getBackgroundColourLine( line );
|
||||
fontRenderer.drawString(
|
||||
text, startX, startY + line * FONT_HEIGHT,
|
||||
colour, backgroundColour, margin, margin, greyscale, palette
|
||||
);
|
||||
}
|
||||
|
||||
// And render the cursor;
|
||||
int tx = terminal.getCursorX(), ty = terminal.getCursorY();
|
||||
if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() &&
|
||||
tx >= 0 && ty >= 0 && tx < tw && ty < th )
|
||||
{
|
||||
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );
|
||||
fontRenderer.drawString(
|
||||
new TextBuffer( '_', 1 ), startX + FONT_WIDTH * tx, startY + FONT_HEIGHT * ty,
|
||||
cursorColour, null, 0, 0, greyscale, palette
|
||||
);
|
||||
}
|
||||
|
||||
GlStateManager.enableDepth();
|
||||
GlStateManager.popMatrix();
|
||||
}
|
||||
// And render the cursor;
|
||||
int tx = terminal.getCursorX(), ty = terminal.getCursorY();
|
||||
if( terminal.getCursorBlink() && FrameInfo.getGlobalCursorBlink() &&
|
||||
tx >= 0 && ty >= 0 && tx < termWidth && ty < termHeight )
|
||||
{
|
||||
TextBuffer cursorColour = new TextBuffer( "0123456789abcdef".charAt( terminal.getTextColour() ), 1 );
|
||||
fontRenderer.drawString(
|
||||
new TextBuffer( '_', 1 ), MARGIN + FONT_WIDTH * tx, MARGIN + FONT_HEIGHT * ty,
|
||||
cursorColour, null, 0, 0, greyscale, palette
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GlStateManager.enableLighting();
|
||||
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, float r, float g, float b )
|
||||
{
|
||||
renderTexture( builder, x, y, textureX, textureY, width, height, width, height, r, g, b );
|
||||
}
|
||||
|
||||
private static void renderTexture( BufferBuilder builder, int x, int y, int textureX, int textureY, int width, int height, int textureWidth, int textureHeight, float r, float g, float b )
|
||||
{
|
||||
float scale = 1 / 255.0f;
|
||||
builder.pos( x, y + height, 0 ).tex( textureX * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
builder.pos( x + width, y + height, 0 ).tex( (textureX + textureWidth) * scale, (textureY + textureHeight) * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
builder.pos( x + width, y, 0 ).tex( (textureX + textureWidth) * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
builder.pos( x, y, 0 ).tex( textureX * scale, textureY * scale ).color( r, g, b, 1.0f ).endVertex();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public final class ModelTransformer
|
||||
private final Point3f[] before = new Point3f[4];
|
||||
private final Point3f[] after = new Point3f[4];
|
||||
|
||||
public NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix )
|
||||
NormalAwareTransformer( IVertexConsumer parent, Matrix4f positionMatrix, Matrix4f normalMatrix )
|
||||
{
|
||||
super( parent );
|
||||
this.positionMatrix = positionMatrix;
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.shared.peripheral.monitor.TileMonitor;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import static net.minecraft.util.EnumFacing.*;
|
||||
|
||||
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Side.CLIENT )
|
||||
public final class MonitorHighlightRenderer
|
||||
{
|
||||
private static final float EXPAND = 0.002f;
|
||||
|
||||
private MonitorHighlightRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void drawHighlight( DrawBlockHighlightEvent event )
|
||||
{
|
||||
if( event.getTarget().typeOfHit != RayTraceResult.Type.BLOCK || event.getPlayer().isSneaking() ) return;
|
||||
|
||||
World world = event.getPlayer().getEntityWorld();
|
||||
BlockPos pos = event.getTarget().getBlockPos();
|
||||
|
||||
if( world.getBlockState( pos ).getBlock() != ComputerCraft.Blocks.peripheral ) return;
|
||||
|
||||
TileEntity tile = world.getTileEntity( pos );
|
||||
if( !(tile instanceof TileMonitor) ) return;
|
||||
|
||||
TileMonitor monitor = (TileMonitor) tile;
|
||||
event.setCanceled( true );
|
||||
|
||||
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
|
||||
EnumSet<EnumFacing> faces = EnumSet.allOf( EnumFacing.class );
|
||||
EnumFacing front = monitor.getFront();
|
||||
faces.remove( front );
|
||||
if( monitor.getXIndex() != 0 ) faces.remove( monitor.getRight().getOpposite() );
|
||||
if( monitor.getXIndex() != monitor.getWidth() - 1 ) faces.remove( monitor.getRight() );
|
||||
if( monitor.getYIndex() != 0 ) faces.remove( monitor.getDown().getOpposite() );
|
||||
if( monitor.getYIndex() != monitor.getHeight() - 1 ) faces.remove( monitor.getDown() );
|
||||
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate( GlStateManager.SourceFactor.SRC_ALPHA, GlStateManager.DestFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ZERO );
|
||||
GL11.glLineWidth( 2.0F );
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.depthMask( false );
|
||||
GlStateManager.pushMatrix();
|
||||
|
||||
EntityPlayer player = event.getPlayer();
|
||||
double x = player.lastTickPosX + (player.posX - player.lastTickPosX) * event.getPartialTicks();
|
||||
double y = player.lastTickPosY + (player.posY - player.lastTickPosY) * event.getPartialTicks();
|
||||
double z = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * event.getPartialTicks();
|
||||
|
||||
GlStateManager.translate( -x + pos.getX(), -y + pos.getY(), -z + pos.getZ() );
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
BufferBuilder buffer = tessellator.getBuffer();
|
||||
buffer.begin( GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR );
|
||||
|
||||
// I wish I could think of a better way to do this
|
||||
if( faces.contains( NORTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 0, UP );
|
||||
if( faces.contains( SOUTH ) || faces.contains( WEST ) ) line( buffer, 0, 0, 1, UP );
|
||||
if( faces.contains( NORTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 0, UP );
|
||||
if( faces.contains( SOUTH ) || faces.contains( EAST ) ) line( buffer, 1, 0, 1, UP );
|
||||
if( faces.contains( NORTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, EAST );
|
||||
if( faces.contains( SOUTH ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 1, EAST );
|
||||
if( faces.contains( NORTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, EAST );
|
||||
if( faces.contains( SOUTH ) || faces.contains( UP ) ) line( buffer, 0, 1, 1, EAST );
|
||||
if( faces.contains( WEST ) || faces.contains( DOWN ) ) line( buffer, 0, 0, 0, SOUTH );
|
||||
if( faces.contains( EAST ) || faces.contains( DOWN ) ) line( buffer, 1, 0, 0, SOUTH );
|
||||
if( faces.contains( WEST ) || faces.contains( UP ) ) line( buffer, 0, 1, 0, SOUTH );
|
||||
if( faces.contains( EAST ) || faces.contains( UP ) ) line( buffer, 1, 1, 0, SOUTH );
|
||||
|
||||
tessellator.draw();
|
||||
|
||||
GlStateManager.popMatrix();
|
||||
GlStateManager.depthMask( true );
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.disableBlend();
|
||||
}
|
||||
|
||||
private static void line( BufferBuilder buffer, int x, int y, int z, EnumFacing direction )
|
||||
{
|
||||
double minX = x == 0 ? -EXPAND : 1 + EXPAND;
|
||||
double minY = y == 0 ? -EXPAND : 1 + EXPAND;
|
||||
double minZ = z == 0 ? -EXPAND : 1 + EXPAND;
|
||||
|
||||
buffer.pos( minX, minY, minZ ).color( 0, 0, 0, 0.4f ).endVertex();
|
||||
buffer.pos(
|
||||
minX + direction.getXOffset() * (1 + EXPAND * 2),
|
||||
minY + direction.getYOffset() * (1 + EXPAND * 2),
|
||||
minZ + direction.getZOffset() * (1 + EXPAND * 2)
|
||||
).color( 0, 0, 0, 0.4f ).endVertex();
|
||||
}
|
||||
}
|
||||
@@ -43,9 +43,7 @@ public class FSAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"fs"
|
||||
};
|
||||
return new String[] { "fs" };
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,9 +42,7 @@ public class HTTPAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"http"
|
||||
};
|
||||
return new String[] { "http" };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,6 +81,7 @@ public class HTTPAPI implements ILuaAPI
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "resource" )
|
||||
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
|
||||
{
|
||||
switch( method )
|
||||
@@ -95,7 +94,7 @@ public class HTTPAPI implements ILuaAPI
|
||||
|
||||
if( args.length >= 1 && args[0] instanceof Map )
|
||||
{
|
||||
Map<?, ?> options = (Map) args[0];
|
||||
Map<?, ?> options = (Map<?, ?>) args[0];
|
||||
address = getStringField( options, "url" );
|
||||
postString = optStringField( options, "body", null );
|
||||
headerTable = optTableField( options, "headers", Collections.emptyMap() );
|
||||
@@ -135,7 +134,6 @@ public class HTTPAPI implements ILuaAPI
|
||||
try
|
||||
{
|
||||
URI uri = HttpRequest.checkUri( address );
|
||||
|
||||
HttpRequest request = new HttpRequest( requests, m_apiEnvironment, address, postString, headers, binary, redirect );
|
||||
|
||||
long requestBody = request.body().readableBytes() + HttpRequest.getHeaderSize( headers );
|
||||
|
||||
@@ -10,6 +10,7 @@ package dan200.computercraft.core.apis;
|
||||
* This exists purely to ensure binary compatibility.
|
||||
*
|
||||
* @see dan200.computercraft.api.lua.ILuaAPI
|
||||
* @deprecated Use the version in the public API. Only exists for compatibility with CCEmuX.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ILuaAPI extends dan200.computercraft.api.lua.ILuaAPI
|
||||
|
||||
281
src/main/java/dan200/computercraft/core/apis/LuaDateTime.java
Normal file
281
src/main/java/dan200/computercraft/core/apis/LuaDateTime.java
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.core.apis;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.TextStyle;
|
||||
import java.time.temporal.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.LongUnaryOperator;
|
||||
|
||||
final class LuaDateTime
|
||||
{
|
||||
private LuaDateTime()
|
||||
{
|
||||
}
|
||||
|
||||
static void format( DateTimeFormatterBuilder formatter, String format, ZoneOffset offset ) throws LuaException
|
||||
{
|
||||
for( int i = 0; i < format.length(); )
|
||||
{
|
||||
char c;
|
||||
switch( c = format.charAt( i++ ) )
|
||||
{
|
||||
case '\n':
|
||||
formatter.appendLiteral( '\n' );
|
||||
break;
|
||||
default:
|
||||
formatter.appendLiteral( c );
|
||||
break;
|
||||
case '%':
|
||||
if( i >= format.length() ) break;
|
||||
switch( c = format.charAt( i++ ) )
|
||||
{
|
||||
default:
|
||||
throw new LuaException( "bad argument #1: invalid conversion specifier '%" + c + "'" );
|
||||
|
||||
case '%':
|
||||
formatter.appendLiteral( '%' );
|
||||
break;
|
||||
case 'a':
|
||||
formatter.appendText( ChronoField.DAY_OF_WEEK, TextStyle.SHORT );
|
||||
break;
|
||||
case 'A':
|
||||
formatter.appendText( ChronoField.DAY_OF_WEEK, TextStyle.FULL );
|
||||
break;
|
||||
case 'b':
|
||||
case 'h':
|
||||
formatter.appendText( ChronoField.MONTH_OF_YEAR, TextStyle.SHORT );
|
||||
break;
|
||||
case 'B':
|
||||
formatter.appendText( ChronoField.MONTH_OF_YEAR, TextStyle.FULL );
|
||||
break;
|
||||
case 'c':
|
||||
format( formatter, "%a %b %e %H:%M:%S %Y", offset );
|
||||
break;
|
||||
case 'C':
|
||||
formatter.appendValueReduced( CENTURY, 2, 2, 0 );
|
||||
break;
|
||||
case 'd':
|
||||
formatter.appendValue( ChronoField.DAY_OF_MONTH, 2 );
|
||||
break;
|
||||
case 'D':
|
||||
case 'x':
|
||||
format( formatter, "%m/%d/%y", offset );
|
||||
break;
|
||||
case 'e':
|
||||
formatter.padNext( 2 ).appendValue( ChronoField.DAY_OF_MONTH );
|
||||
break;
|
||||
case 'F':
|
||||
format( formatter, "%Y-%m-%d", offset );
|
||||
break;
|
||||
case 'g':
|
||||
formatter.appendValueReduced( IsoFields.WEEK_BASED_YEAR, 2, 2, 0 );
|
||||
break;
|
||||
case 'G':
|
||||
formatter.appendValue( IsoFields.WEEK_BASED_YEAR );
|
||||
break;
|
||||
case 'H':
|
||||
formatter.appendValue( ChronoField.HOUR_OF_DAY, 2 );
|
||||
break;
|
||||
case 'I':
|
||||
formatter.appendValue( ChronoField.HOUR_OF_AMPM );
|
||||
break;
|
||||
case 'j':
|
||||
formatter.appendValue( ChronoField.DAY_OF_YEAR, 3 );
|
||||
break;
|
||||
case 'm':
|
||||
formatter.appendValue( ChronoField.MONTH_OF_YEAR, 2 );
|
||||
break;
|
||||
case 'M':
|
||||
formatter.appendValue( ChronoField.MINUTE_OF_HOUR, 2 );
|
||||
break;
|
||||
case 'n':
|
||||
formatter.appendLiteral( '\n' );
|
||||
break;
|
||||
case 'p':
|
||||
formatter.appendText( ChronoField.AMPM_OF_DAY );
|
||||
break;
|
||||
case 'r':
|
||||
format( formatter, "%I:%M:%S %p", offset );
|
||||
break;
|
||||
case 'R':
|
||||
format( formatter, "%H:%M", offset );
|
||||
break;
|
||||
case 'S':
|
||||
formatter.appendValue( ChronoField.SECOND_OF_MINUTE, 2 );
|
||||
break;
|
||||
case 't':
|
||||
formatter.appendLiteral( '\t' );
|
||||
break;
|
||||
case 'T':
|
||||
case 'X':
|
||||
format( formatter, "%H:%M:%S", offset );
|
||||
break;
|
||||
case 'u':
|
||||
formatter.appendValue( ChronoField.DAY_OF_WEEK );
|
||||
break;
|
||||
case 'U':
|
||||
formatter.appendValue( ChronoField.ALIGNED_WEEK_OF_YEAR, 2 );
|
||||
break;
|
||||
case 'V':
|
||||
formatter.appendValue( IsoFields.WEEK_OF_WEEK_BASED_YEAR, 2 );
|
||||
break;
|
||||
case 'w':
|
||||
formatter.appendValue( ZERO_WEEK );
|
||||
break;
|
||||
case 'W':
|
||||
formatter.appendValue( WeekFields.ISO.weekOfYear(), 2 );
|
||||
break;
|
||||
case 'y':
|
||||
formatter.appendValueReduced( ChronoField.YEAR, 2, 2, 0 );
|
||||
break;
|
||||
case 'Y':
|
||||
formatter.appendValue( ChronoField.YEAR );
|
||||
break;
|
||||
case 'z':
|
||||
formatter.appendOffset( "+HHMM", "+0000" );
|
||||
break;
|
||||
case 'Z':
|
||||
formatter.appendChronologyId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static long fromTable( Map<?, ?> table ) throws LuaException
|
||||
{
|
||||
int year = getField( table, "year", -1 );
|
||||
int month = getField( table, "month", -1 );
|
||||
int day = getField( table, "day", -1 );
|
||||
int hour = getField( table, "hour", 12 );
|
||||
int minute = getField( table, "min", 12 );
|
||||
int second = getField( table, "sec", 12 );
|
||||
LocalDateTime time = LocalDateTime.of( year, month, day, hour, minute, second );
|
||||
|
||||
Boolean isDst = getBoolField( table, "isdst" );
|
||||
if( isDst != null )
|
||||
{
|
||||
boolean requireDst = isDst;
|
||||
for( ZoneOffset possibleOffset : ZoneOffset.systemDefault().getRules().getValidOffsets( time ) )
|
||||
{
|
||||
Instant instant = time.toInstant( possibleOffset );
|
||||
if( possibleOffset.getRules().getDaylightSavings( instant ).isZero() == requireDst )
|
||||
{
|
||||
return instant.getEpochSecond();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZoneOffset offset = ZoneOffset.systemDefault().getRules().getOffset( time );
|
||||
return time.toInstant( offset ).getEpochSecond();
|
||||
}
|
||||
|
||||
static Map<String, ?> toTable( TemporalAccessor date, ZoneId offset, Instant instant )
|
||||
{
|
||||
HashMap<String, Object> table = new HashMap<>( 9 );
|
||||
table.put( "year", date.getLong( ChronoField.YEAR ) );
|
||||
table.put( "month", date.getLong( ChronoField.MONTH_OF_YEAR ) );
|
||||
table.put( "day", date.getLong( ChronoField.DAY_OF_MONTH ) );
|
||||
table.put( "hour", date.getLong( ChronoField.HOUR_OF_DAY ) );
|
||||
table.put( "min", date.getLong( ChronoField.MINUTE_OF_HOUR ) );
|
||||
table.put( "sec", date.getLong( ChronoField.SECOND_OF_MINUTE ) );
|
||||
table.put( "wday", date.getLong( WeekFields.SUNDAY_START.dayOfWeek() ) );
|
||||
table.put( "yday", date.getLong( ChronoField.DAY_OF_YEAR ) );
|
||||
table.put( "isdst", offset.getRules().isDaylightSavings( instant ) );
|
||||
return table;
|
||||
}
|
||||
|
||||
private static int getField( Map<?, ?> table, String field, int def ) throws LuaException
|
||||
{
|
||||
Object value = table.get( field );
|
||||
if( value instanceof Number ) return ((Number) value).intValue();
|
||||
if( def < 0 ) throw new LuaException( "field \"" + field + "\" missing in date table" );
|
||||
return def;
|
||||
}
|
||||
|
||||
private static Boolean getBoolField( Map<?, ?> table, String field ) throws LuaException
|
||||
{
|
||||
Object value = table.get( field );
|
||||
if( value instanceof Boolean || value == null ) return (Boolean) value;
|
||||
throw new LuaException( "field \"" + field + "\" missing in date table" );
|
||||
}
|
||||
|
||||
private static final TemporalField CENTURY = map( ChronoField.YEAR, ValueRange.of( 0, 6 ), x -> (x / 100) % 100 );
|
||||
private static final TemporalField ZERO_WEEK = map( WeekFields.SUNDAY_START.dayOfWeek(), ValueRange.of( 0, 6 ), x -> x - 1 );
|
||||
|
||||
private static TemporalField map( TemporalField field, ValueRange range, LongUnaryOperator convert )
|
||||
{
|
||||
return new TemporalField()
|
||||
{
|
||||
private final ValueRange range = ValueRange.of( 0, 99 );
|
||||
|
||||
@Override
|
||||
public TemporalUnit getBaseUnit()
|
||||
{
|
||||
return field.getBaseUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TemporalUnit getRangeUnit()
|
||||
{
|
||||
return field.getRangeUnit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueRange range()
|
||||
{
|
||||
return range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDateBased()
|
||||
{
|
||||
return field.isDateBased();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTimeBased()
|
||||
{
|
||||
return field.isTimeBased();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSupportedBy( TemporalAccessor temporal )
|
||||
{
|
||||
return field.isSupportedBy( temporal );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueRange rangeRefinedBy( TemporalAccessor temporal )
|
||||
{
|
||||
return range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFrom( TemporalAccessor temporal )
|
||||
{
|
||||
return convert.applyAsLong( temporal.getLong( field ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public <R extends Temporal> R adjustInto( R temporal, long newValue )
|
||||
{
|
||||
return (R) temporal.with( field, newValue );
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,11 @@ import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.shared.util.StringUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.util.*;
|
||||
|
||||
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||
@@ -31,9 +36,9 @@ public class OSAPI implements ILuaAPI
|
||||
|
||||
private static class Timer
|
||||
{
|
||||
public int m_ticksLeft;
|
||||
int m_ticksLeft;
|
||||
|
||||
public Timer( int ticksLeft )
|
||||
Timer( int ticksLeft )
|
||||
{
|
||||
m_ticksLeft = ticksLeft;
|
||||
}
|
||||
@@ -41,10 +46,10 @@ public class OSAPI implements ILuaAPI
|
||||
|
||||
private static class Alarm implements Comparable<Alarm>
|
||||
{
|
||||
public final double m_time;
|
||||
public final int m_day;
|
||||
final double m_time;
|
||||
final int m_day;
|
||||
|
||||
public Alarm( double time, int day )
|
||||
Alarm( double time, int day )
|
||||
{
|
||||
m_time = time;
|
||||
m_day = day;
|
||||
@@ -73,9 +78,7 @@ public class OSAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"os"
|
||||
};
|
||||
return new String[] { "os" };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,11 +187,12 @@ public class OSAPI implements ILuaAPI
|
||||
"day",
|
||||
"cancelTimer",
|
||||
"cancelAlarm",
|
||||
"epoch"
|
||||
"epoch",
|
||||
"date",
|
||||
};
|
||||
}
|
||||
|
||||
private float getTimeForCalendar( Calendar c )
|
||||
private static float getTimeForCalendar( Calendar c )
|
||||
{
|
||||
float time = c.get( Calendar.HOUR_OF_DAY );
|
||||
time += c.get( Calendar.MINUTE ) / 60.0f;
|
||||
@@ -196,7 +200,7 @@ public class OSAPI implements ILuaAPI
|
||||
return time;
|
||||
}
|
||||
|
||||
private int getDayForCalendar( Calendar c )
|
||||
private static int getDayForCalendar( Calendar c )
|
||||
{
|
||||
GregorianCalendar g = c instanceof GregorianCalendar ? (GregorianCalendar) c : new GregorianCalendar();
|
||||
int year = c.get( Calendar.YEAR );
|
||||
@@ -209,7 +213,7 @@ public class OSAPI implements ILuaAPI
|
||||
return day;
|
||||
}
|
||||
|
||||
private long getEpochForCalendar( Calendar c )
|
||||
private static long getEpochForCalendar( Calendar c )
|
||||
{
|
||||
return c.getTime().getTime();
|
||||
}
|
||||
@@ -282,6 +286,9 @@ public class OSAPI implements ILuaAPI
|
||||
case 11:
|
||||
{
|
||||
// time
|
||||
Object value = args.length > 0 ? args[0] : null;
|
||||
if( value instanceof Map ) return new Object[] { LuaDateTime.fromTable( (Map<?, ?>) value ) };
|
||||
|
||||
String param = optString( args, 0, "ingame" );
|
||||
switch( param.toLowerCase( Locale.ROOT ) )
|
||||
{
|
||||
@@ -355,9 +362,8 @@ public class OSAPI implements ILuaAPI
|
||||
}
|
||||
return null;
|
||||
}
|
||||
case 15:
|
||||
case 15: // epoch
|
||||
{
|
||||
// epoch
|
||||
String param = optString( args, 0, "ingame" );
|
||||
switch( param.toLowerCase( Locale.ROOT ) )
|
||||
{
|
||||
@@ -377,14 +383,39 @@ public class OSAPI implements ILuaAPI
|
||||
// Get in-game epoch
|
||||
synchronized( m_alarms )
|
||||
{
|
||||
return new Object[] {
|
||||
m_day * 86400000 + (int) (m_time * 3600000.0f)
|
||||
};
|
||||
return new Object[] { m_day * 86400000 + (int) (m_time * 3600000.0f) };
|
||||
}
|
||||
default:
|
||||
throw new LuaException( "Unsupported operation" );
|
||||
}
|
||||
}
|
||||
case 16: // date
|
||||
{
|
||||
String format = optString( args, 0, "%c" );
|
||||
long time = optLong( args, 1, Instant.now().getEpochSecond() );
|
||||
|
||||
Instant instant = Instant.ofEpochSecond( time );
|
||||
ZonedDateTime date;
|
||||
ZoneOffset offset;
|
||||
if( format.startsWith( "!" ) )
|
||||
{
|
||||
offset = ZoneOffset.UTC;
|
||||
date = ZonedDateTime.ofInstant( instant, offset );
|
||||
format = format.substring( 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
ZoneId id = ZoneId.systemDefault();
|
||||
offset = id.getRules().getOffset( instant );
|
||||
date = ZonedDateTime.ofInstant( instant, id );
|
||||
}
|
||||
|
||||
if( format.equals( "*t" ) ) return new Object[] { LuaDateTime.toTable( date, offset, instant ) };
|
||||
|
||||
DateTimeFormatterBuilder formatter = new DateTimeFormatterBuilder();
|
||||
LuaDateTime.format( formatter, format, offset );
|
||||
return new Object[] { formatter.toFormatter( Locale.ROOT ).format( date ) };
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
private Map<String, Integer> m_methodMap;
|
||||
private boolean m_attached;
|
||||
|
||||
public PeripheralWrapper( IPeripheral peripheral, String side )
|
||||
PeripheralWrapper( IPeripheral peripheral, String side )
|
||||
{
|
||||
super( m_environment );
|
||||
m_side = side;
|
||||
@@ -282,9 +282,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"peripheral"
|
||||
};
|
||||
return new String[] { "peripheral" };
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -326,7 +324,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
"isPresent",
|
||||
"getType",
|
||||
"getMethods",
|
||||
"call"
|
||||
"call",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -356,7 +354,6 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
||||
ComputerSide side = ComputerSide.valueOfInsensitive( getString( args, 0 ) );
|
||||
if( side != null )
|
||||
{
|
||||
String type = null;
|
||||
synchronized( m_peripherals )
|
||||
{
|
||||
PeripheralWrapper p = m_peripherals[side.ordinal()];
|
||||
|
||||
@@ -29,9 +29,7 @@ public class RedstoneAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"rs", "redstone"
|
||||
};
|
||||
return new String[] { "rs", "redstone" };
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -33,9 +33,7 @@ public class TermAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"term"
|
||||
};
|
||||
return new String[] { "term" };
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -89,9 +87,7 @@ public class TermAPI implements ILuaAPI
|
||||
|
||||
public static Object[] encodeColour( int colour ) throws LuaException
|
||||
{
|
||||
return new Object[] {
|
||||
1 << colour
|
||||
};
|
||||
return new Object[] { 1 << colour };
|
||||
}
|
||||
|
||||
public static void setColour( Terminal terminal, int colour, double r, double g, double b )
|
||||
|
||||
@@ -212,6 +212,7 @@ public class BinaryReadableHandle extends HandleGeneric
|
||||
}
|
||||
}
|
||||
case 3: // close
|
||||
checkOpen();
|
||||
close();
|
||||
return null;
|
||||
case 4: // seek
|
||||
|
||||
@@ -95,6 +95,7 @@ public class BinaryWritableHandle extends HandleGeneric
|
||||
return null;
|
||||
}
|
||||
case 2: // close
|
||||
checkOpen();
|
||||
close();
|
||||
return null;
|
||||
case 3: // seek
|
||||
|
||||
@@ -152,6 +152,7 @@ public class EncodedReadableHandle extends HandleGeneric
|
||||
return null;
|
||||
}
|
||||
case 3: // close
|
||||
checkOpen();
|
||||
close();
|
||||
return null;
|
||||
default:
|
||||
|
||||
@@ -93,6 +93,7 @@ public class EncodedWritableHandle extends HandleGeneric
|
||||
return null;
|
||||
}
|
||||
case 3: // close
|
||||
checkOpen();
|
||||
close();
|
||||
return null;
|
||||
default:
|
||||
|
||||
@@ -37,8 +37,13 @@ public abstract class HandleGeneric implements ILuaObject
|
||||
protected final void close()
|
||||
{
|
||||
m_open = false;
|
||||
IoUtil.closeQuietly( m_closable );
|
||||
m_closable = null;
|
||||
|
||||
Closeable closeable = m_closable;
|
||||
if( closeable != null )
|
||||
{
|
||||
IoUtil.closeQuietly( closeable );
|
||||
m_closable = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,7 +72,8 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
|
||||
*/
|
||||
protected void dispose()
|
||||
{
|
||||
@SuppressWarnings( "unchecked" ) T thisT = (T) this;
|
||||
@SuppressWarnings( "unchecked" )
|
||||
T thisT = (T) this;
|
||||
limiter.release( thisT );
|
||||
}
|
||||
|
||||
@@ -95,7 +96,8 @@ public abstract class Resource<T extends Resource<T>> implements Closeable
|
||||
|
||||
public boolean queue( Consumer<T> task )
|
||||
{
|
||||
@SuppressWarnings( "unchecked" ) T thisT = (T) this;
|
||||
@SuppressWarnings( "unchecked" )
|
||||
T thisT = (T) this;
|
||||
return limiter.queue( thisT, () -> task.accept( thisT ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.Closeable;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static dan200.computercraft.core.apis.ArgumentHelper.optBoolean;
|
||||
import static dan200.computercraft.core.apis.http.websocket.Websocket.CLOSE_EVENT;
|
||||
import static dan200.computercraft.core.apis.http.websocket.Websocket.MESSAGE_EVENT;
|
||||
|
||||
public class WebsocketHandle implements ILuaObject, Closeable
|
||||
@@ -53,15 +54,18 @@ public class WebsocketHandle implements ILuaObject, Closeable
|
||||
switch( method )
|
||||
{
|
||||
case 0: // receive
|
||||
checkOpen();
|
||||
while( true )
|
||||
{
|
||||
checkOpen();
|
||||
|
||||
Object[] event = context.pullEvent( MESSAGE_EVENT );
|
||||
if( event.length >= 3 && Objects.equal( event[1], websocket.address() ) )
|
||||
Object[] event = context.pullEvent( null );
|
||||
if( event.length >= 3 && Objects.equal( event[0], MESSAGE_EVENT ) && Objects.equal( event[1], websocket.address() ) )
|
||||
{
|
||||
return Arrays.copyOfRange( event, 2, event.length );
|
||||
}
|
||||
else if( event.length >= 2 && Objects.equal( event[0], CLOSE_EVENT ) && Objects.equal( event[1], websocket.address() ) && closed )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
case 1: // send
|
||||
|
||||
@@ -239,7 +239,6 @@ public class Computer
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@SuppressWarnings( "unused" )
|
||||
public void advance( double dt )
|
||||
{
|
||||
tick();
|
||||
|
||||
@@ -30,7 +30,10 @@ public enum ComputerSide
|
||||
|
||||
private final String name;
|
||||
|
||||
ComputerSide( String name ) {this.name = name;}
|
||||
ComputerSide( String name )
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static ComputerSide valueOf( int side )
|
||||
|
||||
@@ -133,7 +133,6 @@ public final class ComputerThread
|
||||
synchronized( threadLock )
|
||||
{
|
||||
running = true;
|
||||
if( monitor == null || !monitor.isAlive() ) (monitor = monitorFactory.newThread( new Monitor() )).start();
|
||||
|
||||
if( runners == null )
|
||||
{
|
||||
@@ -158,6 +157,8 @@ public final class ComputerThread
|
||||
runnerFactory.newThread( runners[i] = new TaskRunner() ).start();
|
||||
}
|
||||
}
|
||||
|
||||
if( monitor == null || !monitor.isAlive() ) (monitor = monitorFactory.newThread( new Monitor() )).start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +369,16 @@ public final class ComputerThread
|
||||
{
|
||||
TaskRunner runner = currentRunners[i];
|
||||
// If we've no runner, skip.
|
||||
if( runner == null ) continue;
|
||||
if( runner == null || runner.owner == null || !runner.owner.isAlive() )
|
||||
{
|
||||
if( !running ) continue;
|
||||
|
||||
// Mark the old runner as dead and start a new one.
|
||||
ComputerCraft.log.warn( "Previous runner ({}) has crashed, restarting!",
|
||||
runner != null && runner.owner != null ? runner.owner.getName() : runner );
|
||||
if( runner != null ) runner.running = false;
|
||||
runnerFactory.newThread( runners[i] = new TaskRunner() ).start();
|
||||
}
|
||||
|
||||
// If the runner has no work, skip
|
||||
ComputerExecutor executor = runner.currentExecutor.get();
|
||||
@@ -492,7 +502,7 @@ public final class ComputerThread
|
||||
{
|
||||
executor.work();
|
||||
}
|
||||
catch( Exception e )
|
||||
catch( Exception | LinkageError | VirtualMachineError e )
|
||||
{
|
||||
ComputerCraft.log.error( "Error running task on computer #" + executor.getComputer().getID(), e );
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ public final class MainThread
|
||||
// Of course, we'll go over the MAX_TICK_TIME most of the time, but eventually that overrun will accumulate
|
||||
// and we'll skip a whole tick - bringing the average back down again.
|
||||
currentTick++;
|
||||
budget += Math.min( budget + ComputerCraft.maxMainGlobalTime, ComputerCraft.maxMainGlobalTime );
|
||||
budget = Math.min( budget + ComputerCraft.maxMainGlobalTime, ComputerCraft.maxMainGlobalTime );
|
||||
canExecute = budget > 0;
|
||||
|
||||
// Cool down any warm computers.
|
||||
|
||||
@@ -224,7 +224,7 @@ final class MainThreadExecutor implements IWorkMonitor
|
||||
{
|
||||
state = State.COOLING;
|
||||
currentTick = MainThread.currentTick();
|
||||
budget += Math.min( budget + ComputerCraft.maxMainComputerTime, ComputerCraft.maxMainComputerTime );
|
||||
budget = Math.min( budget + ComputerCraft.maxMainComputerTime, ComputerCraft.maxMainComputerTime );
|
||||
if( budget < ComputerCraft.maxMainComputerTime ) return false;
|
||||
|
||||
state = State.COOL;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package dan200.computercraft.core.filesystem;
|
||||
|
||||
import dan200.computercraft.api.filesystem.FileOperationException;
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -95,7 +96,7 @@ public class ComboMount implements IMount
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException( "/" + path + ": Not a directory" );
|
||||
throw new FileOperationException( path, "Not a directory" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ public class ComboMount implements IMount
|
||||
return part.getSize( path );
|
||||
}
|
||||
}
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -126,7 +127,7 @@ public class ComboMount implements IMount
|
||||
return part.openForRead( path );
|
||||
}
|
||||
}
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -141,6 +142,6 @@ public class ComboMount implements IMount
|
||||
return part.openChannelForRead( path );
|
||||
}
|
||||
}
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
package dan200.computercraft.core.filesystem;
|
||||
|
||||
import dan200.computercraft.api.filesystem.FileOperationException;
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -44,7 +45,7 @@ public class EmptyMount implements IMount
|
||||
@Deprecated
|
||||
public InputStream openForRead( @Nonnull String path ) throws IOException
|
||||
{
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -52,6 +53,6 @@ public class EmptyMount implements IMount
|
||||
@Deprecated
|
||||
public ReadableByteChannel openChannelForRead( @Nonnull String path ) throws IOException
|
||||
{
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
package dan200.computercraft.core.filesystem;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import dan200.computercraft.api.filesystem.FileOperationException;
|
||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -167,12 +168,12 @@ public class FileMount implements IWritableMount
|
||||
{
|
||||
if( !created() )
|
||||
{
|
||||
if( !path.isEmpty() ) throw new IOException( "/" + path + ": Not a directory" );
|
||||
if( !path.isEmpty() ) throw new FileOperationException( path, "Not a directory" );
|
||||
return;
|
||||
}
|
||||
|
||||
File file = getRealPath( path );
|
||||
if( !file.exists() || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" );
|
||||
if( !file.exists() || !file.isDirectory() ) throw new FileOperationException( path, "Not a directory" );
|
||||
|
||||
String[] paths = file.list();
|
||||
for( String subPath : paths )
|
||||
@@ -194,7 +195,7 @@ public class FileMount implements IWritableMount
|
||||
if( file.exists() ) return file.isDirectory() ? 0 : file.length();
|
||||
}
|
||||
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -208,7 +209,7 @@ public class FileMount implements IWritableMount
|
||||
if( file.exists() && !file.isDirectory() ) return new FileInputStream( file );
|
||||
}
|
||||
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -221,7 +222,7 @@ public class FileMount implements IWritableMount
|
||||
if( file.exists() && !file.isDirectory() ) return FileChannel.open( file.toPath(), READ_OPTIONS );
|
||||
}
|
||||
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
// IWritableMount implementation
|
||||
@@ -233,7 +234,7 @@ public class FileMount implements IWritableMount
|
||||
File file = getRealPath( path );
|
||||
if( file.exists() )
|
||||
{
|
||||
if( !file.isDirectory() ) throw new IOException( "/" + path + ": File exists" );
|
||||
if( !file.isDirectory() ) throw new FileOperationException( path, "File exists" );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -247,7 +248,7 @@ public class FileMount implements IWritableMount
|
||||
|
||||
if( getRemainingSpace() < dirsToCreate * MINIMUM_FILE_SIZE )
|
||||
{
|
||||
throw new IOException( "/" + path + ": Out of space" );
|
||||
throw new FileOperationException( path, "Out of space" );
|
||||
}
|
||||
|
||||
if( file.mkdirs() )
|
||||
@@ -256,14 +257,14 @@ public class FileMount implements IWritableMount
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IOException( "/" + path + ": Access denied" );
|
||||
throw new FileOperationException( path, "Access denied" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete( @Nonnull String path ) throws IOException
|
||||
{
|
||||
if( path.isEmpty() ) throw new IOException( "/" + path + ": Access denied" );
|
||||
if( path.isEmpty() ) throw new FileOperationException( path, "Access denied" );
|
||||
|
||||
if( created() )
|
||||
{
|
||||
@@ -319,7 +320,7 @@ public class FileMount implements IWritableMount
|
||||
{
|
||||
create();
|
||||
File file = getRealPath( path );
|
||||
if( file.exists() && file.isDirectory() ) throw new IOException( "/" + path + ": Cannot write to directory" );
|
||||
if( file.exists() && file.isDirectory() ) throw new FileOperationException( path, "Cannot write to directory" );
|
||||
|
||||
if( file.exists() )
|
||||
{
|
||||
@@ -327,7 +328,7 @@ public class FileMount implements IWritableMount
|
||||
}
|
||||
else if( getRemainingSpace() < MINIMUM_FILE_SIZE )
|
||||
{
|
||||
throw new IOException( "/" + path + ": Out of space" );
|
||||
throw new FileOperationException( path, "Out of space" );
|
||||
}
|
||||
m_usedSpace += MINIMUM_FILE_SIZE;
|
||||
|
||||
@@ -340,12 +341,12 @@ public class FileMount implements IWritableMount
|
||||
{
|
||||
if( !created() )
|
||||
{
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
File file = getRealPath( path );
|
||||
if( !file.exists() ) throw new IOException( "/" + path + ": No such file" );
|
||||
if( file.isDirectory() ) throw new IOException( "/" + path + ": Cannot write to directory" );
|
||||
if( !file.exists() ) throw new FileOperationException( path, "No such file" );
|
||||
if( file.isDirectory() ) throw new FileOperationException( path, "Cannot write to directory" );
|
||||
|
||||
// Allowing seeking when appending is not recommended, so we use a separate channel.
|
||||
return new WritableCountingChannel(
|
||||
|
||||
@@ -8,6 +8,7 @@ package dan200.computercraft.core.filesystem;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
import dan200.computercraft.api.filesystem.FileOperationException;
|
||||
import dan200.computercraft.api.filesystem.IFileSystem;
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
import dan200.computercraft.api.filesystem.IWritableMount;
|
||||
@@ -45,7 +46,7 @@ public class FileSystem
|
||||
m_writableMount = null;
|
||||
}
|
||||
|
||||
public MountWrapper( String label, String location, IWritableMount mount )
|
||||
MountWrapper( String label, String location, IWritableMount mount )
|
||||
{
|
||||
this( label, location, (IMount) mount );
|
||||
m_writableMount = mount;
|
||||
@@ -107,7 +108,7 @@ public class FileSystem
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,12 +123,12 @@ public class FileSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": Not a directory" );
|
||||
throw localExceptionOf( path, "Not a directory" );
|
||||
}
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,12 +150,12 @@ public class FileSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": No such file" );
|
||||
throw localExceptionOf( path, "No such file" );
|
||||
}
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,12 +170,12 @@ public class FileSystem
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": No such file" );
|
||||
throw localExceptionOf( path, "No such file" );
|
||||
}
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,19 +183,14 @@ public class FileSystem
|
||||
|
||||
public void makeDirectory( String path ) throws FileSystemException
|
||||
{
|
||||
if( m_writableMount == null )
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": Access denied" );
|
||||
}
|
||||
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
|
||||
|
||||
path = toLocal( path );
|
||||
try
|
||||
{
|
||||
path = toLocal( path );
|
||||
if( m_mount.exists( path ) )
|
||||
{
|
||||
if( !m_mount.isDirectory( path ) )
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": File exists" );
|
||||
}
|
||||
if( !m_mount.isDirectory( path ) ) throw localExceptionOf( path, "File exists" );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -203,16 +199,14 @@ public class FileSystem
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
public void delete( String path ) throws FileSystemException
|
||||
{
|
||||
if( m_writableMount == null )
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": Access denied" );
|
||||
}
|
||||
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
|
||||
|
||||
try
|
||||
{
|
||||
path = toLocal( path );
|
||||
@@ -227,22 +221,20 @@ public class FileSystem
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
public WritableByteChannel openForWrite( String path ) throws FileSystemException
|
||||
{
|
||||
if( m_writableMount == null )
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": Access denied" );
|
||||
}
|
||||
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
|
||||
|
||||
path = toLocal( path );
|
||||
try
|
||||
{
|
||||
path = toLocal( path );
|
||||
if( m_mount.exists( path ) && m_mount.isDirectory( path ) )
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": Cannot write to directory" );
|
||||
throw localExceptionOf( path, "Cannot write to directory" );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,19 +255,17 @@ public class FileSystem
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
public WritableByteChannel openForAppend( String path ) throws FileSystemException
|
||||
{
|
||||
if( m_writableMount == null )
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": Access denied" );
|
||||
}
|
||||
if( m_writableMount == null ) throw exceptionOf( path, "Access denied" );
|
||||
|
||||
path = toLocal( path );
|
||||
try
|
||||
{
|
||||
path = toLocal( path );
|
||||
if( !m_mount.exists( path ) )
|
||||
{
|
||||
if( !path.isEmpty() )
|
||||
@@ -290,7 +280,7 @@ public class FileSystem
|
||||
}
|
||||
else if( m_mount.isDirectory( path ) )
|
||||
{
|
||||
throw new FileSystemException( "/" + path + ": Cannot write to directory" );
|
||||
throw localExceptionOf( path, "Cannot write to directory" );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -303,16 +293,36 @@ public class FileSystem
|
||||
}
|
||||
catch( IOException e )
|
||||
{
|
||||
throw new FileSystemException( e.getMessage() );
|
||||
throw localExceptionOf( e );
|
||||
}
|
||||
}
|
||||
|
||||
// private members
|
||||
|
||||
private String toLocal( String path )
|
||||
{
|
||||
return FileSystem.toLocal( path, m_location );
|
||||
}
|
||||
|
||||
private FileSystemException localExceptionOf( IOException e )
|
||||
{
|
||||
if( !m_location.isEmpty() && e instanceof FileOperationException )
|
||||
{
|
||||
FileOperationException ex = (FileOperationException) e;
|
||||
if( ex.getFilename() != null ) return localExceptionOf( ex.getFilename(), ex.getMessage() );
|
||||
}
|
||||
|
||||
return new FileSystemException( e.getMessage() );
|
||||
}
|
||||
|
||||
private FileSystemException localExceptionOf( String path, String message )
|
||||
{
|
||||
if( !m_location.isEmpty() ) path = path.isEmpty() ? m_location : m_location + "/" + path;
|
||||
return exceptionOf( path, message );
|
||||
}
|
||||
|
||||
private static FileSystemException exceptionOf( String path, String message )
|
||||
{
|
||||
return new FileSystemException( "/" + path + ": " + message );
|
||||
}
|
||||
}
|
||||
|
||||
private final FileSystemWrapperMount m_wrapper = new FileSystemWrapperMount( this );
|
||||
@@ -769,7 +779,7 @@ public class FileSystem
|
||||
|
||||
// Clean the path or illegal characters.
|
||||
final char[] specialChars = new char[] {
|
||||
'"', ':', '<', '>', '?', '|' // Sorted by ascii value (important)
|
||||
'"', ':', '<', '>', '?', '|', // Sorted by ascii value (important)
|
||||
};
|
||||
|
||||
StringBuilder cleanName = new StringBuilder();
|
||||
|
||||
@@ -9,6 +9,7 @@ package dan200.computercraft.core.filesystem;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import dan200.computercraft.api.filesystem.FileOperationException;
|
||||
import dan200.computercraft.api.filesystem.IMount;
|
||||
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
|
||||
import dan200.computercraft.shared.util.IoUtil;
|
||||
@@ -92,7 +93,7 @@ public class JarMount implements IMount
|
||||
new MountReference( this );
|
||||
|
||||
// Read in all the entries
|
||||
root = new FileEntry( "" );
|
||||
root = new FileEntry();
|
||||
Enumeration<? extends ZipEntry> zipEntries = zip.entries();
|
||||
while( zipEntries.hasMoreElements() )
|
||||
{
|
||||
@@ -139,7 +140,7 @@ public class JarMount implements IMount
|
||||
FileEntry nextEntry = lastEntry.children.get( part );
|
||||
if( nextEntry == null || !nextEntry.isDirectory() )
|
||||
{
|
||||
lastEntry.children.put( part, nextEntry = new FileEntry( part ) );
|
||||
lastEntry.children.put( part, nextEntry = new FileEntry() );
|
||||
}
|
||||
|
||||
lastEntry = nextEntry;
|
||||
@@ -166,7 +167,7 @@ public class JarMount implements IMount
|
||||
public void list( @Nonnull String path, @Nonnull List<String> contents ) throws IOException
|
||||
{
|
||||
FileEntry file = get( path );
|
||||
if( file == null || !file.isDirectory() ) throw new IOException( "/" + path + ": Not a directory" );
|
||||
if( file == null || !file.isDirectory() ) throw new FileOperationException( path, "Not a directory" );
|
||||
|
||||
file.list( contents );
|
||||
}
|
||||
@@ -176,7 +177,7 @@ public class JarMount implements IMount
|
||||
{
|
||||
FileEntry file = get( path );
|
||||
if( file != null ) return file.size;
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -218,22 +219,15 @@ public class JarMount implements IMount
|
||||
}
|
||||
}
|
||||
|
||||
throw new IOException( "/" + path + ": No such file" );
|
||||
throw new FileOperationException( path, "No such file" );
|
||||
}
|
||||
|
||||
private static class FileEntry
|
||||
{
|
||||
final String name;
|
||||
|
||||
String path;
|
||||
long size;
|
||||
Map<String, FileEntry> children;
|
||||
|
||||
FileEntry( String name )
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
void setup( ZipEntry entry )
|
||||
{
|
||||
path = entry.getName();
|
||||
|
||||
@@ -242,7 +242,7 @@ public class CobaltLuaMachine implements ILuaMachine
|
||||
}
|
||||
catch( InterruptedException e )
|
||||
{
|
||||
throw new OrphanedThread();
|
||||
throw new InterruptedError( e );
|
||||
}
|
||||
catch( LuaException e )
|
||||
{
|
||||
@@ -550,7 +550,7 @@ public class CobaltLuaMachine implements ILuaMachine
|
||||
{
|
||||
if( ComputerCraft.logPeripheralErrors ) ComputerCraft.log.error( "Error running task", t );
|
||||
m_computer.queueEvent( "task_complete", new Object[] {
|
||||
taskID, false, "Java Exception Thrown: " + t
|
||||
taskID, false, "Java Exception Thrown: " + t,
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ package dan200.computercraft.core.terminal;
|
||||
|
||||
public class TextBuffer
|
||||
{
|
||||
public char[] m_text;
|
||||
private final char[] m_text;
|
||||
|
||||
public TextBuffer( char c, int length )
|
||||
{
|
||||
|
||||
@@ -402,7 +402,7 @@ public final class Config
|
||||
|
||||
if( oldProperty.isList() )
|
||||
{
|
||||
oldProperty.setValues( oldProperty.getStringList() );
|
||||
oldProperty.setValues( newProperty.getStringList() );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -51,7 +51,6 @@ public abstract class BlockGeneric extends Block implements ITileEntityProvider
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
@SuppressWarnings( "deprecation" )
|
||||
public final void neighborChanged( IBlockState state, World world, BlockPos pos, Block neighbourBlock, BlockPos neighbourPos )
|
||||
{
|
||||
TileEntity tile = world.getTileEntity( pos );
|
||||
|
||||
@@ -63,7 +63,6 @@ public abstract class TileGeneric extends TileEntity
|
||||
{
|
||||
}
|
||||
|
||||
@SuppressWarnings( "deprecation" )
|
||||
public void onNeighbourChange( @Nonnull BlockPos neighbour )
|
||||
{
|
||||
onNeighbourChange();
|
||||
|
||||
@@ -47,9 +47,7 @@ public class CommandAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"commands"
|
||||
};
|
||||
return new String[] { "commands" };
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -62,7 +60,7 @@ public class CommandAPI implements ILuaAPI
|
||||
"list",
|
||||
"getBlockPosition",
|
||||
"getBlockInfos",
|
||||
"getBlockInfo"
|
||||
"getBlockInfo",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ public class TileComputer extends TileComputerBase
|
||||
ServerComputer computer = new ServerComputer(
|
||||
getWorld(),
|
||||
id,
|
||||
m_label,
|
||||
label,
|
||||
instanceID,
|
||||
family,
|
||||
ComputerCraft.terminalWidth_computer,
|
||||
|
||||
@@ -22,7 +22,10 @@ import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import dan200.computercraft.shared.util.RedstoneUtil;
|
||||
import joptsimple.internal.Strings;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockRedstoneWire;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
@@ -34,6 +37,7 @@ import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.IWorldNameable;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -43,7 +47,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
{
|
||||
private int m_instanceID = -1;
|
||||
private int m_computerID = -1;
|
||||
protected String m_label = null;
|
||||
protected String label = null;
|
||||
private boolean m_on = false;
|
||||
boolean m_startOn = false;
|
||||
private boolean m_fresh = false;
|
||||
@@ -124,16 +128,14 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
@Override
|
||||
public boolean getRedstoneConnectivity( EnumFacing side )
|
||||
{
|
||||
if( side == null ) return false;
|
||||
ComputerSide localDir = remapLocalSide( DirectionUtil.toLocal( this, side.getOpposite() ) );
|
||||
return !isRedstoneBlockedOnSide( localDir );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRedstoneOutput( EnumFacing side )
|
||||
{
|
||||
ComputerSide localDir = remapLocalSide( DirectionUtil.toLocal( this, side ) );
|
||||
if( !isRedstoneBlockedOnSide( localDir ) && world != null && !world.isRemote )
|
||||
if( world != null && !world.isRemote )
|
||||
{
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null ) return computer.getRedstoneOutput( localDir );
|
||||
@@ -144,15 +146,14 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
@Override
|
||||
public boolean getBundledRedstoneConnectivity( @Nonnull EnumFacing side )
|
||||
{
|
||||
ComputerSide localDir = remapLocalSide( DirectionUtil.toLocal( this, side ) );
|
||||
return !isRedstoneBlockedOnSide( localDir );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBundledRedstoneOutput( @Nonnull EnumFacing side )
|
||||
{
|
||||
ComputerSide localDir = remapLocalSide( DirectionUtil.toLocal( this, side ) );
|
||||
if( !isRedstoneBlockedOnSide( localDir ) && !world.isRemote )
|
||||
if( !world.isRemote )
|
||||
{
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null ) return computer.getBundledRedstoneOutput( localDir );
|
||||
@@ -189,7 +190,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
|
||||
m_fresh = false;
|
||||
m_computerID = computer.getID();
|
||||
m_label = computer.getLabel();
|
||||
label = computer.getLabel();
|
||||
m_on = computer.isOn();
|
||||
|
||||
if( computer.hasOutputChanged() ) updateOutput();
|
||||
@@ -211,9 +212,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
{
|
||||
nbt.setInteger( "computerID", m_computerID );
|
||||
}
|
||||
if( m_label != null )
|
||||
if( label != null )
|
||||
{
|
||||
nbt.setString( "label", m_label );
|
||||
nbt.setString( "label", label );
|
||||
}
|
||||
nbt.setBoolean( "on", m_on );
|
||||
return super.writeToNBT( nbt );
|
||||
@@ -247,7 +248,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
m_computerID = id;
|
||||
|
||||
// Load label
|
||||
m_label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null;
|
||||
label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null;
|
||||
|
||||
// Load power state
|
||||
m_startOn = nbt.getBoolean( "on" );
|
||||
@@ -259,11 +260,6 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isRedstoneBlockedOnSide( ComputerSide localSide )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected ComputerSide remapLocalSide( ComputerSide localSide )
|
||||
{
|
||||
return localSide;
|
||||
@@ -273,17 +269,36 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
{
|
||||
EnumFacing offsetSide = dir.getOpposite();
|
||||
ComputerSide localDir = remapLocalSide( DirectionUtil.toLocal( this, dir ) );
|
||||
if( !isRedstoneBlockedOnSide( localDir ) )
|
||||
{
|
||||
computer.setRedstoneInput( localDir, getWorld().getRedstonePower( offset, dir ) );
|
||||
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
|
||||
}
|
||||
|
||||
computer.setRedstoneInput( localDir, getRedstoneInput( world, offset, dir ) );
|
||||
computer.setBundledRedstoneInput( localDir, BundledRedstone.getOutput( getWorld(), offset, offsetSide ) );
|
||||
|
||||
if( !isPeripheralBlockedOnSide( localDir ) )
|
||||
{
|
||||
computer.setPeripheral( localDir, Peripherals.getPeripheral( getWorld(), offset, offsetSide ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the redstone input for an adjacent block
|
||||
*
|
||||
* @param world The world we exist in
|
||||
* @param pos The position of the neighbour
|
||||
* @param side The side we are reading from
|
||||
* @return The effective redstone power
|
||||
* @see net.minecraft.block.BlockRedstoneDiode#calculateInputStrength(World, BlockPos, IBlockState)
|
||||
*/
|
||||
protected static int getRedstoneInput( World world, BlockPos pos, EnumFacing side )
|
||||
{
|
||||
int power = world.getRedstonePower( pos, side );
|
||||
if( power >= 15 ) return power;
|
||||
|
||||
IBlockState neighbour = world.getBlockState( pos );
|
||||
return neighbour.getBlock() == Blocks.REDSTONE_WIRE
|
||||
? Math.max( power, neighbour.getValue( BlockRedstoneWire.POWER ) )
|
||||
: power;
|
||||
}
|
||||
|
||||
public void updateInput()
|
||||
{
|
||||
if( getWorld() == null || getWorld().isRemote ) return;
|
||||
@@ -346,7 +361,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
@Override
|
||||
public final String getLabel()
|
||||
{
|
||||
return m_label;
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -363,9 +378,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
@Override
|
||||
public final void setLabel( String label )
|
||||
{
|
||||
if( getWorld().isRemote || Objects.equals( m_label, label ) ) return;
|
||||
if( getWorld().isRemote || Objects.equals( this.label, label ) ) return;
|
||||
|
||||
m_label = label;
|
||||
this.label = label;
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null ) computer.setLabel( label );
|
||||
markDirty();
|
||||
@@ -438,8 +453,8 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
protected void writeDescription( @Nonnull NBTTagCompound nbt )
|
||||
{
|
||||
super.writeDescription( nbt );
|
||||
nbt.setInteger( "instanceID", createServerComputer().getInstanceID() );
|
||||
if( m_label != null ) nbt.setString( "label", m_label );
|
||||
if( m_instanceID >= 0 ) nbt.setInteger( "instanceID", m_instanceID );
|
||||
if( label != null ) nbt.setString( "label", label );
|
||||
if( m_computerID >= 0 ) nbt.setInteger( "computerID", m_computerID );
|
||||
}
|
||||
|
||||
@@ -448,7 +463,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
{
|
||||
super.readDescription( nbt );
|
||||
m_instanceID = nbt.getInteger( "instanceID" );
|
||||
m_label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null;
|
||||
label = nbt.hasKey( "label" ) ? nbt.getString( "label" ) : null;
|
||||
m_computerID = nbt.hasKey( "computerID" ) ? nbt.getInteger( "computerID" ) : -1;
|
||||
}
|
||||
|
||||
@@ -459,7 +474,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
unload();
|
||||
m_instanceID = copy.m_instanceID;
|
||||
m_computerID = copy.m_computerID;
|
||||
m_label = copy.m_label;
|
||||
label = copy.label;
|
||||
m_on = copy.m_on;
|
||||
m_startOn = copy.m_startOn;
|
||||
updateBlock();
|
||||
@@ -478,13 +493,13 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return hasCustomName() ? m_label : getBlockType().getTranslationKey();
|
||||
return hasCustomName() ? label : getBlockType().getTranslationKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCustomName()
|
||||
{
|
||||
return !Strings.isNullOrEmpty( m_label );
|
||||
return !Strings.isNullOrEmpty( label );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -11,9 +11,9 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class ComputerRegistry<TComputer extends IComputer>
|
||||
public class ComputerRegistry<T extends IComputer>
|
||||
{
|
||||
private Map<Integer, TComputer> m_computers;
|
||||
private Map<Integer, T> m_computers;
|
||||
private int m_nextUnusedInstanceID;
|
||||
private int m_sessionID;
|
||||
|
||||
@@ -33,12 +33,12 @@ public class ComputerRegistry<TComputer extends IComputer>
|
||||
return m_nextUnusedInstanceID++;
|
||||
}
|
||||
|
||||
public Collection<TComputer> getComputers()
|
||||
public Collection<T> getComputers()
|
||||
{
|
||||
return m_computers.values();
|
||||
}
|
||||
|
||||
public TComputer get( int instanceID )
|
||||
public T get( int instanceID )
|
||||
{
|
||||
if( instanceID >= 0 )
|
||||
{
|
||||
@@ -55,7 +55,7 @@ public class ComputerRegistry<TComputer extends IComputer>
|
||||
return m_computers.containsKey( instanceID );
|
||||
}
|
||||
|
||||
public void add( int instanceID, TComputer computer )
|
||||
public void add( int instanceID, T computer )
|
||||
{
|
||||
if( m_computers.containsKey( instanceID ) )
|
||||
{
|
||||
|
||||
@@ -175,12 +175,13 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
|
||||
FMLCommonHandler handler = FMLCommonHandler.instance();
|
||||
if( handler != null )
|
||||
{
|
||||
IMessage packet = createTerminalPacket();
|
||||
IMessage packet = null;
|
||||
MinecraftServer server = handler.getMinecraftServerInstance();
|
||||
for( EntityPlayerMP player : server.getPlayerList().getPlayers() )
|
||||
{
|
||||
if( isInteracting( player ) )
|
||||
{
|
||||
if( packet == null ) packet = createTerminalPacket();
|
||||
NetworkHandler.sendToPlayer( player, packet );
|
||||
}
|
||||
}
|
||||
@@ -219,6 +220,13 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput
|
||||
return m_instanceID;
|
||||
}
|
||||
|
||||
/*
|
||||
* getID and getLabel are deprecated on IComputer, as they do not make sense in ClientComputer.
|
||||
* However, for compatibility reasons, we still need these here, and have no choice but to override the IComputer methods.
|
||||
*
|
||||
* Hence, we suppress the deprecation warning.
|
||||
*/
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "deprecation" )
|
||||
public int getID()
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.shared.integration.charset;
|
||||
|
||||
import dan200.computercraft.shared.common.TileGeneric;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.shared.integration.charset;
|
||||
|
||||
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/*
|
||||
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||
* Copyright Daniel Ratcliffe, 2011-2018. Do not distribute without permission.
|
||||
* Copyright Daniel Ratcliffe, 2011-2019. Do not distribute without permission.
|
||||
* Send enquiries to dratcliffe@gmail.com
|
||||
*/
|
||||
|
||||
package dan200.computercraft.shared.integration.charset;
|
||||
|
||||
import dan200.computercraft.ComputerCraft;
|
||||
|
||||
@@ -90,6 +90,7 @@ public class JEIComputerCraft implements IModPlugin
|
||||
ingredients.addIngredientsAtRuntime( VanillaTypes.ITEM, upgradeItems );
|
||||
|
||||
// Hide all upgrade recipes
|
||||
@SuppressWarnings( "unchecked" )
|
||||
IRecipeCategory<? extends IRecipeWrapper> category = (IRecipeCategory<? extends IRecipeWrapper>) registry.getRecipeCategory( VanillaRecipeCategoryUid.CRAFTING );
|
||||
if( category != null )
|
||||
{
|
||||
|
||||
@@ -39,5 +39,8 @@ public enum PeripheralType implements IStringSerializable
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return name; }
|
||||
public String toString()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ public class CommandBlockPeripheral implements IPeripheral
|
||||
{
|
||||
case 0: // getCommand
|
||||
return context.executeMainThreadTask( () -> new Object[] {
|
||||
m_commandBlock.getCommandBlockLogic().getCommand()
|
||||
m_commandBlock.getCommandBlockLogic().getCommand(),
|
||||
} );
|
||||
case 1:
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@ import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.media.IMedia;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.MediaProviders;
|
||||
import dan200.computercraft.shared.media.items.ItemDiskLegacy;
|
||||
import dan200.computercraft.shared.util.StringUtil;
|
||||
import net.minecraft.item.Item;
|
||||
@@ -20,11 +21,11 @@ import javax.annotation.Nonnull;
|
||||
|
||||
import static dan200.computercraft.core.apis.ArgumentHelper.optString;
|
||||
|
||||
public class DiskDrivePeripheral implements IPeripheral
|
||||
class DiskDrivePeripheral implements IPeripheral
|
||||
{
|
||||
private final TileDiskDrive m_diskDrive;
|
||||
|
||||
public DiskDrivePeripheral( TileDiskDrive diskDrive )
|
||||
DiskDrivePeripheral( TileDiskDrive diskDrive )
|
||||
{
|
||||
m_diskDrive = diskDrive;
|
||||
}
|
||||
@@ -51,12 +52,12 @@ public class DiskDrivePeripheral implements IPeripheral
|
||||
"playAudio",
|
||||
"stopAudio",
|
||||
"ejectDisk",
|
||||
"getDiskID"
|
||||
"getDiskID",
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException
|
||||
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
||||
{
|
||||
switch( method )
|
||||
{
|
||||
@@ -64,21 +65,26 @@ public class DiskDrivePeripheral implements IPeripheral
|
||||
return new Object[] { !m_diskDrive.getDiskStack().isEmpty() };
|
||||
case 1: // getDiskLabel
|
||||
{
|
||||
IMedia media = m_diskDrive.getDiskMedia();
|
||||
return media == null ? null : new Object[] { media.getLabel( m_diskDrive.getDiskStack() ) };
|
||||
ItemStack stack = m_diskDrive.getDiskStack();
|
||||
IMedia media = MediaProviders.get( stack );
|
||||
return media == null ? null : new Object[] { media.getLabel( stack ) };
|
||||
}
|
||||
case 2: // setDiskLabel
|
||||
{
|
||||
String label = optString( arguments, 0, null );
|
||||
|
||||
IMedia media = m_diskDrive.getDiskMedia();
|
||||
if( media == null ) return null;
|
||||
return context.executeMainThreadTask( () -> {
|
||||
ItemStack stack = m_diskDrive.getDiskStack();
|
||||
IMedia media = MediaProviders.get( stack );
|
||||
if( media == null ) return null;
|
||||
|
||||
ItemStack disk = m_diskDrive.getDiskStack();
|
||||
label = StringUtil.normaliseLabel( label );
|
||||
if( !media.setLabel( disk, label ) ) throw new LuaException( "Disk label cannot be changed" );
|
||||
m_diskDrive.setDiskStack( disk );
|
||||
return null;
|
||||
if( !media.setLabel( stack, StringUtil.normaliseLabel( label ) ) )
|
||||
{
|
||||
throw new LuaException( "Disk label cannot be changed" );
|
||||
}
|
||||
m_diskDrive.setDiskStack( stack );
|
||||
return null;
|
||||
} );
|
||||
}
|
||||
case 3: // hasData
|
||||
return new Object[] { m_diskDrive.getDiskMountPath( computer ) != null };
|
||||
@@ -87,14 +93,16 @@ public class DiskDrivePeripheral implements IPeripheral
|
||||
case 5:
|
||||
{
|
||||
// hasAudio
|
||||
IMedia media = m_diskDrive.getDiskMedia();
|
||||
return new Object[] { media != null && media.getAudio( m_diskDrive.getDiskStack() ) != null };
|
||||
ItemStack stack = m_diskDrive.getDiskStack();
|
||||
IMedia media = MediaProviders.get( stack );
|
||||
return new Object[] { media != null && media.getAudio( stack ) != null };
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
// getAudioTitle
|
||||
IMedia media = m_diskDrive.getDiskMedia();
|
||||
return new Object[] { media != null ? media.getAudioTitle( m_diskDrive.getDiskStack() ) : false };
|
||||
ItemStack stack = m_diskDrive.getDiskStack();
|
||||
IMedia media = MediaProviders.get( stack );
|
||||
return new Object[] { media != null ? media.getAudioTitle( stack ) : false };
|
||||
}
|
||||
case 7: // playAudio
|
||||
m_diskDrive.playDiskAudio();
|
||||
@@ -131,8 +139,7 @@ public class DiskDrivePeripheral implements IPeripheral
|
||||
@Override
|
||||
public boolean equals( IPeripheral other )
|
||||
{
|
||||
if( this == other ) return true;
|
||||
return other instanceof DiskDrivePeripheral && ((DiskDrivePeripheral) other).m_diskDrive == m_diskDrive;
|
||||
return this == other || other instanceof DiskDrivePeripheral && ((DiskDrivePeripheral) other).m_diskDrive == m_diskDrive;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
||||
@@ -318,35 +318,31 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public ItemStack getDiskStack()
|
||||
ItemStack getDiskStack()
|
||||
{
|
||||
return getStackInSlot( 0 );
|
||||
}
|
||||
|
||||
public void setDiskStack( @Nonnull ItemStack stack )
|
||||
void setDiskStack( @Nonnull ItemStack stack )
|
||||
{
|
||||
setInventorySlotContents( 0, stack );
|
||||
}
|
||||
|
||||
public IMedia getDiskMedia()
|
||||
private IMedia getDiskMedia()
|
||||
{
|
||||
return MediaProviders.get( getDiskStack() );
|
||||
}
|
||||
|
||||
public String getDiskMountPath( IComputerAccess computer )
|
||||
String getDiskMountPath( IComputerAccess computer )
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
if( m_computers.containsKey( computer ) )
|
||||
{
|
||||
MountInfo info = m_computers.get( computer );
|
||||
return info.mountPath;
|
||||
}
|
||||
MountInfo info = m_computers.get( computer );
|
||||
return info != null ? info.mountPath : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void mount( IComputerAccess computer )
|
||||
void mount( IComputerAccess computer )
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
@@ -355,7 +351,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor
|
||||
}
|
||||
}
|
||||
|
||||
public void unmount( IComputerAccess computer )
|
||||
void unmount( IComputerAccess computer )
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
@@ -364,7 +360,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor
|
||||
}
|
||||
}
|
||||
|
||||
public void playDiskAudio()
|
||||
void playDiskAudio()
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
@@ -377,7 +373,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor
|
||||
}
|
||||
}
|
||||
|
||||
public void stopDiskAudio()
|
||||
void stopDiskAudio()
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
@@ -386,7 +382,7 @@ public class TileDiskDrive extends TilePeripheralBase implements DefaultInventor
|
||||
}
|
||||
}
|
||||
|
||||
public void ejectDisk()
|
||||
void ejectDisk()
|
||||
{
|
||||
synchronized( this )
|
||||
{
|
||||
|
||||
@@ -87,7 +87,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa
|
||||
for( IComputerAccess computer : m_computers )
|
||||
{
|
||||
computer.queueEvent( "modem_message", new Object[] {
|
||||
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance
|
||||
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(), distance,
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa
|
||||
for( IComputerAccess computer : m_computers )
|
||||
{
|
||||
computer.queueEvent( "modem_message", new Object[] {
|
||||
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload()
|
||||
computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload(),
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +277,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW
|
||||
private final String[] m_methods;
|
||||
private final Map<String, Integer> m_methodMap;
|
||||
|
||||
public RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name )
|
||||
RemotePeripheralWrapper( WiredModemElement element, IPeripheral peripheral, IComputerAccess computer, String name )
|
||||
{
|
||||
m_element = element;
|
||||
m_peripheral = peripheral;
|
||||
|
||||
@@ -142,7 +142,7 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph
|
||||
for( IComputerAccess computer : monitor.m_computers )
|
||||
{
|
||||
computer.queueEvent( "monitor_resize", new Object[] {
|
||||
computer.getAttachmentName()
|
||||
computer.getAttachmentName(),
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -339,7 +339,7 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph
|
||||
return EnumFacing.WEST;
|
||||
}
|
||||
|
||||
private EnumFacing getDown()
|
||||
public EnumFacing getDown()
|
||||
{
|
||||
int dir = getDir();
|
||||
if( dir <= 5 ) return EnumFacing.UP;
|
||||
@@ -660,7 +660,7 @@ public class TileMonitor extends TileGeneric implements ITilePeripheral, IPeriph
|
||||
for( IComputerAccess computer : monitor.m_computers )
|
||||
{
|
||||
computer.queueEvent( "monitor_touch", new Object[] {
|
||||
computer.getAttachmentName(), xCharPos, yCharPos
|
||||
computer.getAttachmentName(), xCharPos, yCharPos,
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.util.StringUtil;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
@@ -51,8 +52,13 @@ public class PrinterPeripheral implements IPeripheral
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
|
||||
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
|
||||
{
|
||||
// FIXME: There's a theoretical race condition here between getCurrentPage and then using the page. Ideally
|
||||
// we'd lock on the page, consume it, and unlock.
|
||||
|
||||
// FIXME: None of our page modification functions actually mark the tile as dirty, so the page may not be
|
||||
// persisted correctly.
|
||||
switch( method )
|
||||
{
|
||||
case 0: // write
|
||||
@@ -89,10 +95,13 @@ public class PrinterPeripheral implements IPeripheral
|
||||
return new Object[] { width, height };
|
||||
}
|
||||
case 4: // newPage
|
||||
return new Object[] { m_printer.startNewPage() };
|
||||
return context.executeMainThreadTask( () -> new Object[] { m_printer.startNewPage() } );
|
||||
case 5: // endPage
|
||||
getCurrentPage();
|
||||
return new Object[] { m_printer.endCurrentPage() };
|
||||
return context.executeMainThreadTask( () -> {
|
||||
getCurrentPage();
|
||||
return new Object[] { m_printer.endCurrentPage() };
|
||||
} );
|
||||
case 6: // getInkLevel
|
||||
return new Object[] { m_printer.getInkLevel() };
|
||||
case 7:
|
||||
@@ -100,7 +109,7 @@ public class PrinterPeripheral implements IPeripheral
|
||||
// setPageTitle
|
||||
String title = optString( args, 0, "" );
|
||||
getCurrentPage();
|
||||
m_printer.setPageTitle( title );
|
||||
m_printer.setPageTitle( StringUtil.normaliseLabel( title ) );
|
||||
return null;
|
||||
}
|
||||
case 8: // getPaperLevel
|
||||
@@ -123,13 +132,11 @@ public class PrinterPeripheral implements IPeripheral
|
||||
return m_printer;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Terminal getCurrentPage() throws LuaException
|
||||
{
|
||||
Terminal currentPage = m_printer.getCurrentPage();
|
||||
if( currentPage == null )
|
||||
{
|
||||
throw new LuaException( "Page not started" );
|
||||
}
|
||||
if( currentPage == null ) throw new LuaException( "Page not started" );
|
||||
return currentPage;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +45,9 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
{
|
||||
// Statics
|
||||
|
||||
private static final int[] bottomSlots = new int[] { 7, 8, 9, 10, 11, 12 };
|
||||
private static final int[] topSlots = new int[] { 1, 2, 3, 4, 5, 6 };
|
||||
private static final int[] sideSlots = new int[] { 0 };
|
||||
private static final int[] BOTTOM_SLOTS = new int[] { 7, 8, 9, 10, 11, 12 };
|
||||
private static final int[] TOP_SLOTS = new int[] { 1, 2, 3, 4, 5, 6 };
|
||||
private static final int[] SIDE_SLOTS = new int[] { 0 };
|
||||
|
||||
// Members
|
||||
|
||||
@@ -88,18 +88,12 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
}
|
||||
|
||||
// Read inventory
|
||||
synchronized( m_inventory )
|
||||
NBTTagList itemList = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND );
|
||||
for( int i = 0; i < itemList.tagCount(); i++ )
|
||||
{
|
||||
NBTTagList nbttaglist = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND );
|
||||
for( int i = 0; i < nbttaglist.tagCount(); i++ )
|
||||
{
|
||||
NBTTagCompound itemTag = nbttaglist.getCompoundTagAt( i );
|
||||
int j = itemTag.getByte( "Slot" ) & 0xff;
|
||||
if( j < m_inventory.size() )
|
||||
{
|
||||
m_inventory.set( j, new ItemStack( itemTag ) );
|
||||
}
|
||||
}
|
||||
NBTTagCompound itemTag = itemList.getCompoundTagAt( i );
|
||||
int slot = itemTag.getByte( "Slot" ) & 0xff;
|
||||
if( slot < m_inventory.size() ) m_inventory.set( slot, new ItemStack( itemTag ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,21 +110,18 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
}
|
||||
|
||||
// Write inventory
|
||||
synchronized( m_inventory )
|
||||
NBTTagList itemList = new NBTTagList();
|
||||
for( int i = 0; i < m_inventory.size(); i++ )
|
||||
{
|
||||
NBTTagList nbttaglist = new NBTTagList();
|
||||
for( int i = 0; i < m_inventory.size(); i++ )
|
||||
{
|
||||
if( !m_inventory.get( i ).isEmpty() )
|
||||
{
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
tag.setByte( "Slot", (byte) i );
|
||||
m_inventory.get( i ).writeToNBT( tag );
|
||||
nbttaglist.appendTag( tag );
|
||||
}
|
||||
}
|
||||
nbt.setTag( "Items", nbttaglist );
|
||||
ItemStack stack = m_inventory.get( i );
|
||||
if( stack.isEmpty() ) continue;
|
||||
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
tag.setByte( "Slot", (byte) i );
|
||||
stack.writeToNBT( tag );
|
||||
itemList.appendTag( tag );
|
||||
}
|
||||
nbt.setTag( "Items", itemList );
|
||||
|
||||
return super.writeToNBT( nbt );
|
||||
}
|
||||
@@ -148,7 +139,7 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
return super.shouldRefresh( world, pos, oldState, newState ) || BlockPeripheral.getPeripheralType( newState ) != PeripheralType.Printer;
|
||||
}
|
||||
|
||||
public boolean isPrinting()
|
||||
boolean isPrinting()
|
||||
{
|
||||
return m_printing;
|
||||
}
|
||||
@@ -173,73 +164,59 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack getStackInSlot( int i )
|
||||
public ItemStack getStackInSlot( int slot )
|
||||
{
|
||||
return m_inventory.get( i );
|
||||
return m_inventory.get( slot );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack removeStackFromSlot( int i )
|
||||
public ItemStack removeStackFromSlot( int slot )
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
ItemStack result = m_inventory.get( i );
|
||||
m_inventory.set( i, ItemStack.EMPTY );
|
||||
markDirty();
|
||||
updateAnim();
|
||||
return result;
|
||||
}
|
||||
ItemStack result = m_inventory.get( slot );
|
||||
m_inventory.set( slot, ItemStack.EMPTY );
|
||||
markDirty();
|
||||
updateAnim();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack decrStackSize( int i, int j )
|
||||
public ItemStack decrStackSize( int slot, int count )
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
ItemStack stack = m_inventory.get( slot );
|
||||
if( stack.isEmpty() ) return ItemStack.EMPTY;
|
||||
|
||||
if( stack.getCount() <= count )
|
||||
{
|
||||
if( m_inventory.get( i ).isEmpty() ) return ItemStack.EMPTY;
|
||||
|
||||
if( m_inventory.get( i ).getCount() <= j )
|
||||
{
|
||||
ItemStack itemstack = m_inventory.get( i );
|
||||
m_inventory.set( i, ItemStack.EMPTY );
|
||||
markDirty();
|
||||
updateAnim();
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
ItemStack part = m_inventory.get( i ).splitStack( j );
|
||||
if( m_inventory.get( i ).isEmpty() )
|
||||
{
|
||||
m_inventory.set( i, ItemStack.EMPTY );
|
||||
updateAnim();
|
||||
}
|
||||
markDirty();
|
||||
return part;
|
||||
setInventorySlotContents( slot, ItemStack.EMPTY );
|
||||
return stack;
|
||||
}
|
||||
|
||||
ItemStack part = stack.splitStack( count );
|
||||
if( m_inventory.get( slot ).isEmpty() )
|
||||
{
|
||||
m_inventory.set( slot, ItemStack.EMPTY );
|
||||
updateAnim();
|
||||
}
|
||||
markDirty();
|
||||
return part;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInventorySlotContents( int i, @Nonnull ItemStack stack )
|
||||
public void setInventorySlotContents( int slot, @Nonnull ItemStack stack )
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
m_inventory.set( i, stack );
|
||||
markDirty();
|
||||
updateAnim();
|
||||
}
|
||||
m_inventory.set( slot, stack );
|
||||
markDirty();
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY );
|
||||
markDirty();
|
||||
updateAnim();
|
||||
}
|
||||
for( int i = 0; i < m_inventory.size(); i++ ) m_inventory.set( i, ItemStack.EMPTY );
|
||||
markDirty();
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -249,7 +226,7 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
{
|
||||
return isInk( stack );
|
||||
}
|
||||
else if( slot >= topSlots[0] && slot <= topSlots[topSlots.length - 1] )
|
||||
else if( slot >= TOP_SLOTS[0] && slot <= TOP_SLOTS[TOP_SLOTS.length - 1] )
|
||||
{
|
||||
return isPaper( stack );
|
||||
}
|
||||
@@ -295,11 +272,11 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
switch( side )
|
||||
{
|
||||
case DOWN: // Bottom (Out tray)
|
||||
return bottomSlots;
|
||||
return BOTTOM_SLOTS;
|
||||
case UP: // Top (In tray)
|
||||
return topSlots;
|
||||
return TOP_SLOTS;
|
||||
default: // Sides (Ink)
|
||||
return sideSlots;
|
||||
return SIDE_SLOTS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,14 +288,18 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
return new PrinterPeripheral( this );
|
||||
}
|
||||
|
||||
public Terminal getCurrentPage()
|
||||
@Nullable
|
||||
Terminal getCurrentPage()
|
||||
{
|
||||
return m_printing ? m_page : null;
|
||||
synchronized( m_page )
|
||||
{
|
||||
return m_printing ? m_page : null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean startNewPage()
|
||||
boolean startNewPage()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
synchronized( m_page )
|
||||
{
|
||||
if( !canInputPage() ) return false;
|
||||
if( m_printing && !outputPage() ) return false;
|
||||
@@ -326,49 +307,36 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
}
|
||||
}
|
||||
|
||||
public boolean endCurrentPage()
|
||||
boolean endCurrentPage()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
synchronized( m_page )
|
||||
{
|
||||
if( m_printing && outputPage() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getInkLevel()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
ItemStack inkStack = m_inventory.get( 0 );
|
||||
return isInk( inkStack ) ? inkStack.getCount() : 0;
|
||||
return m_printing && outputPage();
|
||||
}
|
||||
}
|
||||
|
||||
public int getPaperLevel()
|
||||
int getInkLevel()
|
||||
{
|
||||
ItemStack inkStack = m_inventory.get( 0 );
|
||||
return isInk( inkStack ) ? inkStack.getCount() : 0;
|
||||
}
|
||||
|
||||
int getPaperLevel()
|
||||
{
|
||||
int count = 0;
|
||||
synchronized( m_inventory )
|
||||
for( int i = 1; i < 7; i++ )
|
||||
{
|
||||
for( int i = 1; i < 7; i++ )
|
||||
{
|
||||
ItemStack paperStack = m_inventory.get( i );
|
||||
if( !paperStack.isEmpty() && isPaper( paperStack ) )
|
||||
{
|
||||
count += paperStack.getCount();
|
||||
}
|
||||
}
|
||||
ItemStack paperStack = m_inventory.get( i );
|
||||
if( isPaper( paperStack ) ) count += paperStack.getCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void setPageTitle( String title )
|
||||
void setPageTitle( String title )
|
||||
{
|
||||
if( m_printing )
|
||||
synchronized( m_page )
|
||||
{
|
||||
m_pageTitle = title;
|
||||
if( m_printing ) m_pageTitle = title;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,145 +353,126 @@ public class TilePrinter extends TilePeripheralBase implements DefaultSidedInven
|
||||
|
||||
private boolean canInputPage()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
ItemStack inkStack = m_inventory.get( 0 );
|
||||
return !inkStack.isEmpty() && isInk( inkStack ) && getPaperLevel() > 0;
|
||||
}
|
||||
ItemStack inkStack = m_inventory.get( 0 );
|
||||
return !inkStack.isEmpty() && isInk( inkStack ) && getPaperLevel() > 0;
|
||||
}
|
||||
|
||||
private boolean inputPage()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
ItemStack inkStack = m_inventory.get( 0 );
|
||||
if( !isInk( inkStack ) ) return false;
|
||||
|
||||
for( int i = 1; i < 7; i++ )
|
||||
{
|
||||
ItemStack inkStack = m_inventory.get( 0 );
|
||||
if( !isInk( inkStack ) ) return false;
|
||||
ItemStack paperStack = m_inventory.get( i );
|
||||
if( paperStack.isEmpty() || !isPaper( paperStack ) ) continue;
|
||||
|
||||
for( int i = 1; i < 7; i++ )
|
||||
// Setup the new page
|
||||
int colour = inkStack.getItemDamage();
|
||||
m_page.setTextColour( colour >= 0 && colour < 16 ? 15 - colour : 15 );
|
||||
|
||||
m_page.clear();
|
||||
if( paperStack.getItem() instanceof ItemPrintout )
|
||||
{
|
||||
ItemStack paperStack = m_inventory.get( i );
|
||||
if( !paperStack.isEmpty() && isPaper( paperStack ) )
|
||||
m_pageTitle = ItemPrintout.getTitle( paperStack );
|
||||
String[] text = ItemPrintout.getText( paperStack );
|
||||
String[] textColour = ItemPrintout.getColours( paperStack );
|
||||
for( int y = 0; y < m_page.getHeight(); y++ )
|
||||
{
|
||||
// Setup the new page
|
||||
int colour = inkStack.getItemDamage();
|
||||
m_page.setTextColour( colour >= 0 && colour < 16 ? 15 - colour : 15 );
|
||||
|
||||
m_page.clear();
|
||||
if( paperStack.getItem() instanceof ItemPrintout )
|
||||
{
|
||||
m_pageTitle = ItemPrintout.getTitle( paperStack );
|
||||
String[] text = ItemPrintout.getText( paperStack );
|
||||
String[] textColour = ItemPrintout.getColours( paperStack );
|
||||
for( int y = 0; y < m_page.getHeight(); y++ )
|
||||
{
|
||||
m_page.setLine( y, text[y], textColour[y], "" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pageTitle = "";
|
||||
}
|
||||
m_page.setCursorPos( 0, 0 );
|
||||
|
||||
// Decrement ink
|
||||
inkStack.shrink( 1 );
|
||||
if( inkStack.isEmpty() ) m_inventory.set( 0, ItemStack.EMPTY );
|
||||
|
||||
// Decrement paper
|
||||
paperStack.shrink( 1 );
|
||||
if( paperStack.isEmpty() )
|
||||
{
|
||||
m_inventory.set( i, ItemStack.EMPTY );
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
markDirty();
|
||||
m_printing = true;
|
||||
return true;
|
||||
m_page.setLine( y, text[y], textColour[y], "" );
|
||||
}
|
||||
}
|
||||
return false;
|
||||
else
|
||||
{
|
||||
m_pageTitle = "";
|
||||
}
|
||||
m_page.setCursorPos( 0, 0 );
|
||||
|
||||
// Decrement ink
|
||||
inkStack.shrink( 1 );
|
||||
if( inkStack.isEmpty() ) m_inventory.set( 0, ItemStack.EMPTY );
|
||||
|
||||
// Decrement paper
|
||||
paperStack.shrink( 1 );
|
||||
if( paperStack.isEmpty() )
|
||||
{
|
||||
m_inventory.set( i, ItemStack.EMPTY );
|
||||
updateAnim();
|
||||
}
|
||||
|
||||
markDirty();
|
||||
m_printing = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean outputPage()
|
||||
{
|
||||
synchronized( m_page )
|
||||
int height = m_page.getHeight();
|
||||
String[] lines = new String[height];
|
||||
String[] colours = new String[height];
|
||||
for( int i = 0; i < height; i++ )
|
||||
{
|
||||
int height = m_page.getHeight();
|
||||
String[] lines = new String[height];
|
||||
String[] colours = new String[height];
|
||||
for( int i = 0; i < height; i++ )
|
||||
{
|
||||
lines[i] = m_page.getLine( i ).toString();
|
||||
colours[i] = m_page.getTextColourLine( i ).toString();
|
||||
}
|
||||
|
||||
ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours );
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
for( int slot : bottomSlots )
|
||||
{
|
||||
if( m_inventory.get( slot ).isEmpty() )
|
||||
{
|
||||
setInventorySlotContents( slot, stack );
|
||||
m_printing = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
lines[i] = m_page.getLine( i ).toString();
|
||||
colours[i] = m_page.getTextColourLine( i ).toString();
|
||||
}
|
||||
|
||||
ItemStack stack = ItemPrintout.createSingleFromTitleAndText( m_pageTitle, lines, colours );
|
||||
for( int slot : BOTTOM_SLOTS )
|
||||
{
|
||||
if( m_inventory.get( slot ).isEmpty() )
|
||||
{
|
||||
setInventorySlotContents( slot, stack );
|
||||
m_printing = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void ejectContents()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
for( int i = 0; i < 13; i++ )
|
||||
{
|
||||
for( int i = 0; i < 13; i++ )
|
||||
ItemStack stack = m_inventory.get( i );
|
||||
if( !stack.isEmpty() )
|
||||
{
|
||||
ItemStack stack = m_inventory.get( i );
|
||||
if( !stack.isEmpty() )
|
||||
{
|
||||
// Remove the stack from the inventory
|
||||
setInventorySlotContents( i, ItemStack.EMPTY );
|
||||
// Remove the stack from the inventory
|
||||
setInventorySlotContents( i, ItemStack.EMPTY );
|
||||
|
||||
// Spawn the item in the world
|
||||
BlockPos pos = getPos();
|
||||
double x = pos.getX() + 0.5;
|
||||
double y = pos.getY() + 0.75;
|
||||
double z = pos.getZ() + 0.5;
|
||||
WorldUtil.dropItemStack( stack, getWorld(), x, y, z );
|
||||
}
|
||||
// Spawn the item in the world
|
||||
BlockPos pos = getPos();
|
||||
double x = pos.getX() + 0.5;
|
||||
double y = pos.getY() + 0.75;
|
||||
double z = pos.getZ() + 0.5;
|
||||
WorldUtil.dropItemStack( stack, getWorld(), x, y, z );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateAnim()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
int anim = 0;
|
||||
for( int i = 1; i < 7; i++ )
|
||||
{
|
||||
int anim = 0;
|
||||
for( int i = 1; i < 7; i++ )
|
||||
ItemStack stack = m_inventory.get( i );
|
||||
if( !stack.isEmpty() && isPaper( stack ) )
|
||||
{
|
||||
ItemStack stack = m_inventory.get( i );
|
||||
if( !stack.isEmpty() && isPaper( stack ) )
|
||||
{
|
||||
anim += 1;
|
||||
break;
|
||||
}
|
||||
anim += 1;
|
||||
break;
|
||||
}
|
||||
for( int i = 7; i < 13; i++ )
|
||||
{
|
||||
ItemStack stack = m_inventory.get( i );
|
||||
if( !stack.isEmpty() && isPaper( stack ) )
|
||||
{
|
||||
anim += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setAnim( anim );
|
||||
}
|
||||
for( int i = 7; i < 13; i++ )
|
||||
{
|
||||
ItemStack stack = m_inventory.get( i );
|
||||
if( !stack.isEmpty() && isPaper( stack ) )
|
||||
{
|
||||
anim += 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setAnim( anim );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -44,7 +44,7 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
||||
{
|
||||
// FIXME: Should be abstract, but we need this for Plethora compat. We'll
|
||||
// be able to change this in a few versions as we implement both there.
|
||||
@SuppressWarnings( "deprecation" ) BlockPos pos = getPos();
|
||||
BlockPos pos = getPos();
|
||||
return new Vec3d( pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5 );
|
||||
}
|
||||
|
||||
@@ -71,8 +71,8 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
||||
public String[] getMethodNames()
|
||||
{
|
||||
return new String[] {
|
||||
"playSound", // Plays sound at resourceLocator
|
||||
"playNote" // Plays note
|
||||
"playSound",
|
||||
"playNote",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -35,9 +35,7 @@ public class PocketAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"pocket"
|
||||
};
|
||||
return new String[] { "pocket" };
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -46,7 +44,7 @@ public class PocketAPI implements ILuaAPI
|
||||
{
|
||||
return new String[] {
|
||||
"equipBack",
|
||||
"unequipBack"
|
||||
"unequipBack",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,13 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler
|
||||
@Override
|
||||
public int refuel( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack currentStack, int slot, int limit )
|
||||
{
|
||||
ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false );
|
||||
int fuelToGive = getFuelPerItem( stack ) * stack.getCount();
|
||||
int fuelSpaceLeft = turtle.getFuelLimit() - turtle.getFuelLevel();
|
||||
int fuelPerItem = getFuelPerItem( turtle.getItemHandler().getStackInSlot( slot ) );
|
||||
int fuelItemLimit = (int) Math.ceil( fuelSpaceLeft / (double) fuelPerItem );
|
||||
if( limit > fuelItemLimit ) limit = fuelItemLimit;
|
||||
|
||||
ItemStack stack = turtle.getItemHandler().extractItem( slot, limit, false );
|
||||
int fuelToGive = fuelPerItem * stack.getCount();
|
||||
// Store the replacement item in the inventory
|
||||
ItemStack replacementStack = stack.getItem().getContainerItem( stack );
|
||||
if( !replacementStack.isEmpty() )
|
||||
|
||||
@@ -45,9 +45,7 @@ public class TurtleAPI implements ILuaAPI
|
||||
@Override
|
||||
public String[] getNames()
|
||||
{
|
||||
return new String[] {
|
||||
"turtle"
|
||||
};
|
||||
return new String[] { "turtle" };
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -336,9 +334,11 @@ public class TurtleAPI implements ILuaAPI
|
||||
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Up ) );
|
||||
case 40: // inspectDown
|
||||
return tryCommand( context, new TurtleInspectCommand( InteractDirection.Down ) );
|
||||
case 41:
|
||||
case 41: // getItemDetail
|
||||
{
|
||||
// getItemDetail
|
||||
// FIXME: There's a race condition here if the stack is being modified (mutating NBT, etc...)
|
||||
// on another thread. The obvious solution is to move this into a command, but some programs rely
|
||||
// on this having a 0-tick delay.
|
||||
int slot = parseOptionalSlotNumber( args, 0, m_turtle.getSelectedSlot() );
|
||||
ItemStack stack = m_turtle.getInventory().getStackInSlot( slot );
|
||||
if( stack.isEmpty() ) return new Object[] { null };
|
||||
|
||||
@@ -218,7 +218,7 @@ public class BlockTurtle extends BlockComputerBase
|
||||
@Deprecated
|
||||
public float getExplosionResistance( Entity exploder )
|
||||
{
|
||||
if( getFamily() == ComputerFamily.Advanced && (exploder instanceof EntityLivingBase || exploder instanceof EntityFireball) )
|
||||
if( getFamily() == ComputerFamily.Advanced || exploder instanceof EntityLivingBase || exploder instanceof EntityFireball )
|
||||
{
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@@ -43,19 +43,16 @@ import net.minecraftforge.items.wrapper.InvWrapper;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
|
||||
import static net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY;
|
||||
|
||||
public class TileTurtle extends TileComputerBase implements ITurtleTile, DefaultInventory
|
||||
{
|
||||
// Statics
|
||||
|
||||
public static final int INVENTORY_SIZE = 16;
|
||||
public static final int INVENTORY_WIDTH = 4;
|
||||
public static final int INVENTORY_HEIGHT = 4;
|
||||
|
||||
// Members
|
||||
|
||||
enum MoveState
|
||||
{
|
||||
NOT_MOVED,
|
||||
@@ -63,12 +60,12 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
MOVED
|
||||
}
|
||||
|
||||
private NonNullList<ItemStack> m_inventory;
|
||||
private NonNullList<ItemStack> m_previousInventory;
|
||||
private final NonNullList<ItemStack> m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
|
||||
private final NonNullList<ItemStack> m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
|
||||
private final IItemHandlerModifiable m_itemHandler = new InvWrapper( this );
|
||||
private boolean m_inventoryChanged;
|
||||
private TurtleBrain m_brain;
|
||||
private MoveState m_moveState;
|
||||
private boolean m_inventoryChanged = false;
|
||||
private TurtleBrain m_brain = new TurtleBrain( this );
|
||||
private MoveState m_moveState = MoveState.NOT_MOVED;
|
||||
private ComputerFamily m_family;
|
||||
|
||||
public TileTurtle()
|
||||
@@ -78,15 +75,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
|
||||
public TileTurtle( ComputerFamily family )
|
||||
{
|
||||
m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
|
||||
m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
|
||||
m_inventoryChanged = false;
|
||||
m_brain = new TurtleBrain( this );
|
||||
m_moveState = MoveState.NOT_MOVED;
|
||||
m_family = family;
|
||||
}
|
||||
|
||||
public boolean hasMoved()
|
||||
private boolean hasMoved()
|
||||
{
|
||||
return m_moveState == MoveState.MOVED;
|
||||
}
|
||||
@@ -95,7 +87,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
protected ServerComputer createComputer( int instanceID, int id )
|
||||
{
|
||||
ServerComputer computer = new ServerComputer(
|
||||
getWorld(), id, m_label, instanceID, getFamily(),
|
||||
getWorld(), id, label, instanceID, getFamily(),
|
||||
ComputerCraft.terminalWidth_turtle, ComputerCraft.terminalHeight_turtle
|
||||
);
|
||||
computer.setPosition( getPos() );
|
||||
@@ -224,18 +216,15 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
{
|
||||
super.update();
|
||||
m_brain.update();
|
||||
synchronized( m_inventory )
|
||||
if( !getWorld().isRemote && m_inventoryChanged )
|
||||
{
|
||||
if( !getWorld().isRemote && m_inventoryChanged )
|
||||
{
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null ) computer.queueEvent( "turtle_inventory" );
|
||||
ServerComputer computer = getServerComputer();
|
||||
if( computer != null ) computer.queueEvent( "turtle_inventory" );
|
||||
|
||||
m_inventoryChanged = false;
|
||||
for( int n = 0; n < getSizeInventory(); n++ )
|
||||
{
|
||||
m_previousInventory.set( n, InventoryUtil.copyItem( getStackInSlot( n ) ) );
|
||||
}
|
||||
m_inventoryChanged = false;
|
||||
for( int n = 0; n < getSizeInventory(); n++ )
|
||||
{
|
||||
m_previousInventory.set( n, InventoryUtil.copyItem( getStackInSlot( n ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -270,8 +259,8 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
|
||||
// Read inventory
|
||||
NBTTagList nbttaglist = nbt.getTagList( "Items", Constants.NBT.TAG_COMPOUND );
|
||||
m_inventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
|
||||
m_previousInventory = NonNullList.withSize( INVENTORY_SIZE, ItemStack.EMPTY );
|
||||
m_inventory.clear();
|
||||
m_previousInventory.clear();
|
||||
for( int i = 0; i < nbttaglist.tagCount(); i++ )
|
||||
{
|
||||
NBTTagCompound tag = nbttaglist.getCompoundTagAt( i );
|
||||
@@ -317,12 +306,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
return hasPeripheralUpgradeOnSide( localSide );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRedstoneBlockedOnSide( ComputerSide localSide )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// IDirectionalTile
|
||||
|
||||
@Override
|
||||
@@ -388,7 +371,7 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
return m_family;
|
||||
}
|
||||
|
||||
public void setOwningPlayer( GameProfile player )
|
||||
void setOwningPlayer( GameProfile player )
|
||||
{
|
||||
m_brain.setOwningPlayer( player );
|
||||
markDirty();
|
||||
@@ -416,109 +399,76 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
@Override
|
||||
public ItemStack getStackInSlot( int slot )
|
||||
{
|
||||
if( slot >= 0 && slot < INVENTORY_SIZE )
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
return m_inventory.get( slot );
|
||||
}
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
return slot >= 0 && slot < INVENTORY_SIZE ? m_inventory.get( slot ) : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack removeStackFromSlot( int slot )
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
ItemStack result = getStackInSlot( slot );
|
||||
setInventorySlotContents( slot, ItemStack.EMPTY );
|
||||
return result;
|
||||
}
|
||||
ItemStack result = getStackInSlot( slot );
|
||||
setInventorySlotContents( slot, ItemStack.EMPTY );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public ItemStack decrStackSize( int slot, int count )
|
||||
{
|
||||
if( count == 0 )
|
||||
if( count == 0 ) return ItemStack.EMPTY;
|
||||
|
||||
ItemStack stack = getStackInSlot( slot );
|
||||
if( stack.isEmpty() ) return ItemStack.EMPTY;
|
||||
|
||||
if( stack.getCount() <= count )
|
||||
{
|
||||
return ItemStack.EMPTY;
|
||||
setInventorySlotContents( slot, ItemStack.EMPTY );
|
||||
return stack;
|
||||
}
|
||||
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
ItemStack stack = getStackInSlot( slot );
|
||||
if( stack.isEmpty() )
|
||||
{
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
if( stack.getCount() <= count )
|
||||
{
|
||||
setInventorySlotContents( slot, ItemStack.EMPTY );
|
||||
return stack;
|
||||
}
|
||||
|
||||
ItemStack part = stack.splitStack( count );
|
||||
onInventoryDefinitelyChanged();
|
||||
return part;
|
||||
}
|
||||
ItemStack part = stack.splitStack( count );
|
||||
onInventoryDefinitelyChanged();
|
||||
return part;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInventorySlotContents( int i, @Nonnull ItemStack stack )
|
||||
{
|
||||
if( i >= 0 && i < INVENTORY_SIZE )
|
||||
if( i >= 0 && i < INVENTORY_SIZE && !InventoryUtil.areItemsEqual( stack, m_inventory.get( i ) ) )
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
{
|
||||
if( !InventoryUtil.areItemsEqual( stack, m_inventory.get( i ) ) )
|
||||
{
|
||||
m_inventory.set( i, stack );
|
||||
onInventoryDefinitelyChanged();
|
||||
}
|
||||
}
|
||||
m_inventory.set( i, stack );
|
||||
onInventoryDefinitelyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
synchronized( m_inventory )
|
||||
boolean changed = false;
|
||||
for( int i = 0; i < INVENTORY_SIZE; i++ )
|
||||
{
|
||||
boolean changed = false;
|
||||
for( int i = 0; i < INVENTORY_SIZE; i++ )
|
||||
if( !m_inventory.get( i ).isEmpty() )
|
||||
{
|
||||
if( !m_inventory.get( i ).isEmpty() )
|
||||
{
|
||||
m_inventory.set( i, ItemStack.EMPTY );
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if( changed )
|
||||
{
|
||||
onInventoryDefinitelyChanged();
|
||||
m_inventory.set( i, ItemStack.EMPTY );
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( changed ) onInventoryDefinitelyChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty()
|
||||
{
|
||||
super.markDirty();
|
||||
synchronized( m_inventory )
|
||||
if( !m_inventoryChanged )
|
||||
{
|
||||
if( !m_inventoryChanged )
|
||||
for( int n = 0; n < getSizeInventory(); n++ )
|
||||
{
|
||||
for( int n = 0; n < getSizeInventory(); n++ )
|
||||
if( !ItemStack.areItemStacksEqual( getStackInSlot( n ), m_previousInventory.get( n ) ) )
|
||||
{
|
||||
if( !ItemStack.areItemStacksEqual( getStackInSlot( n ), m_previousInventory.get( n ) ) )
|
||||
{
|
||||
m_inventoryChanged = true;
|
||||
break;
|
||||
}
|
||||
m_inventoryChanged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -580,8 +530,8 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default
|
||||
public void transferStateFrom( TileTurtle copy )
|
||||
{
|
||||
super.transferStateFrom( copy );
|
||||
m_inventory = copy.m_inventory;
|
||||
m_previousInventory = copy.m_previousInventory;
|
||||
Collections.copy( m_inventory, copy.m_inventory );
|
||||
Collections.copy( m_previousInventory, copy.m_previousInventory );
|
||||
m_inventoryChanged = copy.m_inventoryChanged;
|
||||
m_brain = copy.m_brain;
|
||||
m_brain.setOwner( this );
|
||||
|
||||
@@ -908,14 +908,14 @@ public class TurtleBrain implements ITurtleAccess
|
||||
else
|
||||
{
|
||||
computer.queueEvent( "turtle_response", new Object[] {
|
||||
callbackID, true
|
||||
callbackID, true,
|
||||
} );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
computer.queueEvent( "turtle_response", new Object[] {
|
||||
callbackID, false, result != null ? result.getErrorMessage() : null
|
||||
callbackID, false, result != null ? result.getErrorMessage() : null,
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,19 +53,15 @@ public class TurtleCompareCommand implements ITurtleCommand
|
||||
Block lookAtBlock = lookAtState.getBlock();
|
||||
if( !lookAtBlock.isAir( lookAtState, world, newPosition ) )
|
||||
{
|
||||
// Try createStackedBlock first
|
||||
// Try getSilkTouchDrop first
|
||||
if( !lookAtBlock.hasTileEntity( lookAtState ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
Method method = ReflectionHelper.findMethod(
|
||||
Block.class,
|
||||
"func_180643_i", "getSilkTouchDrop",
|
||||
IBlockState.class
|
||||
);
|
||||
Method method = ReflectionHelper.findMethod( Block.class, "getSilkTouchDrop", "func_180643_i", IBlockState.class );
|
||||
lookAtStack = (ItemStack) method.invoke( lookAtBlock, lookAtState );
|
||||
}
|
||||
catch( ReflectiveOperationException ignored )
|
||||
catch( ReflectiveOperationException | RuntimeException ignored )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
||||
|
||||
// Remember old block
|
||||
EnumFacing direction = m_direction.toWorldDir( turtle );
|
||||
World world = turtle.getWorld();
|
||||
BlockPos coordinates = turtle.getPosition().offset( direction );
|
||||
|
||||
// Create a fake player, and orient it appropriately
|
||||
|
||||
@@ -26,8 +26,8 @@ public class ContainerTurtle extends Container implements IContainerComputer
|
||||
{
|
||||
private static final int PROGRESS_ID_SELECTED_SLOT = 0;
|
||||
|
||||
public final int m_playerInvStartY;
|
||||
public final int m_turtleInvStartX;
|
||||
public final int playerInvStartY;
|
||||
public final int turtleInvStartX;
|
||||
|
||||
private final ITurtleAccess m_turtle;
|
||||
private IComputer m_computer;
|
||||
@@ -36,8 +36,8 @@ public class ContainerTurtle extends Container implements IContainerComputer
|
||||
|
||||
protected ContainerTurtle( IInventory playerInventory, ITurtleAccess turtle, int playerInvStartY, int turtleInvStartX )
|
||||
{
|
||||
m_playerInvStartY = playerInvStartY;
|
||||
m_turtleInvStartX = turtleInvStartX;
|
||||
this.playerInvStartY = playerInvStartY;
|
||||
this.turtleInvStartX = turtleInvStartX;
|
||||
|
||||
m_turtle = turtle;
|
||||
m_selectedSlot = m_turtle.getWorld().isRemote ? 0 : m_turtle.getSelectedSlot();
|
||||
|
||||
@@ -73,7 +73,10 @@ public class ItemTurtleLegacy extends ItemTurtleBase
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getOverlay( @Nonnull ItemStack stack ) { return null; }
|
||||
public ResourceLocation getOverlay( @Nonnull ItemStack stack )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFuelLevel( @Nonnull ItemStack stack )
|
||||
|
||||
@@ -54,7 +54,7 @@ public class TurtleHoe extends TurtleTool
|
||||
{
|
||||
if( verb == TurtleVerb.Dig )
|
||||
{
|
||||
ItemStack hoe = m_item.copy();
|
||||
ItemStack hoe = item.copy();
|
||||
ItemStack remainder = TurtlePlaceCommand.deploy( hoe, turtle, direction, null, null );
|
||||
if( remainder != hoe )
|
||||
{
|
||||
|
||||
@@ -60,7 +60,7 @@ public class TurtleShovel extends TurtleTool
|
||||
{
|
||||
if( verb == TurtleVerb.Dig )
|
||||
{
|
||||
ItemStack shovel = m_item.copy();
|
||||
ItemStack shovel = item.copy();
|
||||
ItemStack remainder = TurtlePlaceCommand.deploy( shovel, turtle, direction, null, null );
|
||||
if( remainder != shovel )
|
||||
{
|
||||
|
||||
@@ -48,18 +48,18 @@ import java.util.function.Function;
|
||||
|
||||
public class TurtleTool extends AbstractTurtleUpgrade
|
||||
{
|
||||
protected ItemStack m_item;
|
||||
protected final ItemStack item;
|
||||
|
||||
public TurtleTool( ResourceLocation id, int legacyID, String adjective, Item item )
|
||||
{
|
||||
super( id, legacyID, TurtleUpgradeType.Tool, adjective, item );
|
||||
m_item = new ItemStack( item, 1, 0 );
|
||||
this.item = new ItemStack( item, 1, 0 );
|
||||
}
|
||||
|
||||
public TurtleTool( ResourceLocation id, int legacyID, Item item )
|
||||
{
|
||||
super( id, legacyID, TurtleUpgradeType.Tool, item );
|
||||
m_item = new ItemStack( item, 1, 0 );
|
||||
this.item = new ItemStack( item, 1, 0 );
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@@ -76,7 +76,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
|
||||
);
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
return Pair.of(
|
||||
mc.getRenderItem().getItemModelMesher().getItemModel( m_item ),
|
||||
mc.getRenderItem().getItemModelMesher().getItemModel( item ),
|
||||
transform
|
||||
);
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
|
||||
if( hit != null )
|
||||
{
|
||||
// Load up the turtle's inventory
|
||||
ItemStack stackCopy = m_item.copy();
|
||||
ItemStack stackCopy = item.copy();
|
||||
turtlePlayer.loadInventory( stackCopy );
|
||||
|
||||
Entity hitEntity = hit.getKey();
|
||||
@@ -202,7 +202,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
|
||||
IBlockState state = world.getBlockState( blockPosition );
|
||||
|
||||
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction );
|
||||
turtlePlayer.loadInventory( m_item.copy() );
|
||||
turtlePlayer.loadInventory( item.copy() );
|
||||
|
||||
if( ComputerCraft.turtlesObeyBlockProtection )
|
||||
{
|
||||
@@ -246,7 +246,7 @@ public class TurtleTool extends AbstractTurtleUpgrade
|
||||
boolean canHarvest = state.getBlock().canHarvestBlock( world, blockPosition, turtlePlayer );
|
||||
boolean canBreak = state.getBlock().removedByPlayer( state, world, blockPosition, turtlePlayer, canHarvest );
|
||||
if( canBreak ) state.getBlock().onPlayerDestroy( world, blockPosition, state );
|
||||
if( canHarvest )
|
||||
if( canHarvest && canBreak )
|
||||
{
|
||||
state.getBlock().harvestBlock( world, turtlePlayer, blockPosition, state, tile, turtlePlayer.getHeldItemMainhand() );
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ public final class ColourUtils
|
||||
"dyeBlack", "dyeRed", "dyeGreen", "dyeBrown",
|
||||
"dyeBlue", "dyePurple", "dyeCyan", "dyeLightGray",
|
||||
"dyeGray", "dyePink", "dyeLime", "dyeYellow",
|
||||
"dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite"
|
||||
"dyeLightBlue", "dyeMagenta", "dyeOrange", "dyeWhite",
|
||||
};
|
||||
|
||||
private static int[] ids;
|
||||
|
||||
@@ -72,12 +72,11 @@ public class Palette
|
||||
|
||||
public static double[] decodeRGB8( int rgb )
|
||||
{
|
||||
return new double[]
|
||||
{
|
||||
((rgb >> 16) & 0xFF) / 255.0f,
|
||||
((rgb >> 8) & 0xFF) / 255.0f,
|
||||
(rgb & 0xFF) / 255.0f
|
||||
};
|
||||
return new double[] {
|
||||
((rgb >> 16) & 0xFF) / 255.0f,
|
||||
((rgb >> 8) & 0xFF) / 255.0f,
|
||||
(rgb & 0xFF) / 255.0f,
|
||||
};
|
||||
}
|
||||
|
||||
public NBTTagCompound writeToNBT( NBTTagCompound nbt )
|
||||
|
||||
195
src/main/resources/assets/computercraft/lang/zh_cn.lang
Normal file
195
src/main/resources/assets/computercraft/lang/zh_cn.lang
Normal file
@@ -0,0 +1,195 @@
|
||||
itemGroup.computercraft=CC: Tweaked
|
||||
|
||||
tile.computercraft:computer.name=计算机
|
||||
tile.computercraft:advanced_computer.name=高级计算机
|
||||
tile.computercraft:drive.name=磁盘驱动器
|
||||
tile.computercraft:printer.name=打印机
|
||||
tile.computercraft:monitor.name=显示器
|
||||
tile.computercraft:advanced_monitor.name=高级显示器
|
||||
tile.computercraft:wireless_modem.name=无线调制解调器
|
||||
tile.computercraft:wired_modem.name=有线调制解调器
|
||||
tile.computercraft:cable.name=网络电缆
|
||||
tile.computercraft:command_computer.name=命令电脑
|
||||
tile.computercraft:advanced_modem.name=末影调制解调器
|
||||
tile.computercraft:speaker.name=扬声器
|
||||
|
||||
tile.computercraft:turtle.name=海龟
|
||||
tile.computercraft:turtle.upgraded.name=%s海龟
|
||||
tile.computercraft:turtle.upgraded_twice.name=%s%s海龟
|
||||
tile.computercraft:advanced_turtle.name=高级海龟
|
||||
tile.computercraft:advanced_turtle.upgraded.name=高级%s海龟
|
||||
tile.computercraft:advanced_turtle.upgraded_twice.name=高级%s%s海龟
|
||||
|
||||
item.computercraft:disk.name=软盘
|
||||
item.computercraft:treasure_disk.name=软盘
|
||||
item.computercraft:page.name=打印纸
|
||||
item.computercraft:pages.name=打印纸
|
||||
item.computercraft:book.name=打印书
|
||||
|
||||
item.computercraft:pocket_computer.name=手提计算机
|
||||
item.computercraft:pocket_computer.upgraded.name=%s手提计算机
|
||||
item.computercraft:advanced_pocket_computer.name=高级手提计算机
|
||||
item.computercraft:advanced_pocket_computer.upgraded.name=高级%s手提计算机
|
||||
|
||||
upgrade.minecraft:diamond_sword.adjective=战斗
|
||||
upgrade.minecraft:diamond_shovel.adjective=挖掘
|
||||
upgrade.minecraft:diamond_pickaxe.adjective=采掘
|
||||
upgrade.minecraft:diamond_axe.adjective=伐木
|
||||
upgrade.minecraft:diamond_hoe.adjective=耕种
|
||||
upgrade.computercraft:wireless_modem.adjective=无线
|
||||
upgrade.minecraft:crafting_table.adjective=合成
|
||||
upgrade.computercraft:advanced_modem.adjective=末影
|
||||
upgrade.computercraft:speaker.adjective=喧闹
|
||||
|
||||
chat.computercraft.wired_modem.peripheral_connected=Peripheral "%s"连接到网络
|
||||
chat.computercraft.wired_modem.peripheral_disconnected=Peripheral "%s"与网络断开连接
|
||||
|
||||
# Command descriptions, usage and any additional messages.
|
||||
commands.computercraft.synopsis=各种控制计算机的命令.
|
||||
commands.computercraft.desc=/computercraft命令提供各种调试和管理工具,用于控制和与计算机交互.
|
||||
|
||||
commands.computercraft.help.synopsis=为特定的命令提供帮助
|
||||
commands.computercraft.help.desc=
|
||||
commands.computercraft.help.usage=[command]
|
||||
commands.computercraft.help.no_children=%s没有子命令
|
||||
commands.computercraft.help.no_command=没有这样的命令'%s'
|
||||
|
||||
commands.computercraft.dump.synopsis=显示计算机的状态.
|
||||
commands.computercraft.dump.desc=显示所有计算机的状态或某台计算机的特定信息. 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer").
|
||||
commands.computercraft.dump.usage=[id]
|
||||
commands.computercraft.dump.action=查看有关此计算机的更多信息
|
||||
|
||||
commands.computercraft.shutdown.synopsis=远程关闭计算机.
|
||||
commands.computercraft.shutdown.desc=关闭列出的计算机或全部计算机(如果未指定). 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer").
|
||||
commands.computercraft.shutdown.usage=[ids...]
|
||||
commands.computercraft.shutdown.done=关闭%s/%s计算机
|
||||
|
||||
commands.computercraft.turn_on.synopsis=远程打开计算机.
|
||||
commands.computercraft.turn_on.desc=打开列出的计算机. 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. "@My Computer").
|
||||
commands.computercraft.turn_on.usage=[ids...]
|
||||
commands.computercraft.turn_on.done=打开%s/%s计算机
|
||||
|
||||
commands.computercraft.tp.synopsis=传送到特定的计算机.
|
||||
commands.computercraft.tp.desc=传送到计算机的位置. 你可以指定计算机的实例id (例如. 123)或计算机id (例如. #123).
|
||||
commands.computercraft.tp.usage=<id>
|
||||
commands.computercraft.tp.action=传送到这台电脑
|
||||
commands.computercraft.tp.not_entity=无法为非玩家打开终端
|
||||
commands.computercraft.tp.not_there=无法在世界上定位电脑
|
||||
|
||||
commands.computercraft.view.synopsis=查看计算机的终端.
|
||||
commands.computercraft.view.desc=打开计算机的终端,允许远程控制计算机. 这不提供对海龟库存的访问. 你可以指定计算机的实例id (例如. 123)或计算机id (例如. #123).
|
||||
commands.computercraft.view.usage=<id>
|
||||
commands.computercraft.view.action=查看此计算机
|
||||
commands.computercraft.view.not_player=无法为非玩家打开终端
|
||||
|
||||
commands.computercraft.track.synopsis=跟踪计算机的执行时间.
|
||||
commands.computercraft.track.desc=跟踪计算机执行的时间以及它们处理的事件数. 这以/forge track类似的方式呈现信息,可用于诊断滞后.
|
||||
|
||||
commands.computercraft.track.start.synopsis=开始跟踪所有计算机
|
||||
commands.computercraft.track.start.desc=开始跟踪所有计算机的执行时间和事件计数. 这将放弃先前运行的结果.
|
||||
commands.computercraft.track.start.usage=
|
||||
commands.computercraft.track.start.stop=运行%s以停止跟踪并查看结果
|
||||
|
||||
commands.computercraft.track.stop.synopsis=停止跟踪所有计算机
|
||||
commands.computercraft.track.stop.desc=停止跟踪所有计算机的事件和执行时间
|
||||
commands.computercraft.track.stop.usage=
|
||||
commands.computercraft.track.stop.action=点击停止跟踪
|
||||
commands.computercraft.track.stop.not_enabled=目前没有跟踪计算机
|
||||
|
||||
commands.computercraft.track.dump.synopsis=输出最新的跟踪结果
|
||||
commands.computercraft.track.dump.desc=输出计算机跟踪的最新结果.
|
||||
commands.computercraft.track.dump.usage=[kind]
|
||||
commands.computercraft.track.dump.no_timings=没有时间可用
|
||||
commands.computercraft.track.dump.no_field=未知字节'%s'
|
||||
commands.computercraft.track.dump.computer=计算器
|
||||
|
||||
commands.computercraft.reload.synopsis=重新加载ComputerCraft配置文件
|
||||
commands.computercraft.reload.desc=重新加载ComputerCraft配置文件
|
||||
commands.computercraft.reload.usage=
|
||||
commands.computercraft.reload.done=重新加载配置
|
||||
|
||||
commands.computercraft.queue.synopsis=将computer_command事件发送到命令计算机
|
||||
commands.computercraft.queue.desc=发送computer_command事件到命令计算机,并传递其他参数. 这主要是为地图制作者设计的, 作为/trigger更加计算机友好的版本. 任何玩家都可以运行命令, 这很可能是通过文本组件的点击事件完成的.
|
||||
commands.computercraft.queue.usage=<id> [args...]
|
||||
|
||||
commands.computercraft.generic.no_position=<无位置>
|
||||
commands.computercraft.generic.position=%s, %s, %s
|
||||
commands.computercraft.generic.yes=Y
|
||||
commands.computercraft.generic.no=N
|
||||
commands.computercraft.generic.exception=未处理的异常(%s)
|
||||
commands.computercraft.generic.additional_rows=%d额外的行…
|
||||
|
||||
commands.computercraft.argument.no_matching=没有计算机匹配'%s'
|
||||
commands.computercraft.argument.many_matching=多台计算机匹配'%s' (实例%s)
|
||||
commands.computercraft.argument.not_number='%s'不是一个数字
|
||||
|
||||
# Names for the various tracking fields.
|
||||
tracking_field.computercraft.tasks.name=任务
|
||||
tracking_field.computercraft.total.name=总计时间
|
||||
tracking_field.computercraft.average.name=平均时间
|
||||
tracking_field.computercraft.max.name=最大时间
|
||||
|
||||
tracking_field.computercraft.server_count.name=服务器任务计数
|
||||
tracking_field.computercraft.server_time.name=服务器任务时间
|
||||
|
||||
tracking_field.computercraft.peripheral.name=外围设备呼叫
|
||||
tracking_field.computercraft.fs.name=文件系统操作
|
||||
tracking_field.computercraft.turtle.name=海龟行动
|
||||
|
||||
tracking_field.computercraft.http.name=HTTP需求
|
||||
tracking_field.computercraft.http_upload.name=HTTP上传
|
||||
tracking_field.computercraft.http_download.name=HTTP下载
|
||||
|
||||
tracking_field.computercraft.websocket_incoming.name=Websocket传入
|
||||
tracking_field.computercraft.websocket_outgoing.name=Websocket传出
|
||||
|
||||
tracking_field.computercraft.coroutines_created.name=协同创建
|
||||
tracking_field.computercraft.coroutines_dead.name=协同处理
|
||||
|
||||
# Misc tooltips
|
||||
gui.computercraft.tooltip.copy=复制到剪贴板
|
||||
gui.computercraft.tooltip.computer_id=(计算机ID: %s)
|
||||
gui.computercraft.tooltip.disk_id=(磁盘ID: %s)
|
||||
|
||||
# Config options
|
||||
gui.computercraft:config.computer_space_limit=计算机空间限制(字节)
|
||||
gui.computercraft:config.floppy_space_limit=软盘空间限制(字节)
|
||||
gui.computercraft:config.maximum_open_files=每台计算机打开的最大文件数
|
||||
gui.computercraft:config.disable_lua51_features=禁用Lua 5.1功能
|
||||
gui.computercraft:config.default_computer_settings=默认计算机设置
|
||||
gui.computercraft:config.debug_enabled=启用debug库
|
||||
gui.computercraft:config.log_computer_errors=记录计算机错误
|
||||
|
||||
gui.computercraft:config.execution=执行
|
||||
gui.computercraft:config.execution.computer_threads=计算机线程数
|
||||
gui.computercraft:config.execution.max_main_global_time=服务器全局tick时间限制
|
||||
gui.computercraft:config.execution.max_main_computer_time=服务器计算机tick时间限制
|
||||
|
||||
gui.computercraft:config.http=HTTP
|
||||
gui.computercraft:config.http.enabled=启用HTTP API
|
||||
gui.computercraft:config.http.websocket_enabled=启用websockets
|
||||
gui.computercraft:config.http.whitelist=HTTP白名单
|
||||
gui.computercraft:config.http.blacklist=HTTP黑名单
|
||||
|
||||
gui.computercraft:config.http.timeout=Timeout
|
||||
gui.computercraft:config.http.max_requests=最大并发请求数
|
||||
gui.computercraft:config.http.max_download=最大响应数据大小
|
||||
gui.computercraft:config.http.max_upload=最大请求数据大小
|
||||
gui.computercraft:config.http.max_websockets=最大并发websockets数
|
||||
gui.computercraft:config.http.max_websocket_message=最大websockets消息大小
|
||||
|
||||
gui.computercraft:config.peripheral=外围设备
|
||||
gui.computercraft:config.peripheral.command_block_enabled=启用命令方块外设
|
||||
gui.computercraft:config.peripheral.modem_range=调制解调器范围(默认)
|
||||
gui.computercraft:config.peripheral.modem_high_altitude_range=调制解调器范围(高海拔)
|
||||
gui.computercraft:config.peripheral.modem_range_during_storm=调制解调器范围(恶劣天气)
|
||||
gui.computercraft:config.peripheral.modem_high_altitude_range_during_storm=调制解调器范围(高海拔, 恶劣天气)
|
||||
gui.computercraft:config.peripheral.max_notes_per_tick=计算机一次可以播放的最大音符数量
|
||||
|
||||
gui.computercraft:config.turtle=海龟
|
||||
gui.computercraft:config.turtle.need_fuel=启用燃料
|
||||
gui.computercraft:config.turtle.normal_fuel_limit=海龟燃料限制
|
||||
gui.computercraft:config.turtle.advanced_fuel_limit=高级海龟燃料限制
|
||||
gui.computercraft:config.turtle.obey_block_protection=海龟服从方块保护
|
||||
gui.computercraft:config.turtle.can_push=海龟可以推动实体
|
||||
gui.computercraft:config.turtle.disabled_actions=禁用海龟动作
|
||||
@@ -1,5 +1,19 @@
|
||||
-- Load in expect from the module path.
|
||||
--
|
||||
-- Ideally we'd use require, but that is part of the shell, and so is not
|
||||
-- available to the BIOS or any APIs. All APIs load this using dofile, but that
|
||||
-- has not been defined at this point.
|
||||
local expect
|
||||
|
||||
do
|
||||
local h = fs.open("rom/modules/main/cc/expect.lua", "r")
|
||||
local f, err = loadstring(h.readAll(), "@expect.lua")
|
||||
h.close()
|
||||
|
||||
if not f then error(err) end
|
||||
expect = f().expect
|
||||
end
|
||||
|
||||
local nativegetfenv = getfenv
|
||||
if _VERSION == "Lua 5.1" then
|
||||
-- If we're on Lua 5.1, install parts of the Lua 5.2/5.3 API so that programs can be written against it
|
||||
local type = type
|
||||
@@ -20,18 +34,11 @@ if _VERSION == "Lua 5.1" then
|
||||
end
|
||||
|
||||
function load( x, name, mode, env )
|
||||
if type( x ) ~= "string" and type( x ) ~= "function" then
|
||||
error( "bad argument #1 (expected string or function, got " .. type( x ) .. ")", 2 )
|
||||
end
|
||||
if name ~= nil and type( name ) ~= "string" then
|
||||
error( "bad argument #2 (expected string, got " .. type( name ) .. ")", 2 )
|
||||
end
|
||||
if mode ~= nil and type( mode ) ~= "string" then
|
||||
error( "bad argument #3 (expected string, got " .. type( mode ) .. ")", 2 )
|
||||
end
|
||||
if env ~= nil and type( env) ~= "table" then
|
||||
error( "bad argument #4 (expected table, got " .. type( env ) .. ")", 2 )
|
||||
end
|
||||
expect(1, x, "function", "string")
|
||||
expect(2, name, "string", "nil")
|
||||
expect(3, mode, "string", "nil")
|
||||
expect(4, env, "table", "nil")
|
||||
|
||||
local ok, p1, p2 = pcall( function()
|
||||
if type(x) == "string" then
|
||||
local result, err = nativeloadstring( x, name )
|
||||
@@ -76,10 +83,9 @@ if _VERSION == "Lua 5.1" then
|
||||
math.log10 = nil
|
||||
table.maxn = nil
|
||||
else
|
||||
loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname ))
|
||||
loadstring = function(string, chunkname) return nativeloadstring(string, prefix( chunkname )) end
|
||||
|
||||
-- Inject a stub for the old bit library
|
||||
end
|
||||
_G.bit = {
|
||||
bnot = bit32.bnot,
|
||||
band = bit32.band,
|
||||
@@ -175,9 +181,7 @@ end
|
||||
|
||||
-- Install globals
|
||||
function sleep( nTime )
|
||||
if nTime ~= nil and type( nTime ) ~= "number" then
|
||||
error( "bad argument #1 (expected number, got " .. type( nTime ) .. ")", 2 )
|
||||
end
|
||||
expect(1, nTime, "number", "nil")
|
||||
local timer = os.startTimer( nTime or 0 )
|
||||
repeat
|
||||
local sEvent, param = os.pullEvent( "timer" )
|
||||
@@ -185,9 +189,7 @@ function sleep( nTime )
|
||||
end
|
||||
|
||||
function write( sText )
|
||||
if type( sText ) ~= "string" and type( sText ) ~= "number" then
|
||||
error( "bad argument #1 (expected string or number, got " .. type( sText ) .. ")", 2 )
|
||||
end
|
||||
expect(1, sText, "string", "number")
|
||||
|
||||
local w,h = term.getSize()
|
||||
local x,y = term.getCursorPos()
|
||||
@@ -275,18 +277,11 @@ function printError( ... )
|
||||
end
|
||||
|
||||
function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault )
|
||||
if _sReplaceChar ~= nil and type( _sReplaceChar ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _sReplaceChar ) .. ")", 2 )
|
||||
end
|
||||
if _tHistory ~= nil and type( _tHistory ) ~= "table" then
|
||||
error( "bad argument #2 (expected table, got " .. type( _tHistory ) .. ")", 2 )
|
||||
end
|
||||
if _fnComplete ~= nil and type( _fnComplete ) ~= "function" then
|
||||
error( "bad argument #3 (expected function, got " .. type( _fnComplete ) .. ")", 2 )
|
||||
end
|
||||
if _sDefault ~= nil and type( _sDefault ) ~= "string" then
|
||||
error( "bad argument #4 (expected string, got " .. type( _sDefault ) .. ")", 2 )
|
||||
end
|
||||
expect(1, _sReplaceChar, "string", "nil")
|
||||
expect(2, _tHistory, "table", "nil")
|
||||
expect(3, _fnComplete, "function", "nil")
|
||||
expect(4, _sDefault, "string", "nil")
|
||||
|
||||
term.setCursorBlink( true )
|
||||
|
||||
local sLine
|
||||
@@ -544,27 +539,28 @@ function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault )
|
||||
return sLine
|
||||
end
|
||||
|
||||
loadfile = function( _sFile, _tEnv )
|
||||
if type( _sFile ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _sFile ) .. ")", 2 )
|
||||
function loadfile( filename, mode, env )
|
||||
-- Support the previous `loadfile(filename, env)` form instead.
|
||||
if type(mode) == "table" and env == nil then
|
||||
mode, env = nil, mode
|
||||
end
|
||||
if _tEnv ~= nil and type( _tEnv ) ~= "table" then
|
||||
error( "bad argument #2 (expected table, got " .. type( _tEnv ) .. ")", 2 )
|
||||
end
|
||||
local file = fs.open( _sFile, "r" )
|
||||
if file then
|
||||
local func, err = load( file.readAll(), "@" .. fs.getName( _sFile ), "t", _tEnv )
|
||||
file.close()
|
||||
return func, err
|
||||
end
|
||||
return nil, "File not found"
|
||||
|
||||
expect(1, filename, "string")
|
||||
expect(2, mode, "string", "nil")
|
||||
expect(3, env, "table", "nil")
|
||||
|
||||
local file = fs.open( filename, "r" )
|
||||
if not file then return nil, "File not found" end
|
||||
|
||||
local func, err = load( file.readAll(), "@" .. fs.getName( filename ), mode, env )
|
||||
file.close()
|
||||
return func, err
|
||||
end
|
||||
|
||||
dofile = function( _sFile )
|
||||
if type( _sFile ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _sFile ) .. ")", 2 )
|
||||
end
|
||||
local fnFile, e = loadfile( _sFile, _G )
|
||||
function dofile( _sFile )
|
||||
expect(1, _sFile, "string")
|
||||
|
||||
local fnFile, e = loadfile( _sFile, nil, _G )
|
||||
if fnFile then
|
||||
return fnFile()
|
||||
else
|
||||
@@ -574,16 +570,13 @@ end
|
||||
|
||||
-- Install the rest of the OS api
|
||||
function os.run( _tEnv, _sPath, ... )
|
||||
if type( _tEnv ) ~= "table" then
|
||||
error( "bad argument #1 (expected table, got " .. type( _tEnv ) .. ")", 2 )
|
||||
end
|
||||
if type( _sPath ) ~= "string" then
|
||||
error( "bad argument #2 (expected string, got " .. type( _sPath ) .. ")", 2 )
|
||||
end
|
||||
expect(1, _tEnv, "table")
|
||||
expect(2, _sPath, "string")
|
||||
|
||||
local tArgs = table.pack( ... )
|
||||
local tEnv = _tEnv
|
||||
setmetatable( tEnv, { __index = _G } )
|
||||
local fnFile, err = loadfile( _sPath, tEnv )
|
||||
local fnFile, err = loadfile( _sPath, nil, tEnv )
|
||||
if fnFile then
|
||||
local ok, err = pcall( function()
|
||||
fnFile( table.unpack( tArgs, 1, tArgs.n ) )
|
||||
@@ -604,9 +597,7 @@ end
|
||||
|
||||
local tAPIsLoading = {}
|
||||
function os.loadAPI( _sPath )
|
||||
if type( _sPath ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 )
|
||||
end
|
||||
expect(1, _sPath, "string")
|
||||
local sName = fs.getName( _sPath )
|
||||
if sName:sub(-4) == ".lua" then
|
||||
sName = sName:sub(1,-5)
|
||||
@@ -619,7 +610,7 @@ function os.loadAPI( _sPath )
|
||||
|
||||
local tEnv = {}
|
||||
setmetatable( tEnv, { __index = _G } )
|
||||
local fnAPI, err = loadfile( _sPath, tEnv )
|
||||
local fnAPI, err = loadfile( _sPath, nil, tEnv )
|
||||
if fnAPI then
|
||||
local ok, err = pcall( fnAPI )
|
||||
if not ok then
|
||||
@@ -644,9 +635,7 @@ function os.loadAPI( _sPath )
|
||||
end
|
||||
|
||||
function os.unloadAPI( _sName )
|
||||
if type( _sName ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _sName ) .. ")", 2 )
|
||||
end
|
||||
expect(1, _sName, "string")
|
||||
if _sName ~= "_G" and type(_G[_sName]) == "table" then
|
||||
_G[_sName] = nil
|
||||
end
|
||||
@@ -692,9 +681,11 @@ if http then
|
||||
|
||||
local function checkOptions( options, body )
|
||||
checkKey( options, "url", "string")
|
||||
if body == false
|
||||
then checkKey( options, "body", "nil" )
|
||||
else checkKey( options, "body", "string", not body ) end
|
||||
if body == false then
|
||||
checkKey( options, "body", "nil" )
|
||||
else
|
||||
checkKey( options, "body", "string", not body )
|
||||
end
|
||||
checkKey( options, "headers", "table", true )
|
||||
checkKey( options, "method", "string", true )
|
||||
checkKey( options, "redirect", "boolean", true )
|
||||
@@ -725,15 +716,9 @@ if http then
|
||||
return wrapRequest( _url.url, _url )
|
||||
end
|
||||
|
||||
if type( _url ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 )
|
||||
end
|
||||
if _headers ~= nil and type( _headers ) ~= "table" then
|
||||
error( "bad argument #2 (expected table, got " .. type( _headers ) .. ")", 2 )
|
||||
end
|
||||
if _binary ~= nil and type( _binary ) ~= "boolean" then
|
||||
error( "bad argument #3 (expected boolean, got " .. type( _binary ) .. ")", 2 )
|
||||
end
|
||||
expect(1, _url, "string")
|
||||
expect(2, _headers, "table", "nil")
|
||||
expect(3, _binary, "boolean", "nil")
|
||||
return wrapRequest( _url, _url, nil, _headers, _binary )
|
||||
end
|
||||
|
||||
@@ -743,18 +728,10 @@ if http then
|
||||
return wrapRequest( _url.url, _url )
|
||||
end
|
||||
|
||||
if type( _url ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 )
|
||||
end
|
||||
if type( _post ) ~= "string" then
|
||||
error( "bad argument #2 (expected string, got " .. type( _post ) .. ")", 2 )
|
||||
end
|
||||
if _headers ~= nil and type( _headers ) ~= "table" then
|
||||
error( "bad argument #3 (expected table, got " .. type( _headers ) .. ")", 2 )
|
||||
end
|
||||
if _binary ~= nil and type( _binary ) ~= "boolean" then
|
||||
error( "bad argument #4 (expected boolean, got " .. type( _binary ) .. ")", 2 )
|
||||
end
|
||||
expect(1, _url, "string")
|
||||
expect(2, _post, "string")
|
||||
expect(3, _headers, "table", "nil")
|
||||
expect(4, _binary, "boolean", "nil")
|
||||
return wrapRequest( _url, _url, _post, _headers, _binary )
|
||||
end
|
||||
|
||||
@@ -764,19 +741,10 @@ if http then
|
||||
checkOptions( _url )
|
||||
url = _url.url
|
||||
else
|
||||
if type( _url ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 )
|
||||
end
|
||||
if _post ~= nil and type( _post ) ~= "string" then
|
||||
error( "bad argument #2 (expected string, got " .. type( _post ) .. ")", 2 )
|
||||
end
|
||||
if _headers ~= nil and type( _headers ) ~= "table" then
|
||||
error( "bad argument #3 (expected table, got " .. type( _headers ) .. ")", 2 )
|
||||
end
|
||||
if _binary ~= nil and type( _binary ) ~= "boolean" then
|
||||
error( "bad argument #4 (expected boolean, got " .. type( _binary ) .. ")", 2 )
|
||||
end
|
||||
|
||||
expect(1, _url, "string")
|
||||
expect(2, _post, "string", "nil")
|
||||
expect(3, _headers, "table", "nil")
|
||||
expect(4, _binary, "boolean", "nil")
|
||||
url = _url.url
|
||||
end
|
||||
|
||||
@@ -802,12 +770,9 @@ if http then
|
||||
local nativeWebsocket = http.websocket
|
||||
http.websocketAsync = nativeWebsocket
|
||||
http.websocket = function( _url, _headers )
|
||||
if type( _url ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 )
|
||||
end
|
||||
if _headers ~= nil and type( _headers ) ~= "table" then
|
||||
error( "bad argument #2 (expected table, got " .. type( _headers ) .. ")", 2 )
|
||||
end
|
||||
expect(1, _url, "string")
|
||||
expect(2, _headers, "table", "nil")
|
||||
|
||||
local ok, err = nativeWebsocket( _url, _headers )
|
||||
if not ok then return ok, err end
|
||||
|
||||
@@ -825,18 +790,11 @@ end
|
||||
-- Install the lua part of the FS api
|
||||
local tEmpty = {}
|
||||
function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs )
|
||||
if type( sPath ) ~= "string" then
|
||||
error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 )
|
||||
end
|
||||
if type( sLocation ) ~= "string" then
|
||||
error( "bad argument #2 (expected string, got " .. type( sLocation ) .. ")", 2 )
|
||||
end
|
||||
if bIncludeFiles ~= nil and type( bIncludeFiles ) ~= "boolean" then
|
||||
error( "bad argument #3 (expected boolean, got " .. type( bIncludeFiles ) .. ")", 2 )
|
||||
end
|
||||
if bIncludeDirs ~= nil and type( bIncludeDirs ) ~= "boolean" then
|
||||
error( "bad argument #4 (expected boolean, got " .. type( bIncludeDirs ) .. ")", 2 )
|
||||
end
|
||||
expect(1, sPath, "string")
|
||||
expect(2, sLocation, "string")
|
||||
expect(3, bIncludeFiles, "boolean", "nil")
|
||||
expect(4, bIncludeDirs, "boolean", "nil")
|
||||
|
||||
bIncludeFiles = (bIncludeFiles ~= false)
|
||||
bIncludeDirs = (bIncludeDirs ~= false)
|
||||
local sDir = sLocation
|
||||
@@ -982,6 +940,8 @@ settings.set( "edit.default_extension", "lua" )
|
||||
settings.set( "paint.default_extension", "nfp" )
|
||||
settings.set( "lua.autocomplete", true )
|
||||
settings.set( "list.show_hidden", false )
|
||||
settings.set( "motd.enable", false )
|
||||
settings.set( "motd.path", "/rom/motd.txt:/motd.txt" )
|
||||
if term.isColour() then
|
||||
settings.set( "bios.use_multishell", true )
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
||||
|
||||
-- Colors
|
||||
white = 1
|
||||
orange = 2
|
||||
@@ -18,49 +20,35 @@ black = 32768
|
||||
|
||||
function combine( ... )
|
||||
local r = 0
|
||||
for n,c in ipairs( { ... } ) do
|
||||
if type( c ) ~= "number" then
|
||||
error( "bad argument #"..n.." (expected number, got " .. type( c ) .. ")", 2 )
|
||||
end
|
||||
for i = 1, select('#', ...) do
|
||||
local c = select(i, ...)
|
||||
expect(i, c, "number")
|
||||
r = bit32.bor(r,c)
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function subtract( colors, ... )
|
||||
if type( colors ) ~= "number" then
|
||||
error( "bad argument #1 (expected number, got " .. type( colors ) .. ")", 2 )
|
||||
end
|
||||
expect(1, colors, "number")
|
||||
local r = colors
|
||||
for n,c in ipairs( { ... } ) do
|
||||
if type( c ) ~= "number" then
|
||||
error( "bad argument #"..tostring( n+1 ).." (expected number, got " .. type( c ) .. ")", 2 )
|
||||
end
|
||||
for i = 1, select('#', ...) do
|
||||
local c = select(i, ...)
|
||||
expect(i + 1, c, "number")
|
||||
r = bit32.band(r, bit32.bnot(c))
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function test( colors, color )
|
||||
if type( colors ) ~= "number" then
|
||||
error( "bad argument #1 (expected number, got " .. type( colors ) .. ")", 2 )
|
||||
end
|
||||
if type( color ) ~= "number" then
|
||||
error( "bad argument #2 (expected number, got " .. type( color ) .. ")", 2 )
|
||||
end
|
||||
expect(1, colors, "number")
|
||||
expect(2, color, "number")
|
||||
return bit32.band(colors, color) == color
|
||||
end
|
||||
|
||||
function packRGB( r, g, b )
|
||||
if type( r ) ~= "number" then
|
||||
error( "bad argument #1 (expected number, got " .. type( r ) .. ")", 2 )
|
||||
end
|
||||
if type( g ) ~= "number" then
|
||||
error( "bad argument #2 (expected number, got " .. type( g ) .. ")", 2 )
|
||||
end
|
||||
if type( b ) ~= "number" then
|
||||
error( "bad argument #3 (expected number, got " .. type( b ) .. ")", 2 )
|
||||
end
|
||||
expect(1, r, "number")
|
||||
expect(2, g, "number")
|
||||
expect(3, b, "number")
|
||||
return
|
||||
bit32.band( r * 255, 0xFF ) * 2^16 +
|
||||
bit32.band( g * 255, 0xFF ) * 2^8 +
|
||||
@@ -68,9 +56,7 @@ function packRGB( r, g, b )
|
||||
end
|
||||
|
||||
function unpackRGB( rgb )
|
||||
if type( rgb ) ~= "number" then
|
||||
error( "bad argument #1 (expected number, got " .. type( rgb ) .. ")", 2 )
|
||||
end
|
||||
expect(1, rgb, "number")
|
||||
return
|
||||
bit32.band( bit32.rshift( rgb, 16 ), 0xFF ) / 255,
|
||||
bit32.band( bit32.rshift( rgb, 8 ), 0xFF ) / 255,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user