mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-18 07:27:39 +00:00
Compare commits
18 Commits
v1.21.7-1.
...
feature/1.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d0d4df367f | ||
![]() |
91b3b60ca2 | ||
![]() |
64b1eb5fae | ||
![]() |
ef1923dd3e | ||
![]() |
4cccf1817c | ||
![]() |
b8d9499027 | ||
![]() |
e81a2c72ce | ||
![]() |
01de6110c6 | ||
![]() |
9cf0f85fcb | ||
![]() |
018ce7c8a5 | ||
![]() |
44726827b4 | ||
![]() |
2bf0aba455 | ||
![]() |
3cf914cb4c | ||
![]() |
4868c4aa32 | ||
![]() |
180156ff1c | ||
![]() |
c6ba753568 | ||
![]() |
9f45c91925 | ||
![]() |
5fa724ed24 |
3
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
3
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -11,7 +11,8 @@ body:
|
||||
What version of Minecraft are you using? If your version is not listed, please try to reproduce on one of the supported versions.
|
||||
options:
|
||||
- 1.20.1
|
||||
- 1.21.x
|
||||
- 1.21.1
|
||||
- 1.21.7
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
|
@@ -25,6 +25,7 @@ repositories {
|
||||
name = "Fabric"
|
||||
content {
|
||||
includeGroup("net.fabricmc")
|
||||
includeGroup("net.fabricmc.unpick")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -68,5 +68,5 @@ tasks.ideaSyncTask {
|
||||
tasks.named("checkDependencyConsistency", DependencyCheck::class.java) {
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
// Minecraft depends on asm, but Fabric forces it to a more recent version
|
||||
override(libs.findLibrary("asm").get(), "9.8")
|
||||
override(libs.findLibrary("asm").get(), "9.9")
|
||||
}
|
||||
|
@@ -50,7 +50,6 @@ repositories {
|
||||
includeGroup("com.simibubi.create")
|
||||
includeGroup("net.commoble.morered")
|
||||
includeGroup("dev.architectury")
|
||||
includeGroup("dev.emi")
|
||||
includeGroup("maven.modrinth")
|
||||
includeGroup("me.shedaniel.cloth")
|
||||
includeGroup("me.shedaniel")
|
||||
|
@@ -12,6 +12,7 @@ files:
|
||||
de: de_de # German
|
||||
es-ES: es_es # Spanish
|
||||
fr: fr_fr # French
|
||||
hu: hu_hu # Hungarian
|
||||
it: it_it # Italian
|
||||
ja: ja_jp # Japanese
|
||||
ko: ko_kr # Korean
|
||||
|
@@ -12,7 +12,7 @@ neogradle.subsystems.conventions.runs.enabled=false
|
||||
|
||||
# Mod properties
|
||||
isUnstable=true
|
||||
modVersion=1.116.0
|
||||
modVersion=1.116.1
|
||||
|
||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||
mcVersion=1.21.7
|
||||
mcVersion=1.21.10
|
||||
|
@@ -7,14 +7,14 @@
|
||||
# Minecraft
|
||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
||||
fabric-api = "0.128.0+1.21.7"
|
||||
fabric-loader = "0.16.14"
|
||||
neoForge = "21.7.1-beta"
|
||||
fabric-api = "0.135.0+1.21.10"
|
||||
fabric-loader = "0.17.3"
|
||||
neoForge = "21.10.6-beta"
|
||||
neoMergeTool = "2.0.0"
|
||||
mixin = "0.8.5"
|
||||
parchment = "2025.06.29"
|
||||
parchmentMc = "1.21.6"
|
||||
yarn = "1.21.7+build.1"
|
||||
parchment = "2025.10.12"
|
||||
parchmentMc = "1.21.10"
|
||||
yarn = "1.21.10+build.2"
|
||||
|
||||
# Core dependencies (these versions are tied to the version Minecraft uses)
|
||||
fastutil = "8.5.15"
|
||||
@@ -36,16 +36,15 @@ kotlin-coroutines = "1.10.1"
|
||||
nightConfig = "3.8.1"
|
||||
|
||||
# Minecraft mods
|
||||
emi = "1.1.7+1.21"
|
||||
fabricPermissions = "0.3.3"
|
||||
iris-fabric = "1.8.11+1.21.5-fabric"
|
||||
iris-forge = "1.8.11+1.21.5-neoforge"
|
||||
jei = "19.8.2.99"
|
||||
modmenu = "13.0.2"
|
||||
iris-fabric = "1.9.1+1.21.7-fabric"
|
||||
iris-forge = "1.9.1+1.21.7-neoforge"
|
||||
jei = "26.0.0.1"
|
||||
modmenu = "16.0.0-rc.1"
|
||||
moreRed = "6.0.0.3"
|
||||
rei = "18.0.800"
|
||||
sodium-fabric = "mc1.21.5-0.6.12-fabric"
|
||||
sodium-forge = "mc1.21.5-0.6.12-neoforge"
|
||||
sodium-fabric = "mc1.21.6-0.6.13-fabric"
|
||||
sodium-forge = "mc1.21.6-0.6.13-neoforge"
|
||||
mixinExtra = "0.3.5"
|
||||
create-forge = "6.0.0-6"
|
||||
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
||||
@@ -62,20 +61,20 @@ cctJavadoc = "1.8.5"
|
||||
checkstyle = "10.23.1"
|
||||
errorProne-core = "2.38.0"
|
||||
errorProne-plugin = "4.1.0"
|
||||
fabric-loom = "1.10.4"
|
||||
fabric-loom = "1.11.8"
|
||||
githubRelease = "2.5.2"
|
||||
gradleVersions = "0.50.0"
|
||||
ideaExt = "1.1.7"
|
||||
illuaminate = "0.1.0-83-g1131f68"
|
||||
lwjgl = "3.3.3"
|
||||
minotaur = "2.8.7"
|
||||
modDevGradle = "2.0.95"
|
||||
modDevGradle = "2.0.113"
|
||||
nullAway = "0.12.7"
|
||||
shadow = "8.3.1"
|
||||
spotless = "7.0.2"
|
||||
taskTree = "2.1.1"
|
||||
teavm = "0.11.0-SQUID.1"
|
||||
vanillaExtract = "0.2.1"
|
||||
teavm = "0.13.0-SQUID.1"
|
||||
vanillaExtract = "0.3.0"
|
||||
versionCatalogUpdate = "0.8.1"
|
||||
|
||||
[libraries]
|
||||
@@ -106,16 +105,15 @@ slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
||||
# Minecraft mods
|
||||
create-fabric = { module = "com.simibubi.create:create-fabric-1.20.1", version.ref = "create-fabric" }
|
||||
create-forge = { module = "com.simibubi.create:create-1.21.1", version.ref = "create-forge" }
|
||||
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
|
||||
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
|
||||
fabric-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" }
|
||||
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
|
||||
fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" }
|
||||
iris-fabric = { module = "maven.modrinth:iris", version.ref = "iris-fabric" }
|
||||
iris-forge = { module = "maven.modrinth:iris", version.ref = "iris-forge" }
|
||||
jei-api = { module = "mezz.jei:jei-1.21-common-api", version.ref = "jei" }
|
||||
jei-fabric = { module = "mezz.jei:jei-1.21-fabric", version.ref = "jei" }
|
||||
jei-forge = { module = "mezz.jei:jei-1.21-neoforge", version.ref = "jei" }
|
||||
jei-api = { module = "mezz.jei:jei-1.21.10-common-api", version.ref = "jei" }
|
||||
jei-fabric = { module = "mezz.jei:jei-1.21.10-fabric", version.ref = "jei" }
|
||||
jei-forge = { module = "mezz.jei:jei-1.21.10-neoforge", version.ref = "jei" }
|
||||
mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" }
|
||||
mixinExtra = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinExtra" }
|
||||
modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" }
|
||||
@@ -186,7 +184,7 @@ kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
||||
# Minecraft
|
||||
externalMods-common = ["iris-forge", "jei-api", "nightConfig-core", "nightConfig-toml"]
|
||||
externalMods-forge-compile = ["moreRed", "iris-forge", "jei-api"]
|
||||
externalMods-forge-runtime = []
|
||||
externalMods-forge-runtime = ["jei-forge"]
|
||||
externalMods-fabric-compile = ["fabricPermissions", "iris-fabric", "jei-api", "rei-api", "rei-builtin"]
|
||||
externalMods-fabric-runtime = []
|
||||
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
6
gradlew
vendored
6
gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
CLASSPATH="\\\"\\\""
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -205,7 +205,7 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
set CLASSPATH=
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
275
package-lock.json
generated
275
package-lock.json
generated
@@ -16,7 +16,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
"@rollup/plugin-typescript": "^12.0.0 && <12.1.3",
|
||||
"@rollup/plugin-typescript": "^12.0.0",
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@swc/core": "^1.3.92",
|
||||
"@types/node": "^24.0.0",
|
||||
@@ -481,9 +481,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/plugin-typescript": {
|
||||
"version": "12.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz",
|
||||
"integrity": "sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==",
|
||||
"version": "12.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.4.tgz",
|
||||
"integrity": "sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -554,9 +554,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.43.0.tgz",
|
||||
"integrity": "sha512-Krjy9awJl6rKbruhQDgivNbD1WuLb8xAclM4IR4cN5pHGAs2oIMMQJEiC3IC/9TZJ+QZkmZhlMO/6MBGxPidpw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz",
|
||||
"integrity": "sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -568,9 +568,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.43.0.tgz",
|
||||
"integrity": "sha512-ss4YJwRt5I63454Rpj+mXCXicakdFmKnUNxr1dLK+5rv5FJgAxnN7s31a5VchRYxCFWdmnDWKd0wbAdTr0J5EA==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz",
|
||||
"integrity": "sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -582,9 +582,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.43.0.tgz",
|
||||
"integrity": "sha512-eKoL8ykZ7zz8MjgBenEF2OoTNFAPFz1/lyJ5UmmFSz5jW+7XbH1+MAgCVHy72aG59rbuQLcJeiMrP8qP5d/N0A==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz",
|
||||
"integrity": "sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -596,9 +596,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.43.0.tgz",
|
||||
"integrity": "sha512-SYwXJgaBYW33Wi/q4ubN+ldWC4DzQY62S4Ll2dgfr/dbPoF50dlQwEaEHSKrQdSjC6oIe1WgzosoaNoHCdNuMg==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz",
|
||||
"integrity": "sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -610,9 +610,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.43.0.tgz",
|
||||
"integrity": "sha512-SV+U5sSo0yujrjzBF7/YidieK2iF6E7MdF6EbYxNz94lA+R0wKl3SiixGyG/9Klab6uNBIqsN7j4Y/Fya7wAjQ==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz",
|
||||
"integrity": "sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -624,9 +624,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.43.0.tgz",
|
||||
"integrity": "sha512-J7uCsiV13L/VOeHJBo5SjasKiGxJ0g+nQTrBkAsmQBIdil3KhPnSE9GnRon4ejX1XDdsmK/l30IYLiAaQEO0Cg==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz",
|
||||
"integrity": "sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -638,9 +638,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.43.0.tgz",
|
||||
"integrity": "sha512-gTJ/JnnjCMc15uwB10TTATBEhK9meBIY+gXP4s0sHD1zHOaIh4Dmy1X9wup18IiY9tTNk5gJc4yx9ctj/fjrIw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz",
|
||||
"integrity": "sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -652,9 +652,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.43.0.tgz",
|
||||
"integrity": "sha512-ZJ3gZynL1LDSIvRfz0qXtTNs56n5DI2Mq+WACWZ7yGHFUEirHBRt7fyIk0NsCKhmRhn7WAcjgSkSVVxKlPNFFw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz",
|
||||
"integrity": "sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -666,9 +666,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-8FnkipasmOOSSlfucGYEu58U8cxEdhziKjPD2FIa0ONVMxvl/hmONtX/7y4vGjdUhjcTHlKlDhw3H9t98fPvyA==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -680,9 +680,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.43.0.tgz",
|
||||
"integrity": "sha512-KPPyAdlcIZ6S9C3S2cndXDkV0Bb1OSMsX0Eelr2Bay4EsF9yi9u9uzc9RniK3mcUGCLhWY9oLr6er80P5DE6XA==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz",
|
||||
"integrity": "sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -694,9 +694,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-HPGDIH0/ZzAZjvtlXj6g+KDQ9ZMHfSP553za7o2Odegb/BEfwJcR0Sw0RLNpQ9nC6Gy8s+3mSS9xjZ0n3rhcYg==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -708,9 +708,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-gEmwbOws4U4GLAJDhhtSPWPXUzDfMRedT3hFMyRAvM9Mrnj+dJIFIeL7otsv2WF3D7GrV0GIewW0y28dOYWkmw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -722,9 +722,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-XXKvo2e+wFtXZF/9xoWohHg+MuRnvO29TI5Hqe9xwN5uN8NKUYy7tXUG3EZAlfchufNCTHNGjEx7uN78KsBo0g==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -736,9 +736,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.43.0.tgz",
|
||||
"integrity": "sha512-ruf3hPWhjw6uDFsOAzmbNIvlXFXlBQ4nk57Sec8E8rUxs/AI4HD6xmiiasOOx/3QxS2f5eQMKTAwk7KHwpzr/Q==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz",
|
||||
"integrity": "sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -750,9 +750,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-QmNIAqDiEMEvFV15rsSnjoSmO0+eJLoKRD9EAa9rrYNwO/XRCtOGM3A5A0X+wmG+XRrw9Fxdsw+LnyYiZWWcVw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -764,9 +764,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.43.0.tgz",
|
||||
"integrity": "sha512-jAHr/S0iiBtFyzjhOkAics/2SrXE092qyqEg96e90L3t9Op8OTzS6+IX0Fy5wCt2+KqeHAkti+eitV0wvblEoQ==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz",
|
||||
"integrity": "sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -778,9 +778,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.43.0.tgz",
|
||||
"integrity": "sha512-3yATWgdeXyuHtBhrLt98w+5fKurdqvs8B53LaoKD7P7H7FKOONLsBVMNl9ghPQZQuYcceV5CDyPfyfGpMWD9mQ==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz",
|
||||
"integrity": "sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -792,9 +792,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.43.0.tgz",
|
||||
"integrity": "sha512-wVzXp2qDSCOpcBCT5WRWLmpJRIzv23valvcTwMHEobkjippNf+C3ys/+wf07poPkeNix0paTNemB2XrHr2TnGw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz",
|
||||
"integrity": "sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -806,9 +806,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.43.0.tgz",
|
||||
"integrity": "sha512-fYCTEyzf8d+7diCw8b+asvWDCLMjsCEA8alvtAutqJOJp/wL5hs1rWSqJ1vkjgW0L2NB4bsYJrpKkiIPRR9dvw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz",
|
||||
"integrity": "sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -820,9 +820,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.43.0.tgz",
|
||||
"integrity": "sha512-SnGhLiE5rlK0ofq8kzuDkM0g7FN1s5VYY+YSMTibP7CqShxCQvqtNxTARS4xX4PFJfHjG0ZQYX9iGzI3FQh5Aw==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz",
|
||||
"integrity": "sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -844,9 +844,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.12.1.tgz",
|
||||
"integrity": "sha512-aKXdDTqxTVFl/bKQZ3EQUjEMBEoF6JBv29moMZq0kbVO43na6u/u+3Vcbhbrh+A2N0X5OL4RaveuWfAjEgOmeA==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.12.9.tgz",
|
||||
"integrity": "sha512-O+LfT2JlVMsIMWG9x+rdxg8GzpzeGtCZQfXV7cKc1PjIKUkLFf1QJ7okuseA4f/9vncu37dQ2ZcRrPKy0Ndd5g==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
@@ -862,16 +862,16 @@
|
||||
"url": "https://opencollective.com/swc"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@swc/core-darwin-arm64": "1.12.1",
|
||||
"@swc/core-darwin-x64": "1.12.1",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.12.1",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.1",
|
||||
"@swc/core-linux-arm64-musl": "1.12.1",
|
||||
"@swc/core-linux-x64-gnu": "1.12.1",
|
||||
"@swc/core-linux-x64-musl": "1.12.1",
|
||||
"@swc/core-win32-arm64-msvc": "1.12.1",
|
||||
"@swc/core-win32-ia32-msvc": "1.12.1",
|
||||
"@swc/core-win32-x64-msvc": "1.12.1"
|
||||
"@swc/core-darwin-arm64": "1.12.9",
|
||||
"@swc/core-darwin-x64": "1.12.9",
|
||||
"@swc/core-linux-arm-gnueabihf": "1.12.9",
|
||||
"@swc/core-linux-arm64-gnu": "1.12.9",
|
||||
"@swc/core-linux-arm64-musl": "1.12.9",
|
||||
"@swc/core-linux-x64-gnu": "1.12.9",
|
||||
"@swc/core-linux-x64-musl": "1.12.9",
|
||||
"@swc/core-win32-arm64-msvc": "1.12.9",
|
||||
"@swc/core-win32-ia32-msvc": "1.12.9",
|
||||
"@swc/core-win32-x64-msvc": "1.12.9"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/helpers": ">=0.5.17"
|
||||
@@ -883,9 +883,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-arm64": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.1.tgz",
|
||||
"integrity": "sha512-nUjWVcJ3YS2N40ZbKwYO2RJ4+o2tWYRzNOcIQp05FqW0+aoUCVMdAUUzQinPDynfgwVshDAXCKemY8X7nN5MaA==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.12.9.tgz",
|
||||
"integrity": "sha512-GACFEp4nD6V+TZNR2JwbMZRHB+Yyvp14FrcmB6UCUYmhuNWjkxi+CLnEvdbuiKyQYv0zA+TRpCHZ+whEs6gwfA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -900,9 +900,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-darwin-x64": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.12.1.tgz",
|
||||
"integrity": "sha512-OGm4a4d3OeJn+tRt8H/eiHgTFrJbS6r8mi/Ob65tAEXZGHN900T2kR7c5ALr0V2hBOQ8BfhexwPoQlGQP/B95w==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.12.9.tgz",
|
||||
"integrity": "sha512-hv2kls7Ilkm2EpeJz+I9MCil7pGS3z55ZAgZfxklEuYsxpICycxeH+RNRv4EraggN44ms+FWCjtZFu0LGg2V3g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -917,9 +917,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm-gnueabihf": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.12.1.tgz",
|
||||
"integrity": "sha512-76YeeQKyK0EtNkQiNBZ0nbVGooPf9IucY0WqVXVpaU4wuG7ZyLEE2ZAIgXafIuzODGQoLfetue7I8boMxh1/MA==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.12.9.tgz",
|
||||
"integrity": "sha512-od9tDPiG+wMU9wKtd6y3nYJdNqgDOyLdgRRcrj1/hrbHoUPOM8wZQZdwQYGarw63iLXGgsw7t5HAF9Yc51ilFA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -934,9 +934,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-gnu": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.1.tgz",
|
||||
"integrity": "sha512-BxJDIJPq1+aCh9UsaSAN6wo3tuln8UhNXruOrzTI8/ElIig/3sAueDM6Eq7GvZSGGSA7ljhNATMJ0elD7lFatQ==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.12.9.tgz",
|
||||
"integrity": "sha512-6qx1ka9LHcLzxIgn2Mros+CZLkHK2TawlXzi/h7DJeNnzi8F1Hw0Yzjp8WimxNCg6s2n+o3jnmin1oXB7gg8rw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -951,9 +951,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-arm64-musl": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.12.1.tgz",
|
||||
"integrity": "sha512-NhLdbffSXvY0/FwUSAl4hKBlpe5GHQGXK8DxTo3HHjLsD9sCPYieo3vG0NQoUYAy4ZUY1WeGjyxeq4qZddJzEQ==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.12.9.tgz",
|
||||
"integrity": "sha512-yghFZWKPVVGbUdqiD7ft23G0JX6YFGDJPz9YbLLAwGuKZ9th3/jlWoQDAw1Naci31LQhVC+oIji6ozihSuwB2A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -968,9 +968,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-gnu": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.1.tgz",
|
||||
"integrity": "sha512-CrYnV8SZIgArQ9LKH0xEF95PKXzX9WkRSc5j55arOSBeDCeDUQk1Bg/iKdnDiuj5HC1hZpvzwMzSBJjv+Z70jA==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.9.tgz",
|
||||
"integrity": "sha512-SFUxyhWLZRNL8QmgGNqdi2Q43PNyFVkRZ2zIif30SOGFSxnxcf2JNeSeBgKIGVgaLSuk6xFVVCtJ3KIeaStgRg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -985,9 +985,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-linux-x64-musl": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.12.1.tgz",
|
||||
"integrity": "sha512-BQMl3d0HaGB0/h2xcKlGtjk/cGRn2tnbsaChAKcjFdCepblKBCz1pgO/mL7w5iXq3s57wMDUn++71/a5RAkZOA==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.12.9.tgz",
|
||||
"integrity": "sha512-9FB0wM+6idCGTI20YsBNBg9xSWtkDBymnpaTCsZM3qDc0l4uOpJMqbfWhQvp17x7r/ulZfb2QY8RDvQmCL6AcQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1002,9 +1002,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-arm64-msvc": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.12.1.tgz",
|
||||
"integrity": "sha512-b7NeGnpqTfmIGtUqXBl0KqoSmOnH64nRZoT5l4BAGdvwY7nxitWR94CqZuwyLPty/bLywmyDA9uO12Kvgb3+gg==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.12.9.tgz",
|
||||
"integrity": "sha512-zHOusMVbOH9ik5RtRrMiGzLpKwxrPXgXkBm3SbUCa65HAdjV33NZ0/R9Rv1uPESALtEl2tzMYLUxYA5ECFDFhA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1019,9 +1019,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-ia32-msvc": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.12.1.tgz",
|
||||
"integrity": "sha512-iU/29X2D7cHBp1to62cUg/5Xk8K+lyOJiKIGGW5rdzTW/c2zz3d/ehgpzVP/rqC4NVr88MXspqHU4il5gmDajw==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.12.9.tgz",
|
||||
"integrity": "sha512-aWZf0PqE0ot7tCuhAjRkDFf41AzzSQO0x2xRfTbnhpROp57BRJ/N5eee1VULO/UA2PIJRG7GKQky5bSGBYlFug==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1036,9 +1036,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/core-win32-x64-msvc": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.12.1.tgz",
|
||||
"integrity": "sha512-+Zh+JKDwiFqV5N9yAd2DhYVGPORGh9cfenu1ptr9yge+eHAf7vZJcC3rnj6QMR1QJh0Y5VC9+YBjRFjZVA7XDw==",
|
||||
"version": "1.12.9",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.12.9.tgz",
|
||||
"integrity": "sha512-C25fYftXOras3P3anSUeXXIpxmEkdAcsIL9yrr0j1xepTZ/yKwpnQ6g3coj8UXdeJy4GTVlR6+Ow/QiBgZQNOg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1124,9 +1124,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.3.tgz",
|
||||
"integrity": "sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==",
|
||||
"version": "24.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.8.tgz",
|
||||
"integrity": "sha512-WytNrFSgWO/esSH9NbpWUfTMGQwCGIKfCmNlmFDNiI5gGhgMmEA+V1AEvKLeBNvvtBnailJtkrEa2OIISwrVAA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2856,13 +2856,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.43.0.tgz",
|
||||
"integrity": "sha512-wdN2Kd3Twh8MAEOEJZsuxuLKCsBEo4PVNLK6tQWAn10VhsVewQLzcucMgLolRlhFybGxfclbPeEYBaP6RvUFGg==",
|
||||
"version": "4.44.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.1.tgz",
|
||||
"integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.7"
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
@@ -2872,36 +2872,29 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.43.0",
|
||||
"@rollup/rollup-android-arm64": "4.43.0",
|
||||
"@rollup/rollup-darwin-arm64": "4.43.0",
|
||||
"@rollup/rollup-darwin-x64": "4.43.0",
|
||||
"@rollup/rollup-freebsd-arm64": "4.43.0",
|
||||
"@rollup/rollup-freebsd-x64": "4.43.0",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.43.0",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.43.0",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.43.0",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.43.0",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.43.0",
|
||||
"@rollup/rollup-linux-x64-musl": "4.43.0",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.43.0",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.43.0",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.43.0",
|
||||
"@rollup/rollup-android-arm-eabi": "4.44.1",
|
||||
"@rollup/rollup-android-arm64": "4.44.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.44.1",
|
||||
"@rollup/rollup-darwin-x64": "4.44.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.44.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.44.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.44.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.44.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.44.1",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-powerpc64le-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.44.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.44.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.44.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.44.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.44.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.44.1",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup/node_modules/@types/estree": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz",
|
||||
"integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
|
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
"@rollup/plugin-typescript": "^12.0.0 && <12.1.3",
|
||||
"@rollup/plugin-typescript": "^12.0.0",
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@swc/core": "^1.3.92",
|
||||
"@types/node": "^24.0.0",
|
||||
|
@@ -6,12 +6,15 @@ package dan200.computercraft.api.client;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModel;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
@@ -19,10 +22,11 @@ import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.model.BlockModelRotation;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ModelBakery;
|
||||
import net.minecraft.client.resources.model.ResolvedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ARGB;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ItemOwner;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.joml.Vector3f;
|
||||
@@ -113,7 +117,7 @@ public final class StandaloneModel {
|
||||
* Set up an {@link ItemStackRenderState.LayerRenderState} to render this model.
|
||||
*
|
||||
* @param layer The layer to set up.
|
||||
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
||||
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, ItemOwner, int)
|
||||
*/
|
||||
public void setupItemLayer(ItemStackRenderState.LayerRenderState layer) {
|
||||
layer.setExtents(extents);
|
||||
@@ -127,26 +131,37 @@ public final class StandaloneModel {
|
||||
* Render the model directly.
|
||||
*
|
||||
* @param transform The current pose stack transformations.
|
||||
* @param buffers The buffer source to use for rendering.
|
||||
* @param collector The node collector to render to.
|
||||
* @param light The current light texture coordinate.
|
||||
* @param overlay The current overlay texture coordinate.
|
||||
*/
|
||||
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||
render(transform, buffers, light, overlay, null);
|
||||
public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay) {
|
||||
submit(transform, collector, light, overlay, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the model directly.
|
||||
*
|
||||
* @param transform The current pose stack transformations.
|
||||
* @param buffers The buffer source to use for rendering.
|
||||
* @param light The current light texture coordinate.
|
||||
* @param overlay The current overlay texture coordinate.
|
||||
* @param tints The tints for this model.
|
||||
* @param transform The current pose stack transformations.
|
||||
* @param collector The node collector to render to.
|
||||
* @param light The current light texture coordinate.
|
||||
* @param overlay The current overlay texture coordinate.
|
||||
* @param tints The tints for this model.
|
||||
* @param crumblingOverlay The current breaking progress.
|
||||
*/
|
||||
public void render(PoseStack transform, MultiBufferSource buffers, int light, int overlay, int @Nullable [] tints) {
|
||||
var pose = transform.last();
|
||||
var buffer = buffers.getBuffer(renderType);
|
||||
public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay, int @Nullable [] tints, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
|
||||
collector.submitCustomGeometry(transform, renderType, (pose, buffer) -> render(pose, buffer, tints, light, overlay));
|
||||
|
||||
if (crumblingOverlay != null && renderType.affectsCrumbling()) {
|
||||
// FIXME: We need a custom hook here, which renders to crumblingBufferSource. Currently the DESTROY_TYPES
|
||||
// buffer gets flushed before the main model gets rendered.
|
||||
collector.submitCustomGeometry(transform, ModelBakery.DESTROY_TYPES.get(crumblingOverlay.progress()), (pose, buffer) ->
|
||||
render(pose, new SheetedDecalTextureGenerator(buffer, crumblingOverlay.cameraPose(), 1.0f), null, light, overlay)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void render(PoseStack.Pose pose, VertexConsumer buffer, int @Nullable [] tints, int light, int overlay) {
|
||||
for (var quad : quads) {
|
||||
float r, g, b, a;
|
||||
var idx = quad.tintIndex();
|
||||
|
@@ -4,16 +4,13 @@
|
||||
|
||||
package dan200.computercraft.api.client.turtle;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.StandaloneModel;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||
import net.minecraft.client.renderer.item.BlockModelWrapper;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
@@ -70,11 +67,6 @@ public final class BasicUpgradeModel implements TurtleUpgradeModel {
|
||||
getModel(side).setupItemLayer(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||
getModel(side).render(transform, buffers, light, overlay);
|
||||
}
|
||||
|
||||
private record Unbaked(ResourceLocation left, ResourceLocation right) implements TurtleUpgradeModel.Unbaked {
|
||||
@Override
|
||||
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
||||
|
@@ -9,12 +9,10 @@ import com.mojang.math.Axis;
|
||||
import com.mojang.math.Transformation;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
@@ -23,7 +21,6 @@ import net.minecraft.client.renderer.special.SpecialModelRenderer;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.joml.Matrix4f;
|
||||
@@ -77,15 +74,6 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||
transform.mulPose(getRenderer(side).transform().getMatrix());
|
||||
transform.mulPose(Axis.YP.rotation(Mth.PI));
|
||||
Minecraft.getInstance().getItemRenderer().renderStatic(
|
||||
upgrade.getUpgradeItem(), ItemDisplayContext.FIXED, light, overlay, transform, buffers, turtle.getLevel(), 0
|
||||
);
|
||||
}
|
||||
|
||||
private static final class Unbaked implements TurtleUpgradeModel.Unbaked {
|
||||
@Override
|
||||
public MapCodec<? extends TurtleUpgradeModel.Unbaked> type() {
|
||||
@@ -120,14 +108,14 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
|
||||
|
||||
private record TransformedRenderer(Transformation transform) implements SpecialModelRenderer<ItemStackRenderState> {
|
||||
@Override
|
||||
public void render(
|
||||
@Nullable ItemStackRenderState state, ItemDisplayContext itemDisplayContext, PoseStack poseStack,
|
||||
MultiBufferSource multiBufferSource, int overlay, int light, boolean bl
|
||||
public void submit(
|
||||
@Nullable ItemStackRenderState state, ItemDisplayContext context, PoseStack poseStack, SubmitNodeCollector sink,
|
||||
int light, int overlay, boolean foil, int outlineColour
|
||||
) {
|
||||
if (state == null) return;
|
||||
poseStack.pushPose();
|
||||
poseStack.mulPose(transform.getMatrix());
|
||||
state.render(poseStack, multiBufferSource, overlay, light);
|
||||
state.submit(poseStack, sink, light, overlay, outlineColour);
|
||||
poseStack.popPose();
|
||||
}
|
||||
|
||||
|
@@ -6,20 +6,17 @@ package dan200.computercraft.api.client.turtle;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.DataResult;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
@@ -71,11 +68,6 @@ public final class SelectUpgradeModel<T> implements TurtleUpgradeModel {
|
||||
getModel(upgrade).renderForItem(upgrade, side, renderer, resolver, transform, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay) {
|
||||
getModel(upgrade).renderForLevel(upgrade, side, turtle, transform, buffers, light, overlay);
|
||||
}
|
||||
|
||||
private record Unbaked<T>(
|
||||
Cases<T> cases,
|
||||
Optional<TurtleUpgradeModel.Unbaked> fallback
|
||||
|
@@ -4,24 +4,21 @@
|
||||
|
||||
package dan200.computercraft.api.client.turtle;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
import dan200.computercraft.impl.client.ComputerCraftAPIClientService;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ResolvableModel;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ItemOwner;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
@@ -67,24 +64,10 @@ public interface TurtleUpgradeModel {
|
||||
* @param resolver The model resolver.
|
||||
* @param transform The root model's transformation.
|
||||
* @param seed The current model seed.
|
||||
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, LivingEntity, int)
|
||||
* @see ItemModel#update(ItemStackRenderState, ItemStack, ItemModelResolver, ItemDisplayContext, ClientLevel, ItemOwner, int)
|
||||
*/
|
||||
void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed);
|
||||
|
||||
/**
|
||||
* Render this upgrade to a {@link MultiBufferSource}. This is used for rendering the block-entity form of the
|
||||
* upgrade.
|
||||
*
|
||||
* @param upgrade The upgrade being rendered.
|
||||
* @param side Which side of the turtle (left or right) the upgrade is equipped on.
|
||||
* @param turtle Access to the turtle that the upgrade resides on.
|
||||
* @param transform The current pose stack.
|
||||
* @param buffers The buffers to render to.
|
||||
* @param light The lightmap coordinate.
|
||||
* @param overlay The overlay coordinate.
|
||||
*/
|
||||
void renderForLevel(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ITurtleAccess turtle, PoseStack transform, MultiBufferSource buffers, int light, int overlay);
|
||||
|
||||
/**
|
||||
* An unbaked turtle model. Much like other unbaked models (e.g. {@link ItemModel.Unbaked}), this should resolve
|
||||
* any dependencies and returned the fully-resolved model.
|
||||
|
@@ -11,13 +11,6 @@ plugins {
|
||||
id("cc-tweaked.publishing")
|
||||
}
|
||||
|
||||
sourceSets.client {
|
||||
java {
|
||||
exclude("dan200/computercraft/client/integration/emi")
|
||||
exclude("dan200/computercraft/client/integration/jei")
|
||||
}
|
||||
}
|
||||
|
||||
minecraft {
|
||||
accessWideners(
|
||||
"src/main/resources/computercraft.accesswidener",
|
||||
@@ -46,7 +39,6 @@ dependencies {
|
||||
compileOnly(libs.mixin)
|
||||
compileOnly(libs.mixinExtra)
|
||||
compileOnly(libs.bundles.externalMods.common)
|
||||
clientCompileOnly(variantOf(libs.emi) { classifier("api") })
|
||||
|
||||
annotationProcessorEverywhere(libs.autoService)
|
||||
testFixturesAnnotationProcessor(libs.autoService)
|
||||
|
@@ -7,7 +7,6 @@ package dan200.computercraft.client;
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
import dan200.computercraft.client.render.CableHighlightRenderer;
|
||||
import dan200.computercraft.client.render.ExtendedItemFrameRenderState;
|
||||
@@ -22,14 +21,13 @@ import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
@@ -40,8 +38,6 @@ import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Event listeners for client-only code.
|
||||
* <p>
|
||||
@@ -71,30 +67,31 @@ public final class ClientHooks {
|
||||
}
|
||||
|
||||
public static boolean drawHighlight(PoseStack transform, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) {
|
||||
// TODO: Reconsider this API once https://github.com/FabricMC/fabric/pull/4906/ is merged.
|
||||
return CableHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit)
|
||||
|| MonitorHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit);
|
||||
}
|
||||
|
||||
public static boolean onRenderHeldItem(
|
||||
PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand,
|
||||
PoseStack transform, SubmitNodeCollector collector, int lightTexture, InteractionHand hand,
|
||||
float pitch, float equipProgress, float swingProgress, ItemStack stack
|
||||
) {
|
||||
if (stack.getItem() instanceof PocketComputerItem) {
|
||||
PocketItemRenderer.INSTANCE.renderItemFirstPerson(transform, render, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||
PocketItemRenderer.INSTANCE.renderItemFirstPerson(transform, collector, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||
return true;
|
||||
}
|
||||
if (stack.getItem() instanceof PrintoutItem) {
|
||||
PrintoutItemRenderer.INSTANCE.renderItemFirstPerson(transform, render, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||
PrintoutItemRenderer.INSTANCE.renderItemFirstPerson(transform, collector, lightTexture, hand, pitch, equipProgress, swingProgress, stack);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean onRenderItemFrame(PoseStack transform, MultiBufferSource render, ItemFrameRenderState frame, ExtendedItemFrameRenderState state, int light) {
|
||||
public static boolean onRenderItemFrame(PoseStack transform, SubmitNodeCollector render, ItemFrameRenderState frame, ExtendedItemFrameRenderState state) {
|
||||
if (state.printoutData != null) {
|
||||
transform.mulPose(Axis.ZP.rotationDegrees(frame.rotation * 360.0f / 8.0f));
|
||||
PrintoutItemRenderer.onRenderInFrame(transform, render, frame, state.printoutData, state.isBook, light);
|
||||
PrintoutItemRenderer.onRenderInFrame(transform, render, frame, state.printoutData, state.isBook);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -105,37 +102,6 @@ public final class ClientHooks {
|
||||
SpeakerManager.onPlayStreaming(engine, channel, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional information about the currently targeted block to the debug screen.
|
||||
*
|
||||
* @param addText A callback which adds a single line of text.
|
||||
*/
|
||||
public static void addBlockDebugInfo(Consumer<String> addText) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
if (!minecraft.getDebugOverlay().showDebugScreen() || minecraft.level == null) return;
|
||||
if (minecraft.hitResult == null || minecraft.hitResult.getType() != HitResult.Type.BLOCK) return;
|
||||
|
||||
var tile = minecraft.level.getBlockEntity(((BlockHitResult) minecraft.hitResult).getBlockPos());
|
||||
|
||||
if (tile instanceof MonitorBlockEntity monitor) {
|
||||
addText.accept("");
|
||||
addText.accept(
|
||||
String.format("Targeted monitor: (%d, %d), %d x %d", monitor.getXIndex(), monitor.getYIndex(), monitor.getWidth(), monitor.getHeight())
|
||||
);
|
||||
} else if (tile instanceof TurtleBlockEntity turtle) {
|
||||
addText.accept("");
|
||||
addText.accept("Targeted turtle:");
|
||||
addText.accept(String.format("Id: %d", turtle.getComputerID()));
|
||||
addTurtleUpgrade(addText, turtle, TurtleSide.LEFT);
|
||||
addTurtleUpgrade(addText, turtle, TurtleSide.RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addTurtleUpgrade(Consumer<String> out, TurtleBlockEntity turtle, TurtleSide side) {
|
||||
var upgrade = turtle.getAccess().getUpgradeWithData(side);
|
||||
if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location()));
|
||||
}
|
||||
|
||||
public static BlockState getBlockBreakingState(BlockState state, BlockPos pos) {
|
||||
// Only apply to cables which have both a cable and modem
|
||||
if (state.getBlock() != ModRegistry.Blocks.CABLE.get()
|
||||
|
@@ -12,6 +12,9 @@ import dan200.computercraft.client.item.colour.PocketComputerLight;
|
||||
import dan200.computercraft.client.item.model.TurtleOverlayModel;
|
||||
import dan200.computercraft.client.item.properties.PocketComputerStateProperty;
|
||||
import dan200.computercraft.client.item.properties.TurtleShowElfOverlay;
|
||||
import dan200.computercraft.client.model.LecternBookModel;
|
||||
import dan200.computercraft.client.model.LecternPocketModel;
|
||||
import dan200.computercraft.client.model.LecternPrintoutModel;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.platform.ModelKey;
|
||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||
@@ -23,11 +26,14 @@ import dan200.computercraft.client.turtle.TurtleUpgradeModelManager;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import net.minecraft.client.color.item.ItemTintSource;
|
||||
import net.minecraft.client.gui.components.debug.DebugScreenEntry;
|
||||
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
|
||||
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
@@ -51,6 +57,7 @@ import java.util.concurrent.Executor;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Registers client-side objects, such as {@link BlockEntityRendererProvider}s and
|
||||
@@ -193,6 +200,12 @@ public final class ClientRegistry {
|
||||
register.accept(TurtleShowElfOverlay.ID, TurtleShowElfOverlay.CODEC);
|
||||
}
|
||||
|
||||
public static void registerLayerDefinitions(BiConsumer<ModelLayerLocation, Supplier<LayerDefinition>> register) {
|
||||
register.accept(LecternBookModel.LAYER, LecternBookModel::createLayer);
|
||||
register.accept(LecternPrintoutModel.LAYER, LecternPrintoutModel::createLayer);
|
||||
register.accept(LecternPocketModel.LAYER, LecternPocketModel::createLayer);
|
||||
}
|
||||
|
||||
public interface RegisterPictureInPictureRenderer {
|
||||
<T extends PictureInPictureRenderState> void register(Class<T> state, Function<MultiBufferSource.BufferSource, PictureInPictureRenderer<T>> factory);
|
||||
}
|
||||
@@ -200,4 +213,8 @@ public final class ClientRegistry {
|
||||
public static void registerPictureInPictureRenderers(RegisterPictureInPictureRenderer register) {
|
||||
register.register(PrintoutScreen.PrintoutRenderState.class, PrintoutScreen.PrintoutPictureRenderer::new);
|
||||
}
|
||||
|
||||
public static void registerDebugScreenEntries(BiConsumer<ResourceLocation, DebugScreenEntry> register) {
|
||||
register.accept(LookingAtBlockEntityDebugEntry.ID, LookingAtBlockEntityDebugEntry.create());
|
||||
}
|
||||
}
|
||||
|
@@ -23,6 +23,8 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.client.input.KeyEvent;
|
||||
import net.minecraft.client.input.MouseButtonEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
@@ -105,24 +107,33 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
||||
public boolean keyPressed(KeyEvent event) {
|
||||
// Forward the tab key to the terminal, rather than moving between controls.
|
||||
if (key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
||||
return getFocused().keyPressed(key, scancode, modifiers);
|
||||
if (event.key() == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
||||
return getFocused().keyPressed(event);
|
||||
}
|
||||
|
||||
return super.keyPressed(key, scancode, modifiers);
|
||||
return super.keyPressed(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(double x, double y, int button) {
|
||||
public boolean mouseReleased(MouseButtonEvent event) {
|
||||
// Reimplement ContainerEventHandler.mouseReleased, as it's not called in vanilla (it is in Forge, but that
|
||||
// shouldn't matter).
|
||||
setDragging(false);
|
||||
var child = getChildAt(x, y);
|
||||
if (child.isPresent() && child.get().mouseReleased(x, y, button)) return true;
|
||||
var child = getChildAt(event.x(), event.y());
|
||||
if (child.isPresent() && child.get().mouseReleased(event)) return true;
|
||||
|
||||
return super.mouseReleased(x, y, button);
|
||||
return super.mouseReleased(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
||||
// Reimplement ContainerEventHandler.mouseScrolled, as AbstractContainerScreen overrides it.
|
||||
var child = getChildAt(mouseX, mouseY);
|
||||
if (child.isPresent() && child.get().mouseScrolled(mouseX, mouseY, scrollX, scrollY)) return true;
|
||||
|
||||
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,8 +143,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double x, double y, int button) {
|
||||
var changed = super.mouseClicked(x, y, button);
|
||||
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
|
||||
var changed = super.mouseClicked(event, doubleClick);
|
||||
// Clicking the terminate/shutdown button steals focus, which means then pressing "enter" will click the button
|
||||
// again. Restore the focus to the terminal in these cases.
|
||||
if (getFocused() instanceof DynamicImageButton) setFocused(terminal);
|
||||
@@ -141,9 +152,9 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(double x, double y, int button, double deltaX, double deltaY) {
|
||||
return (getFocused() != null && getFocused().mouseDragged(x, y, button, deltaX, deltaY))
|
||||
|| super.mouseDragged(x, y, button, deltaX, deltaY);
|
||||
public boolean mouseDragged(MouseButtonEvent event, double deltaX, double deltaY) {
|
||||
return (getFocused() != null && getFocused().mouseDragged(event, deltaX, deltaY))
|
||||
|| super.mouseDragged(event, deltaX, deltaY);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,96 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.components.debug.DebugEntryLookingAtBlock;
|
||||
import net.minecraft.client.gui.components.debug.DebugScreenDisplayer;
|
||||
import net.minecraft.client.gui.components.debug.DebugScreenEntry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* A {@link DebugScreenEntry} that provides information about the currently looked at block entity.
|
||||
*
|
||||
* @see DebugEntryLookingAtBlock
|
||||
*/
|
||||
public final class LookingAtBlockEntityDebugEntry implements DebugScreenEntry {
|
||||
public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "looking_at_block_entity");
|
||||
|
||||
private final Map<BlockEntityType<?>, BiConsumer<List<String>, BlockEntity>> blockEntityEmitters = new HashMap<>();
|
||||
|
||||
private LookingAtBlockEntityDebugEntry() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk) {
|
||||
var entity = Minecraft.getInstance().getCameraEntity();
|
||||
var trueLevel = SharedConstants.DEBUG_SHOW_SERVER_DEBUG_VALUES ? level : Minecraft.getInstance().level;
|
||||
if (entity == null || trueLevel == null) return;
|
||||
|
||||
var hitResult = entity.pick(20.0, 0.0F, false);
|
||||
if (hitResult.getType() != HitResult.Type.BLOCK) return;
|
||||
|
||||
var blockEntity = trueLevel.getBlockEntity(((BlockHitResult) hitResult).getBlockPos());
|
||||
if (blockEntity == null) return;
|
||||
var emitter = blockEntityEmitters.get(blockEntity.getType());
|
||||
if (emitter == null) return;
|
||||
|
||||
List<String> lines = new ArrayList<>();
|
||||
emitter.accept(lines, blockEntity);
|
||||
displayer.addToGroup(ID, lines);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends BlockEntity> LookingAtBlockEntityDebugEntry register(BlockEntityType<T> type, BiConsumer<List<String>, T> emit) {
|
||||
blockEntityEmitters.put(type, (BiConsumer<List<String>, BlockEntity>) emit);
|
||||
return this;
|
||||
}
|
||||
|
||||
public static DebugScreenEntry create() {
|
||||
return new LookingAtBlockEntityDebugEntry()
|
||||
.register(ModRegistry.BlockEntities.MONITOR_NORMAL.get(), LookingAtBlockEntityDebugEntry::debugMonitor)
|
||||
.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), LookingAtBlockEntityDebugEntry::debugMonitor)
|
||||
.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), LookingAtBlockEntityDebugEntry::debugTurtle)
|
||||
.register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), LookingAtBlockEntityDebugEntry::debugTurtle);
|
||||
}
|
||||
|
||||
private static void debugMonitor(List<String> lines, MonitorBlockEntity monitor) {
|
||||
lines.add(
|
||||
String.format("Targeted monitor: (%d, %d), %d x %d", monitor.getXIndex(), monitor.getYIndex(), monitor.getWidth(), monitor.getHeight())
|
||||
);
|
||||
}
|
||||
|
||||
private static void debugTurtle(List<String> lines, TurtleBlockEntity turtle) {
|
||||
lines.add("Targeted turtle:");
|
||||
lines.add(String.format("Id: %d", turtle.getComputerID()));
|
||||
addTurtleUpgrade(lines, turtle, TurtleSide.LEFT);
|
||||
addTurtleUpgrade(lines, turtle, TurtleSide.RIGHT);
|
||||
}
|
||||
|
||||
private static void addTurtleUpgrade(List<String> out, TurtleBlockEntity turtle, TurtleSide side) {
|
||||
var upgrade = turtle.getAccess().getUpgradeWithData(side);
|
||||
if (upgrade != null) out.add(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location()));
|
||||
}
|
||||
|
||||
}
|
@@ -14,6 +14,7 @@ import net.minecraft.client.ScrollWheelHandler;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
||||
import net.minecraft.client.input.KeyEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -91,13 +92,13 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean keyPressed(int key, int scancode, int modifiers) {
|
||||
public final boolean keyPressed(KeyEvent event) {
|
||||
// Forward the tab key to the terminal, rather than moving between controls.
|
||||
if (key == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
||||
return getFocused().keyPressed(key, scancode, modifiers);
|
||||
if (event.key() == GLFW.GLFW_KEY_TAB && getFocused() != null && getFocused() == terminal) {
|
||||
return getFocused().keyPressed(event);
|
||||
}
|
||||
|
||||
return super.keyPressed(key, scancode, modifiers);
|
||||
return super.keyPressed(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -96,7 +96,7 @@ public final class OptionScreen extends Screen {
|
||||
);
|
||||
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING, 256, 256);
|
||||
|
||||
assertNonNull(messageRenderer).renderLeftAlignedNoShadow(graphics, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040);
|
||||
assertNonNull(messageRenderer).render(graphics, MultiLineLabel.Align.LEFT, +PADDING, y + PADDING, FONT_HEIGHT, false, 0x404040);
|
||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@ import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
|
||||
import net.minecraft.client.gui.render.state.GuiElementRenderState;
|
||||
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.client.input.KeyEvent;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -87,18 +88,18 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
||||
if (key == GLFW.GLFW_KEY_RIGHT) {
|
||||
public boolean keyPressed(KeyEvent event) {
|
||||
if (event.key() == GLFW.GLFW_KEY_RIGHT) {
|
||||
nextPage();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == GLFW.GLFW_KEY_LEFT) {
|
||||
if (event.key() == GLFW.GLFW_KEY_LEFT) {
|
||||
previousPage();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.keyPressed(key, scancode, modifiers);
|
||||
return super.keyPressed(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,7 +186,9 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
|
||||
pose.translate(-0.5f * X_SIZE, -(Y_SIZE + COVER_SIZE), 0);
|
||||
pose.scale(1.0f, 1.0f, -1.0f);
|
||||
|
||||
drawBorder(pose, bufferSource, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightTexture.FULL_BRIGHT);
|
||||
var buffer = bufferSource.getBuffer(PrintoutRenderer.BACKGROUND);
|
||||
drawBorder(pose.last().pose(), buffer, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightTexture.FULL_BRIGHT);
|
||||
|
||||
drawText(
|
||||
pose, bufferSource, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightTexture.FULL_BRIGHT,
|
||||
state.printout().text(), state.printout().colour()
|
||||
|
@@ -19,7 +19,9 @@ import net.minecraft.client.gui.narration.NarrationElementOutput;
|
||||
import net.minecraft.client.gui.navigation.ScreenRectangle;
|
||||
import net.minecraft.client.gui.render.TextureSetup;
|
||||
import net.minecraft.client.gui.render.state.GuiElementRenderState;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.input.CharacterEvent;
|
||||
import net.minecraft.client.input.KeyEvent;
|
||||
import net.minecraft.client.input.MouseButtonEvent;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.RenderPipelines;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -78,22 +80,22 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charTyped(char ch, int modifiers) {
|
||||
var terminalChar = StringUtil.unicodeToTerminal(ch);
|
||||
public boolean charTyped(CharacterEvent event) {
|
||||
var terminalChar = StringUtil.unicodeToTerminal(event.codepoint());
|
||||
if (StringUtil.isTypableChar(terminalChar)) computer.charTyped((byte) terminalChar);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
||||
if (key == GLFW.GLFW_KEY_ESCAPE) return false;
|
||||
if (Screen.isPaste(key)) {
|
||||
public boolean keyPressed(KeyEvent event) {
|
||||
if (event.key() == GLFW.GLFW_KEY_ESCAPE) return false;
|
||||
if (event.isPaste()) {
|
||||
paste();
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) {
|
||||
switch (KeyConverter.physicalToActual(key, scancode)) {
|
||||
if ((event.modifiers() & GLFW.GLFW_MOD_CONTROL) != 0) {
|
||||
switch (KeyConverter.physicalToActual(event.key(), event.scancode())) {
|
||||
case GLFW.GLFW_KEY_T -> {
|
||||
if (terminateTimer < 0) terminateTimer = 0;
|
||||
}
|
||||
@@ -106,11 +108,11 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
}
|
||||
|
||||
if (key >= 0 && terminateTimer < KEY_SUPPRESS_DELAY && rebootTimer < KEY_SUPPRESS_DELAY && shutdownTimer < KEY_SUPPRESS_DELAY) {
|
||||
if (event.key() >= 0 && terminateTimer < KEY_SUPPRESS_DELAY && rebootTimer < KEY_SUPPRESS_DELAY && shutdownTimer < KEY_SUPPRESS_DELAY) {
|
||||
// Queue the "key" event and add to the down set
|
||||
var repeat = keysDown.get(key);
|
||||
keysDown.set(key);
|
||||
computer.keyDown(key, repeat);
|
||||
var repeat = keysDown.get(event.key());
|
||||
keysDown.set(event.key());
|
||||
computer.keyDown(event.key(), repeat);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -122,14 +124,14 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyReleased(int key, int scancode, int modifiers) {
|
||||
public boolean keyReleased(KeyEvent event) {
|
||||
// Queue the "key_up" event and remove from the down set
|
||||
if (key >= 0 && keysDown.get(key)) {
|
||||
keysDown.set(key, false);
|
||||
computer.keyUp(key);
|
||||
if (event.key() >= 0 && keysDown.get(event.key())) {
|
||||
keysDown.set(event.key(), false);
|
||||
computer.keyUp(event.key());
|
||||
}
|
||||
|
||||
switch (KeyConverter.physicalToActual(key, scancode)) {
|
||||
switch (KeyConverter.physicalToActual(event.key(), event.scancode())) {
|
||||
case GLFW.GLFW_KEY_T -> terminateTimer = -1;
|
||||
case GLFW.GLFW_KEY_R -> rebootTimer = -1;
|
||||
case GLFW.GLFW_KEY_S -> shutdownTimer = -1;
|
||||
@@ -141,18 +143,18 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
if (!inTermRegion(mouseX, mouseY)) return false;
|
||||
if (!hasMouseSupport() || button < 0 || button > 2) return false;
|
||||
public boolean mouseClicked(MouseButtonEvent event, boolean doubleClick) {
|
||||
if (!inTermRegion(event.x(), event.y())) return false;
|
||||
if (!hasMouseSupport() || event.button() < 0 || event.button() > 2) return false;
|
||||
|
||||
var charX = (int) ((mouseX - innerX) / FONT_WIDTH);
|
||||
var charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
|
||||
var charX = (int) ((event.x() - innerX) / FONT_WIDTH);
|
||||
var charY = (int) ((event.y() - innerY) / FONT_HEIGHT);
|
||||
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
||||
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
||||
|
||||
computer.mouseClick(button + 1, charX + 1, charY + 1);
|
||||
computer.mouseClick(event.button() + 1, charX + 1, charY + 1);
|
||||
|
||||
lastMouseButton = button;
|
||||
lastMouseButton = event.button();
|
||||
lastMouseX = charX;
|
||||
lastMouseY = charY;
|
||||
|
||||
@@ -160,16 +162,16 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseReleased(double mouseX, double mouseY, int button) {
|
||||
if (!inTermRegion(mouseX, mouseY)) return false;
|
||||
if (!hasMouseSupport() || button < 0 || button > 2) return false;
|
||||
public boolean mouseReleased(MouseButtonEvent event) {
|
||||
if (!inTermRegion(event.x(), event.y())) return false;
|
||||
if (!hasMouseSupport() || event.button() < 0 || event.button() > 2) return false;
|
||||
|
||||
var charX = (int) ((mouseX - innerX) / FONT_WIDTH);
|
||||
var charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
|
||||
var charX = (int) ((event.x() - innerX) / FONT_WIDTH);
|
||||
var charY = (int) ((event.y() - innerY) / FONT_HEIGHT);
|
||||
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
||||
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
||||
|
||||
if (lastMouseButton == button) {
|
||||
if (lastMouseButton == event.button()) {
|
||||
computer.mouseUp(lastMouseButton + 1, charX + 1, charY + 1);
|
||||
lastMouseButton = -1;
|
||||
}
|
||||
@@ -181,17 +183,17 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseDragged(double mouseX, double mouseY, int button, double v2, double v3) {
|
||||
if (!inTermRegion(mouseX, mouseY)) return false;
|
||||
if (!hasMouseSupport() || button < 0 || button > 2) return false;
|
||||
public boolean mouseDragged(MouseButtonEvent event, double v2, double v3) {
|
||||
if (!inTermRegion(event.x(), event.y())) return false;
|
||||
if (!hasMouseSupport() || event.button() < 0 || event.button() > 2) return false;
|
||||
|
||||
var charX = (int) ((mouseX - innerX) / FONT_WIDTH);
|
||||
var charY = (int) ((mouseY - innerY) / FONT_HEIGHT);
|
||||
var charX = (int) ((event.x() - innerX) / FONT_WIDTH);
|
||||
var charY = (int) ((event.y() - innerY) / FONT_HEIGHT);
|
||||
charX = Math.min(Math.max(charX, 0), terminal.getWidth() - 1);
|
||||
charY = Math.min(Math.max(charY, 0), terminal.getHeight() - 1);
|
||||
|
||||
if (button == lastMouseButton && (charX != lastMouseX || charY != lastMouseY)) {
|
||||
computer.mouseDrag(button + 1, charX + 1, charY + 1);
|
||||
if (event.button() == lastMouseButton && (charX != lastMouseX || charY != lastMouseY)) {
|
||||
computer.mouseDrag(event.button() + 1, charX + 1, charY + 1);
|
||||
lastMouseX = charX;
|
||||
lastMouseY = charY;
|
||||
}
|
||||
@@ -308,9 +310,8 @@ public class TerminalWidget extends AbstractWidget {
|
||||
@Nullable ScreenRectangle scissorArea
|
||||
) implements GuiElementRenderState {
|
||||
@Override
|
||||
public void buildVertices(VertexConsumer vertexConsumer, float z) {
|
||||
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose).translate(0, 0, z), vertexConsumer);
|
||||
FixedWidthFontRenderer.drawTerminalBackground(quads, x, y, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
||||
public void buildVertices(VertexConsumer buffer) {
|
||||
FixedWidthFontRenderer.drawTerminalBackground(new Matrix4f().mul(pose), buffer, x, y, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -324,14 +325,14 @@ public class TerminalWidget extends AbstractWidget {
|
||||
@Nullable ScreenRectangle bounds, @Nullable ScreenRectangle scissorArea
|
||||
) implements GuiElementRenderState {
|
||||
@Override
|
||||
public void buildVertices(VertexConsumer vertexConsumer, float z) {
|
||||
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose).translate(0, 0, z), vertexConsumer);
|
||||
FixedWidthFontRenderer.drawTerminalForeground(quads, x, y, terminal);
|
||||
FixedWidthFontRenderer.drawCursor(quads, x, y, terminal);
|
||||
public void buildVertices(VertexConsumer buffer) {
|
||||
var transform = new Matrix4f().mul(pose);
|
||||
FixedWidthFontRenderer.drawTerminalForeground(transform, buffer, x, y, terminal);
|
||||
FixedWidthFontRenderer.drawCursor(transform, buffer, x, y, terminal);
|
||||
|
||||
// The GUI renderer requires that the buffer is non-empty. Add a zero-size vertex so we always have something.
|
||||
for (var i = 0; i < 4; i++) {
|
||||
vertexConsumer.addVertex(0, 0, z).setColor(0x00ffffff).setUv(0, 0).setLight(LightTexture.FULL_BRIGHT);
|
||||
buffer.addVertex(0, 0, 0).setColor(0x00ffffff).setUv(0, 0).setLight(LightTexture.FULL_BRIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,49 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.integration.emi;
|
||||
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.integration.RecipeModHelpers;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import dev.emi.emi.api.EmiEntrypoint;
|
||||
import dev.emi.emi.api.EmiPlugin;
|
||||
import dev.emi.emi.api.EmiRegistry;
|
||||
import dev.emi.emi.api.stack.Comparison;
|
||||
import dev.emi.emi.api.stack.EmiStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
@EmiEntrypoint
|
||||
public class EMIComputerCraft implements EmiPlugin {
|
||||
@Override
|
||||
public void register(EmiRegistry registry) {
|
||||
registry.setDefaultComparison(ModRegistry.Items.TURTLE_NORMAL.get(), turtleComparison);
|
||||
registry.setDefaultComparison(ModRegistry.Items.TURTLE_ADVANCED.get(), turtleComparison);
|
||||
|
||||
registry.setDefaultComparison(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), pocketComparison);
|
||||
registry.setDefaultComparison(ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get(), pocketComparison);
|
||||
|
||||
for (var stack : RecipeModHelpers.getExtraStacks(Minecraft.getInstance().level.registryAccess())) {
|
||||
registry.addEmiStack(EmiStack.of(stack));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Comparison turtleComparison = compareStacks((left, right)
|
||||
-> TurtleItem.getUpgrade(left, TurtleSide.LEFT) == TurtleItem.getUpgrade(right, TurtleSide.LEFT)
|
||||
&& TurtleItem.getUpgrade(left, TurtleSide.RIGHT) == TurtleItem.getUpgrade(right, TurtleSide.RIGHT));
|
||||
|
||||
private static final Comparison pocketComparison = compareStacks((left, right) -> PocketComputerItem.getUpgrade(left) == PocketComputerItem.getUpgrade(right));
|
||||
|
||||
private static Comparison compareStacks(BiPredicate<ItemStack, ItemStack> test) {
|
||||
return Comparison.of((left, right) -> {
|
||||
ItemStack leftStack = left.getItemStack(), rightStack = right.getItemStack();
|
||||
return leftStack.getItem() == rightStack.getItem() && test.test(leftStack, rightStack);
|
||||
});
|
||||
}
|
||||
}
|
@@ -8,13 +8,14 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.integration.RecipeModHelpers;
|
||||
import dan200.computercraft.shared.pocket.core.PocketSide;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import mezz.jei.api.IModPlugin;
|
||||
import mezz.jei.api.JeiPlugin;
|
||||
import mezz.jei.api.constants.RecipeTypes;
|
||||
import mezz.jei.api.constants.VanillaTypes;
|
||||
import mezz.jei.api.ingredients.subtypes.IIngredientSubtypeInterpreter;
|
||||
import mezz.jei.api.ingredients.subtypes.ISubtypeInterpreter;
|
||||
import mezz.jei.api.registration.IAdvancedRegistration;
|
||||
import mezz.jei.api.registration.ISubtypeRegistration;
|
||||
import mezz.jei.api.runtime.IJeiRuntime;
|
||||
@@ -46,7 +47,7 @@ public class JEIComputerCraft implements IModPlugin {
|
||||
|
||||
@Override
|
||||
public void registerAdvanced(IAdvancedRegistration registry) {
|
||||
registry.addRecipeManagerPlugin(new RecipeResolver(getRegistryAccess()));
|
||||
registry.addSimpleRecipeManagerPlugin(RecipeTypes.CRAFTING, new RecipeResolver(getRegistryAccess()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +63,7 @@ public class JEIComputerCraft implements IModPlugin {
|
||||
// Hide all upgrade recipes
|
||||
var category = registry.createRecipeLookup(RecipeTypes.CRAFTING);
|
||||
category.get().forEach(wrapper -> {
|
||||
if (RecipeModHelpers.shouldRemoveRecipe(wrapper.id())) {
|
||||
if (RecipeModHelpers.shouldRemoveRecipe(wrapper.id().location())) {
|
||||
registry.hideRecipes(RecipeTypes.CRAFTING, List.of(wrapper));
|
||||
}
|
||||
});
|
||||
@@ -71,7 +72,7 @@ public class JEIComputerCraft implements IModPlugin {
|
||||
/**
|
||||
* Distinguishes turtles by upgrades and family.
|
||||
*/
|
||||
private static final IIngredientSubtypeInterpreter<ItemStack> turtleSubtype = (stack, ctx) -> {
|
||||
private static final ISubtypeInterpreter<ItemStack> turtleSubtype = (stack, ctx) -> {
|
||||
var name = new StringBuilder("turtle:");
|
||||
|
||||
// Add left and right upgrades to the identifier
|
||||
@@ -87,12 +88,15 @@ public class JEIComputerCraft implements IModPlugin {
|
||||
/**
|
||||
* Distinguishes pocket computers by upgrade and family.
|
||||
*/
|
||||
private static final IIngredientSubtypeInterpreter<ItemStack> pocketSubtype = (stack, ctx) -> {
|
||||
private static final ISubtypeInterpreter<ItemStack> pocketSubtype = (stack, ctx) -> {
|
||||
var name = new StringBuilder("pocket:");
|
||||
|
||||
// Add the upgrade to the identifier
|
||||
var upgrade = PocketComputerItem.getUpgradeWithData(stack);
|
||||
if (upgrade != null) name.append(upgrade.holder().key().location());
|
||||
var back = PocketComputerItem.getUpgradeWithData(stack, PocketSide.BACK);
|
||||
var bottom = PocketComputerItem.getUpgradeWithData(stack, PocketSide.BOTTOM);
|
||||
if (back != null) name.append(back.holder().key().location());
|
||||
if (back != null && bottom != null) name.append('|');
|
||||
if (bottom != null) name.append(bottom.holder().key().location());
|
||||
|
||||
return name.toString();
|
||||
};
|
||||
@@ -100,7 +104,7 @@ public class JEIComputerCraft implements IModPlugin {
|
||||
/**
|
||||
* Distinguishes disks by colour.
|
||||
*/
|
||||
private static final IIngredientSubtypeInterpreter<ItemStack> diskSubtype = (stack, ctx) -> Integer.toString(DyedItemColor.getOrDefault(stack, -1));
|
||||
private static final ISubtypeInterpreter<ItemStack> diskSubtype = (stack, ctx) -> Integer.toString(DyedItemColor.getOrDefault(stack, -1));
|
||||
|
||||
private static RegistryAccess getRegistryAccess() {
|
||||
return Minecraft.getInstance().level.registryAccess();
|
||||
|
@@ -8,71 +8,90 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.integration.UpgradeRecipeGenerator;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import mezz.jei.api.constants.RecipeTypes;
|
||||
import mezz.jei.api.recipe.IFocus;
|
||||
import mezz.jei.api.recipe.RecipeType;
|
||||
import mezz.jei.api.recipe.advanced.IRecipeManagerPlugin;
|
||||
import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import mezz.jei.api.ingredients.ITypedIngredient;
|
||||
import mezz.jei.api.recipe.advanced.ISimpleRecipeManagerPlugin;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.CraftingRecipe;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.*;
|
||||
import net.minecraft.world.item.crafting.display.RecipeDisplay;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
class RecipeResolver implements IRecipeManagerPlugin {
|
||||
private final UpgradeRecipeGenerator<RecipeHolder<CraftingRecipe>> resolver;
|
||||
|
||||
class RecipeResolver implements ISimpleRecipeManagerPlugin<RecipeHolder<CraftingRecipe>> {
|
||||
/**
|
||||
* We need to generate unique ids for each recipe, as JEI will attempt to deduplicate them otherwise.
|
||||
*/
|
||||
private int nextId = 0;
|
||||
|
||||
private final UpgradeRecipeGenerator<RecipeHolder<CraftingRecipe>> resolver;
|
||||
|
||||
RecipeResolver(HolderLookup.Provider registries) {
|
||||
resolver = new UpgradeRecipeGenerator<>(
|
||||
x -> new RecipeHolder<>(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "upgrade_" + nextId++), x),
|
||||
registries
|
||||
);
|
||||
resolver = new UpgradeRecipeGenerator<>(x -> new RecipeHolder<>(
|
||||
ResourceKey.create(Registries.RECIPE, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "upgrade_" + nextId++)),
|
||||
new CraftingWrapper(x)
|
||||
), registries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> List<RecipeType<?>> getRecipeTypes(IFocus<V> focus) {
|
||||
var value = focus.getTypedValue().getIngredient();
|
||||
if (!(value instanceof ItemStack stack)) return List.of();
|
||||
|
||||
return switch (focus.getRole()) {
|
||||
case INPUT ->
|
||||
stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem || resolver.isUpgrade(stack)
|
||||
? List.of(RecipeTypes.CRAFTING)
|
||||
: List.of();
|
||||
case OUTPUT -> stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem
|
||||
? List.of(RecipeTypes.CRAFTING)
|
||||
: List.of();
|
||||
default -> List.of();
|
||||
};
|
||||
public boolean isHandledInput(ITypedIngredient<?> input) {
|
||||
return input.getIngredient() instanceof ItemStack stack
|
||||
&& (stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem || resolver.isUpgrade(stack));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V> List<T> getRecipes(IRecipeCategory<T> recipeCategory, IFocus<V> focus) {
|
||||
if (!(focus.getTypedValue().getIngredient() instanceof ItemStack stack) || recipeCategory.getRecipeType() != RecipeTypes.CRAFTING) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return switch (focus.getRole()) {
|
||||
case INPUT -> cast(RecipeTypes.CRAFTING, resolver.findRecipesWithInput(stack));
|
||||
case OUTPUT -> cast(RecipeTypes.CRAFTING, resolver.findRecipesWithOutput(stack));
|
||||
default -> List.of();
|
||||
};
|
||||
public boolean isHandledOutput(ITypedIngredient<?> output) {
|
||||
return output.getIngredient() instanceof ItemStack stack
|
||||
&& (stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getRecipes(IRecipeCategory<T> recipeCategory) {
|
||||
public List<RecipeHolder<CraftingRecipe>> getRecipesForInput(ITypedIngredient<?> input) {
|
||||
return input.getIngredient() instanceof ItemStack stack ? resolver.findRecipesWithInput(stack) : List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RecipeHolder<CraftingRecipe>> getRecipesForOutput(ITypedIngredient<?> output) {
|
||||
return output.getIngredient() instanceof ItemStack stack ? resolver.findRecipesWithOutput(stack) : List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RecipeHolder<CraftingRecipe>> getAllRecipes() {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes", "UnusedVariable" })
|
||||
private static <T, U> List<T> cast(RecipeType<U> ignoredType, List<U> from) {
|
||||
return (List) from;
|
||||
private record CraftingWrapper(RecipeDisplay recipes) implements CraftingRecipe {
|
||||
@Override
|
||||
public RecipeSerializer<? extends CraftingRecipe> getSerializer() {
|
||||
throw new IllegalStateException("Should not serialise CraftingWrapper");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CraftingBookCategory category() {
|
||||
return CraftingBookCategory.MISC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(CraftingInput input, Level level) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack assemble(CraftingInput input, HolderLookup.Provider registries) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlacementInfo placementInfo() {
|
||||
return PlacementInfo.NOT_PLACEABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RecipeDisplay> display() {
|
||||
return List.of(recipes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -17,7 +17,7 @@ import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ItemOwner;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -35,7 +35,7 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
|
||||
).apply(instance, Unbaked::new));
|
||||
|
||||
@Override
|
||||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable LivingEntity holder, int light) {
|
||||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable ItemOwner holder, int light) {
|
||||
var overlay = TurtleItem.getOverlay(stack);
|
||||
if (overlay == null) return;
|
||||
|
||||
|
@@ -17,7 +17,7 @@ import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ItemOwner;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -36,7 +36,7 @@ public record TurtleUpgradeModel(TurtleSide side, ItemTransforms base) implement
|
||||
).apply(instance, Unbaked::new));
|
||||
|
||||
@Override
|
||||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable LivingEntity holder, int seed) {
|
||||
public void update(ItemStackRenderState state, ItemStack stack, ItemModelResolver resolver, ItemDisplayContext context, @Nullable ClientLevel level, @Nullable ItemOwner holder, int seed) {
|
||||
var upgrade = TurtleItem.getUpgradeWithData(stack, side);
|
||||
if (upgrade == null) return;
|
||||
|
||||
|
@@ -0,0 +1,65 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.model;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import net.minecraft.client.model.Model;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraft.client.model.geom.PartPose;
|
||||
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Unit;
|
||||
|
||||
import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_HEIGHT;
|
||||
import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_WIDTH;
|
||||
|
||||
/**
|
||||
* A model for {@linkplain PrintoutItem printed books} placed on a lectern.
|
||||
*
|
||||
* @see CustomLecternRenderer
|
||||
*/
|
||||
public final class LecternBookModel extends Model<Unit> {
|
||||
public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_book"), "main");
|
||||
|
||||
public LecternBookModel(ModelPart root) {
|
||||
super(root, RenderType::entitySolid);
|
||||
}
|
||||
|
||||
public static LayerDefinition createLayer() {
|
||||
var mesh = new MeshDefinition();
|
||||
var parts = mesh.getRoot();
|
||||
|
||||
parts.addOrReplaceChild(
|
||||
"spine",
|
||||
CubeListBuilder.create().texOffs(12, 15).addBox(-0.005f, -5.0f, -0.5f, 0, 10, 1.0f),
|
||||
PartPose.ZERO
|
||||
);
|
||||
|
||||
var angle = (float) Math.toRadians(5);
|
||||
parts.addOrReplaceChild(
|
||||
"left",
|
||||
CubeListBuilder.create()
|
||||
.texOffs(0, 10).addBox(0, -5.0f, -6.0f, 0, 10, 6.0f)
|
||||
.texOffs(0, 0).addBox(0.005f, -4.0f, -5.0f, 1.0f, 8.0f, 5.0f),
|
||||
PartPose.offsetAndRotation(-0.005f, 0, -0.5f, 0, -angle, 0)
|
||||
);
|
||||
|
||||
parts.addOrReplaceChild(
|
||||
"right",
|
||||
CubeListBuilder.create()
|
||||
.texOffs(14, 10).addBox(0, -5.0f, 0, 0, 10, 6.0f)
|
||||
.texOffs(0, 0).addBox(0.005f, -4.0f, 0, 1.0f, 8.0f, 5.0f),
|
||||
PartPose.offsetAndRotation(-0.005f, 0, 0.5f, 0, angle, 0)
|
||||
);
|
||||
|
||||
return LayerDefinition.create(mesh, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
}
|
||||
}
|
@@ -10,16 +10,22 @@ import dan200.computercraft.client.pocket.PocketComputerData;
|
||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import net.minecraft.client.model.Model;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraft.client.model.geom.PartPose;
|
||||
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.client.resources.model.MaterialSet;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.item.component.DyedItemColor;
|
||||
|
||||
/**
|
||||
@@ -27,18 +33,14 @@ import net.minecraft.world.item.component.DyedItemColor;
|
||||
*
|
||||
* @see CustomLecternRenderer
|
||||
*/
|
||||
public class LecternPocketModel {
|
||||
public static final ResourceLocation TEXTURE_NORMAL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_normal");
|
||||
public static final ResourceLocation TEXTURE_ADVANCED = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_advanced");
|
||||
public static final ResourceLocation TEXTURE_COLOUR = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_colour");
|
||||
public static final ResourceLocation TEXTURE_FRAME = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_frame");
|
||||
public static final ResourceLocation TEXTURE_LIGHT = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_light");
|
||||
public class LecternPocketModel extends Model<Unit> {
|
||||
public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_pocket"), "main");
|
||||
|
||||
private static final Material MATERIAL_NORMAL = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_NORMAL);
|
||||
private static final Material MATERIAL_ADVANCED = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_ADVANCED);
|
||||
private static final Material MATERIAL_COLOUR = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_COLOUR);
|
||||
private static final Material MATERIAL_FRAME = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_FRAME);
|
||||
private static final Material MATERIAL_LIGHT = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_LIGHT);
|
||||
public static final Material MATERIAL_NORMAL = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_normal"));
|
||||
public static final Material MATERIAL_ADVANCED = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_advanced"));
|
||||
public static final Material MATERIAL_COLOUR = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_colour"));
|
||||
public static final Material MATERIAL_FRAME = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_frame"));
|
||||
public static final Material MATERIAL_LIGHT = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_light"));
|
||||
|
||||
// The size of the terminal within the model.
|
||||
public static final float TERM_WIDTH = 12.0f / 32.0f;
|
||||
@@ -48,13 +50,11 @@ public class LecternPocketModel {
|
||||
private static final int TEXTURE_WIDTH = 48 / 2;
|
||||
private static final int TEXTURE_HEIGHT = 48 / 2;
|
||||
|
||||
private final ModelPart root;
|
||||
|
||||
public LecternPocketModel() {
|
||||
root = buildPages();
|
||||
public LecternPocketModel(ModelPart root) {
|
||||
super(root, RenderType::entityCutout);
|
||||
}
|
||||
|
||||
private static ModelPart buildPages() {
|
||||
public static LayerDefinition createLayer() {
|
||||
var mesh = new MeshDefinition();
|
||||
var parts = mesh.getRoot();
|
||||
parts.addOrReplaceChild(
|
||||
@@ -62,29 +62,43 @@ public class LecternPocketModel {
|
||||
CubeListBuilder.create().texOffs(0, 0).addBox(0f, -5.0f, -4.0f, 1f, 10.0f, 8.0f),
|
||||
PartPose.ZERO
|
||||
);
|
||||
return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
return LayerDefinition.create(mesh, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the pocket computer model.
|
||||
*
|
||||
* @param poseStack The current pose stack.
|
||||
* @param bufferSource The buffer source to draw to.
|
||||
* @param packedLight The current light level.
|
||||
* @param packedOverlay The overlay texture (used for entity hurt animation).
|
||||
* @param family The computer family.
|
||||
* @param frameColour The pocket computer's {@linkplain DyedItemColor colour}.
|
||||
* @param lightColour The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}.
|
||||
* @param poseStack The current pose stack.
|
||||
* @param collector The collector to draw to.
|
||||
* @param materials The current materials
|
||||
* @param packedLight The current light level.
|
||||
* @param family The computer family.
|
||||
* @param frameColour The pocket computer's {@linkplain DyedItemColor colour}.
|
||||
* @param lightColour The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}.
|
||||
*/
|
||||
public void render(PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, ComputerFamily family, int frameColour, int lightColour) {
|
||||
public void submit(
|
||||
PoseStack poseStack, SubmitNodeCollector collector, MaterialSet materials, int packedLight, ComputerFamily family, int frameColour, int lightColour
|
||||
) {
|
||||
if (frameColour != -1) {
|
||||
root.render(poseStack, MATERIAL_FRAME.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay);
|
||||
root.render(poseStack, MATERIAL_COLOUR.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay, frameColour);
|
||||
collector.submitModel(
|
||||
this, Unit.INSTANCE, poseStack, MATERIAL_FRAME.renderType(RenderType::entityCutout),
|
||||
packedLight, OverlayTexture.NO_OVERLAY, -1, materials.get(MATERIAL_FRAME), 0, null
|
||||
);
|
||||
collector.submitModel(
|
||||
this, Unit.INSTANCE, poseStack, MATERIAL_COLOUR.renderType(RenderType::entityCutout),
|
||||
packedLight, OverlayTexture.NO_OVERLAY, frameColour, materials.get(MATERIAL_COLOUR), 0, null
|
||||
);
|
||||
} else {
|
||||
var buffer = (family == ComputerFamily.ADVANCED ? MATERIAL_ADVANCED : MATERIAL_NORMAL).buffer(bufferSource, RenderType::entityCutout);
|
||||
root.render(poseStack, buffer, packedLight, packedOverlay);
|
||||
var material = family == ComputerFamily.ADVANCED ? MATERIAL_ADVANCED : MATERIAL_NORMAL;
|
||||
collector.submitModel(
|
||||
this, Unit.INSTANCE, poseStack, material.renderType(RenderType::entityCutout),
|
||||
packedLight, OverlayTexture.NO_OVERLAY, -1, materials.get(material), 0, null
|
||||
);
|
||||
}
|
||||
|
||||
root.render(poseStack, MATERIAL_LIGHT.buffer(bufferSource, RenderType::entityCutout), LightTexture.FULL_BRIGHT, packedOverlay, lightColour);
|
||||
collector.submitModel(
|
||||
this, Unit.INSTANCE, poseStack, MATERIAL_LIGHT.renderType(RenderType::entityCutout),
|
||||
LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, lightColour, materials.get(MATERIAL_LIGHT), 0, null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -4,52 +4,46 @@
|
||||
|
||||
package dan200.computercraft.client.model;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import net.minecraft.client.model.Model;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.model.geom.ModelPart;
|
||||
import net.minecraft.client.model.geom.PartPose;
|
||||
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_HEIGHT;
|
||||
import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_WIDTH;
|
||||
|
||||
/**
|
||||
* A model for {@linkplain PrintoutItem printouts} placed on a lectern.
|
||||
* <p>
|
||||
* This provides two models, {@linkplain #renderPages(PoseStack, VertexConsumer, int, int, int) one for a variable
|
||||
* number of pages}, and {@linkplain #renderBook(PoseStack, VertexConsumer, int, int) one for books}.
|
||||
* A model for {@linkplain PrintoutItem printouts} placed on a lectern. This renders a variable number of pages (1-3),
|
||||
* stored in {@link State#pages}.
|
||||
*
|
||||
* @see CustomLecternRenderer
|
||||
*/
|
||||
public class LecternPrintoutModel {
|
||||
public static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/printout");
|
||||
public static final Material MATERIAL = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE);
|
||||
|
||||
private static final int TEXTURE_WIDTH = 32;
|
||||
private static final int TEXTURE_HEIGHT = 32;
|
||||
public final class LecternPrintoutModel extends Model<LecternPrintoutModel.State> {
|
||||
public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_printout"), "main");
|
||||
|
||||
private static final String PAGE_1 = "page_1";
|
||||
private static final String PAGE_2 = "page_2";
|
||||
private static final String PAGE_3 = "page_3";
|
||||
private static final List<String> PAGES = List.of(PAGE_1, PAGE_2, PAGE_3);
|
||||
|
||||
private final ModelPart pagesRoot;
|
||||
private final ModelPart bookRoot;
|
||||
private final ModelPart[] pages;
|
||||
|
||||
public LecternPrintoutModel() {
|
||||
pagesRoot = buildPages();
|
||||
bookRoot = buildBook();
|
||||
pages = PAGES.stream().map(pagesRoot::getChild).toArray(ModelPart[]::new);
|
||||
public LecternPrintoutModel(ModelPart root) {
|
||||
super(root, RenderType::entitySolid);
|
||||
pages = PAGES.stream().map(root::getChild).toArray(ModelPart[]::new);
|
||||
}
|
||||
|
||||
private static ModelPart buildPages() {
|
||||
public static LayerDefinition createLayer() {
|
||||
var mesh = new MeshDefinition();
|
||||
var parts = mesh.getRoot();
|
||||
parts.addOrReplaceChild(
|
||||
@@ -69,49 +63,20 @@ public class LecternPrintoutModel {
|
||||
PartPose.offsetAndRotation(-0.25f, 0, -1.5f, (float) -Math.PI * (2f / 16), 0, 0)
|
||||
);
|
||||
|
||||
return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
return LayerDefinition.create(mesh, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
}
|
||||
|
||||
private static ModelPart buildBook() {
|
||||
var mesh = new MeshDefinition();
|
||||
var parts = mesh.getRoot();
|
||||
|
||||
parts.addOrReplaceChild(
|
||||
"spine",
|
||||
CubeListBuilder.create().texOffs(12, 15).addBox(-0.005f, -5.0f, -0.5f, 0, 10, 1.0f),
|
||||
PartPose.ZERO
|
||||
);
|
||||
|
||||
var angle = (float) Math.toRadians(5);
|
||||
parts.addOrReplaceChild(
|
||||
"left",
|
||||
CubeListBuilder.create()
|
||||
.texOffs(0, 10).addBox(0, -5.0f, -6.0f, 0, 10, 6.0f)
|
||||
.texOffs(0, 0).addBox(0.005f, -4.0f, -5.0f, 1.0f, 8.0f, 5.0f),
|
||||
PartPose.offsetAndRotation(-0.005f, 0, -0.5f, 0, -angle, 0)
|
||||
);
|
||||
|
||||
parts.addOrReplaceChild(
|
||||
"right",
|
||||
CubeListBuilder.create()
|
||||
.texOffs(14, 10).addBox(0, -5.0f, 0, 0, 10, 6.0f)
|
||||
.texOffs(0, 0).addBox(0.005f, -4.0f, 0, 1.0f, 8.0f, 5.0f),
|
||||
PartPose.offsetAndRotation(-0.005f, 0, 0.5f, 0, angle, 0)
|
||||
);
|
||||
|
||||
return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||
}
|
||||
|
||||
public void renderBook(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay) {
|
||||
bookRoot.render(poseStack, buffer, packedLight, packedOverlay);
|
||||
}
|
||||
|
||||
public void renderPages(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int pageCount) {
|
||||
@Override
|
||||
public void setupAnim(State renderState) {
|
||||
var pageCount = renderState.pages;
|
||||
if (pageCount > pages.length) pageCount = pages.length;
|
||||
|
||||
var i = 0;
|
||||
for (; i < pageCount; i++) pages[i].visible = true;
|
||||
for (; i < pages.length; i++) pages[i].visible = false;
|
||||
}
|
||||
|
||||
pagesRoot.render(poseStack, buffer, packedLight, packedOverlay);
|
||||
public static class State {
|
||||
public int pages;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.model;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.resources.model.Material;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Definitions for the lectern printout model.
|
||||
*
|
||||
* @see LecternBookModel
|
||||
* @see LecternPrintoutModel
|
||||
*/
|
||||
public final class LecternPrintoutModelDefinitions {
|
||||
public static final Material MATERIAL = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "printout"));
|
||||
|
||||
static final int TEXTURE_WIDTH = 32;
|
||||
static final int TEXTURE_HEIGHT = 32;
|
||||
|
||||
private LecternPrintoutModelDefinitions() {
|
||||
}
|
||||
}
|
@@ -6,26 +6,36 @@ package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import dan200.computercraft.client.model.LecternBookModel;
|
||||
import dan200.computercraft.client.model.LecternPocketModel;
|
||||
import dan200.computercraft.client.model.LecternPrintoutModel;
|
||||
import dan200.computercraft.client.model.LecternPrintoutModelDefinitions;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
|
||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.LecternRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.client.resources.model.MaterialSet;
|
||||
import net.minecraft.util.ARGB;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.item.component.DyedItemColor;
|
||||
import net.minecraft.world.level.block.LecternBlock;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
@@ -36,60 +46,89 @@ import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FON
|
||||
* <p>
|
||||
* This largely follows {@link LecternRenderer}, but with support for multiple types of item.
|
||||
*/
|
||||
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity> {
|
||||
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity, CustomLecternRenderer.State> {
|
||||
private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32;
|
||||
|
||||
private final MaterialSet materials;
|
||||
private final LecternPrintoutModel printoutModel;
|
||||
private final LecternBookModel bookModel;
|
||||
private final LecternPocketModel pocketModel;
|
||||
|
||||
public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
|
||||
printoutModel = new LecternPrintoutModel();
|
||||
pocketModel = new LecternPocketModel();
|
||||
materials = context.materials();
|
||||
bookModel = new LecternBookModel(context.bakeLayer(LecternBookModel.LAYER));
|
||||
printoutModel = new LecternPrintoutModel(context.bakeLayer(LecternPrintoutModel.LAYER));
|
||||
pocketModel = new LecternPocketModel(context.bakeLayer(LecternPocketModel.LAYER));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(CustomLecternBlockEntity lectern, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay, Vec3 camera) {
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(0.5f, 1.0625f, 0.5f);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(-lectern.getBlockState().getValue(LecternBlock.FACING).getClockWise().toYRot()));
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees(67.5f));
|
||||
poseStack.translate(0, -0.125f, 0);
|
||||
public State createRenderState() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractRenderState(CustomLecternBlockEntity lectern, State state, float f, Vec3 camera, ModelFeatureRenderer.@Nullable CrumblingOverlay overlay) {
|
||||
BlockEntityRenderer.super.extractRenderState(lectern, state, f, camera, overlay);
|
||||
|
||||
var item = lectern.getItem();
|
||||
if (item.getItem() instanceof PrintoutItem) {
|
||||
var vertexConsumer = LecternPrintoutModel.MATERIAL.buffer(buffer, RenderType::entitySolid);
|
||||
if (item.is(ModRegistry.Items.PRINTED_BOOK.get())) {
|
||||
printoutModel.renderBook(poseStack, vertexConsumer, packedLight, packedOverlay);
|
||||
} else {
|
||||
printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutData.getOrEmpty(item).pages());
|
||||
}
|
||||
state.setPrintout(item.is(ModRegistry.Items.PRINTED_BOOK.get()), PrintoutData.getOrEmpty(item).pages());
|
||||
} else if (item.getItem() instanceof PocketComputerItem pocket) {
|
||||
var computer = ClientPocketComputers.get(item);
|
||||
|
||||
pocketModel.render(
|
||||
poseStack, buffer, packedLight, packedOverlay, pocket.getFamily(), DyedItemColor.getOrDefault(item, -1),
|
||||
ARGB.opaque(computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState())
|
||||
state.setPocket(
|
||||
pocket.getFamily(), DyedItemColor.getOrDefault(item, -1),
|
||||
ARGB.opaque(computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState()),
|
||||
// Only render a terminal if we're close to it.
|
||||
computer == null || !Vec3.atCenterOf(lectern.getBlockPos()).closerThan(camera, POCKET_TERMINAL_RENDER_DISTANCE)
|
||||
? null : computer.getTerminal()
|
||||
);
|
||||
} else {
|
||||
state.setUnknown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(State state, PoseStack poseStack, SubmitNodeCollector collector, CameraRenderState cameraRenderState) {
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(0.5f, 1.0625f, 0.5f);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(-state.blockState.getValue(LecternBlock.FACING).getClockWise().toYRot()));
|
||||
poseStack.mulPose(Axis.ZP.rotationDegrees(67.5f));
|
||||
poseStack.translate(0, -0.125f, 0);
|
||||
|
||||
if (state.type == Type.PRINTOUT) {
|
||||
if (state.isBook) {
|
||||
collector.submitModel(
|
||||
bookModel, Unit.INSTANCE, poseStack, LecternPrintoutModelDefinitions.MATERIAL.renderType(RenderType::entitySolid),
|
||||
state.lightCoords, OverlayTexture.NO_OVERLAY, -1,
|
||||
materials.get(LecternPrintoutModelDefinitions.MATERIAL), 0, null
|
||||
);
|
||||
} else {
|
||||
collector.submitModel(
|
||||
printoutModel, state.printoutState, poseStack, LecternPrintoutModelDefinitions.MATERIAL.renderType(RenderType::entitySolid),
|
||||
state.lightCoords, OverlayTexture.NO_OVERLAY, -1,
|
||||
materials.get(LecternPrintoutModelDefinitions.MATERIAL), 0, null
|
||||
);
|
||||
}
|
||||
} else if (state.type == Type.POCKET_COMPUTER) {
|
||||
pocketModel.submit(poseStack, collector, materials, state.lightCoords, state.pocketFamily, state.pocketColour, state.pocketLight);
|
||||
|
||||
// Jiggle the terminal about a bit, so (0, 0) is in the top left of the model's terminal hole.
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(90f));
|
||||
poseStack.translate(-0.5 * LecternPocketModel.TERM_WIDTH, 0.5 * LecternPocketModel.TERM_HEIGHT + 1f / 32.0f, 1 / 16.0f);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
|
||||
// Either render the terminal or a black screen, depending on how close we are.
|
||||
var terminal = computer == null ? null : computer.getTerminal();
|
||||
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(poseStack, buffer.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
|
||||
if (terminal != null && Vec3.atCenterOf(lectern.getBlockPos()).closerThan(camera, POCKET_TERMINAL_RENDER_DISTANCE)) {
|
||||
renderPocketTerminal(poseStack, quadEmitter, terminal);
|
||||
// Either render the terminal or a black screen.
|
||||
if (state.pocketTerminal != null) {
|
||||
renderPocketTerminal(poseStack, collector, state.pocketTerminal);
|
||||
} else {
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, LecternPocketModel.TERM_WIDTH, LecternPocketModel.TERM_HEIGHT);
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(poseStack, collector, 0, 0, LecternPocketModel.TERM_WIDTH, LecternPocketModel.TERM_HEIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
|
||||
private static void renderPocketTerminal(PoseStack poseStack, FixedWidthFontRenderer.QuadEmitter quadEmitter, Terminal terminal) {
|
||||
private static void renderPocketTerminal(PoseStack poseStack, SubmitNodeCollector collector, Terminal terminal) {
|
||||
var width = terminal.getWidth() * FONT_WIDTH;
|
||||
var height = terminal.getHeight() * FONT_HEIGHT;
|
||||
|
||||
@@ -103,6 +142,48 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
|
||||
var marginX = ((LecternPocketModel.TERM_WIDTH / scale) - width) / 2;
|
||||
var marginY = ((LecternPocketModel.TERM_HEIGHT / scale) - height) / 2;
|
||||
|
||||
FixedWidthFontRenderer.drawTerminal(quadEmitter, marginX, marginY, terminal, marginY, marginY, marginX, marginX);
|
||||
collector.submitCustomGeometry(poseStack, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) ->
|
||||
FixedWidthFontRenderer.drawTerminal(pose.pose(), buffer, marginX, marginY, terminal, marginY, marginY, marginX, marginX));
|
||||
}
|
||||
|
||||
private enum Type {
|
||||
PRINTOUT,
|
||||
POCKET_COMPUTER,
|
||||
UNKNOWN,
|
||||
}
|
||||
|
||||
public static final class State extends BlockEntityRenderState {
|
||||
private Type type = Type.PRINTOUT;
|
||||
private boolean isBook;
|
||||
private final LecternPrintoutModel.State printoutState = new LecternPrintoutModel.State();
|
||||
|
||||
private ComputerFamily pocketFamily = ComputerFamily.NORMAL;
|
||||
private int pocketColour;
|
||||
private int pocketLight;
|
||||
private @Nullable Terminal pocketTerminal; // TODO: Make this immutable
|
||||
|
||||
private State() {
|
||||
}
|
||||
|
||||
private void setUnknown() {
|
||||
this.type = Type.UNKNOWN;
|
||||
this.pocketTerminal = null;
|
||||
}
|
||||
|
||||
private void setPrintout(boolean isBook, int pages) {
|
||||
this.type = Type.PRINTOUT;
|
||||
this.isBook = isBook;
|
||||
this.printoutState.pages = pages;
|
||||
|
||||
this.pocketTerminal = null;
|
||||
}
|
||||
|
||||
private void setPocket(ComputerFamily family, int colour, int light, @Nullable Terminal terminal) {
|
||||
this.type = Type.POCKET_COMPUTER;
|
||||
this.pocketFamily = family;
|
||||
this.pocketColour = colour;
|
||||
this.pocketLight = light;
|
||||
this.pocketTerminal = terminal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.HumanoidArm;
|
||||
@@ -22,29 +22,29 @@ import java.util.Objects;
|
||||
/**
|
||||
* A base class for items which have map-like rendering when held in the hand.
|
||||
*
|
||||
* @see dan200.computercraft.client.ClientHooks#onRenderHeldItem(PoseStack, MultiBufferSource, int, InteractionHand, float, float, float, ItemStack)
|
||||
* @see dan200.computercraft.client.ClientHooks#onRenderHeldItem(PoseStack, SubmitNodeCollector, int, InteractionHand, float, float, float, ItemStack)
|
||||
*/
|
||||
public abstract class ItemMapLikeRenderer {
|
||||
/**
|
||||
* The main rendering method for the item.
|
||||
*
|
||||
* @param transform The matrix transformation stack
|
||||
* @param render The buffer to render to
|
||||
* @param collector The buffer to render to
|
||||
* @param stack The stack to render
|
||||
* @param light The packed lightmap coordinates.
|
||||
* @see ItemInHandRenderer#renderItem(LivingEntity, ItemStack, ItemDisplayContext, boolean, PoseStack, MultiBufferSource, int)
|
||||
* @see ItemInHandRenderer#renderItem(LivingEntity, ItemStack, ItemDisplayContext, PoseStack, SubmitNodeCollector, int)
|
||||
*/
|
||||
protected abstract void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light);
|
||||
protected abstract void renderItem(PoseStack transform, SubmitNodeCollector collector, ItemStack stack, int light);
|
||||
|
||||
public void renderItemFirstPerson(PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
public void renderItemFirstPerson(PoseStack transform, SubmitNodeCollector collector, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
Player player = Objects.requireNonNull(Minecraft.getInstance().player);
|
||||
|
||||
transform.pushPose();
|
||||
if (hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty()) {
|
||||
renderItemFirstPersonCenter(transform, render, lightTexture, pitch, equipProgress, swingProgress, stack);
|
||||
renderItemFirstPersonCenter(transform, collector, lightTexture, pitch, equipProgress, swingProgress, stack);
|
||||
} else {
|
||||
renderItemFirstPersonSide(
|
||||
transform, render, lightTexture,
|
||||
transform, collector, lightTexture,
|
||||
hand == InteractionHand.MAIN_HAND ? player.getMainArm() : player.getMainArm().getOpposite(),
|
||||
equipProgress, swingProgress, stack
|
||||
);
|
||||
@@ -56,15 +56,15 @@ public abstract class ItemMapLikeRenderer {
|
||||
* Renders the item to one side of the player.
|
||||
*
|
||||
* @param transform The matrix transformation stack
|
||||
* @param render The buffer to render to
|
||||
* @param collector The buffer to render to
|
||||
* @param combinedLight The current light level
|
||||
* @param side The side to render on
|
||||
* @param equipProgress The equip progress of this item
|
||||
* @param swingProgress The swing progress of this item
|
||||
* @param stack The stack to render
|
||||
* @see ItemInHandRenderer#renderOneHandedMap(PoseStack, MultiBufferSource, int, float, HumanoidArm, float, ItemStack)
|
||||
* @see ItemInHandRenderer#renderOneHandedMap(PoseStack, SubmitNodeCollector, int, float, HumanoidArm, float, ItemStack)
|
||||
*/
|
||||
private void renderItemFirstPersonSide(PoseStack transform, MultiBufferSource render, int combinedLight, HumanoidArm side, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
private void renderItemFirstPersonSide(PoseStack transform, SubmitNodeCollector collector, int combinedLight, HumanoidArm side, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
var offset = side == HumanoidArm.RIGHT ? 1f : -1f;
|
||||
transform.translate(offset * 0.125f, -0.125f, 0f);
|
||||
@@ -73,7 +73,7 @@ public abstract class ItemMapLikeRenderer {
|
||||
if (!minecraft.player.isInvisible()) {
|
||||
transform.pushPose();
|
||||
transform.mulPose(Axis.ZP.rotationDegrees(offset * 10f));
|
||||
minecraft.getEntityRenderDispatcher().getItemInHandRenderer().renderPlayerArm(transform, render, combinedLight, equipProgress, swingProgress, side);
|
||||
minecraft.getEntityRenderDispatcher().getItemInHandRenderer().renderPlayerArm(transform, collector, combinedLight, equipProgress, swingProgress, side);
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public abstract class ItemMapLikeRenderer {
|
||||
transform.mulPose(Axis.XP.rotationDegrees(f2 * -45f));
|
||||
transform.mulPose(Axis.YP.rotationDegrees(offset * f2 * -30f));
|
||||
|
||||
renderItem(transform, render, stack, combinedLight);
|
||||
renderItem(transform, collector, stack, combinedLight);
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
@@ -99,15 +99,15 @@ public abstract class ItemMapLikeRenderer {
|
||||
* Render an item in the middle of the screen.
|
||||
*
|
||||
* @param transform The matrix transformation stack
|
||||
* @param render The buffer to render to
|
||||
* @param collector The buffer to render to
|
||||
* @param combinedLight The current light level
|
||||
* @param pitch The pitch of the player
|
||||
* @param equipProgress The equip progress of this item
|
||||
* @param swingProgress The swing progress of this item
|
||||
* @param stack The stack to render
|
||||
* @see ItemInHandRenderer#renderTwoHandedMap(PoseStack, MultiBufferSource, int, float, float, float)
|
||||
* @see ItemInHandRenderer#renderTwoHandedMap(PoseStack, SubmitNodeCollector, int, float, float, float)
|
||||
*/
|
||||
private void renderItemFirstPersonCenter(PoseStack transform, MultiBufferSource render, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
private void renderItemFirstPersonCenter(PoseStack transform, SubmitNodeCollector collector, int combinedLight, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
var renderer = minecraft.getEntityRenderDispatcher().getItemInHandRenderer();
|
||||
|
||||
@@ -124,8 +124,8 @@ public abstract class ItemMapLikeRenderer {
|
||||
if (!minecraft.player.isInvisible()) {
|
||||
transform.pushPose();
|
||||
transform.mulPose(Axis.YP.rotationDegrees(90.0F));
|
||||
renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.RIGHT);
|
||||
renderer.renderMapHand(transform, render, combinedLight, HumanoidArm.LEFT);
|
||||
renderer.renderMapHand(transform, collector, combinedLight, HumanoidArm.RIGHT);
|
||||
renderer.renderMapHand(transform, collector, combinedLight, HumanoidArm.LEFT);
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
@@ -133,6 +133,6 @@ public abstract class ItemMapLikeRenderer {
|
||||
transform.mulPose(Axis.XP.rotationDegrees(rX * 20.0F));
|
||||
transform.scale(2.0F, 2.0F, 2.0F);
|
||||
|
||||
renderItem(transform, render, stack, combinedLight);
|
||||
renderItem(transform, collector, stack, combinedLight);
|
||||
}
|
||||
}
|
||||
|
@@ -15,12 +15,14 @@ import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.resources.metadata.gui.GuiMetadataSection;
|
||||
import net.minecraft.client.resources.metadata.gui.GuiSpriteScaling;
|
||||
import net.minecraft.data.AtlasIds;
|
||||
import net.minecraft.util.ARGB;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.DyedItemColor;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
||||
@@ -42,7 +44,7 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderItem(PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light) {
|
||||
protected void renderItem(PoseStack transform, SubmitNodeCollector collector, ItemStack stack, int light) {
|
||||
var computer = ClientPocketComputers.get(stack);
|
||||
var terminal = computer == null ? null : computer.getTerminal();
|
||||
|
||||
@@ -74,42 +76,41 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
||||
var family = item.getFamily();
|
||||
var frameColour = DyedItemColor.getOrDefault(stack, -1);
|
||||
|
||||
var matrix = transform.last().pose();
|
||||
renderFrame(matrix, bufferSource, family, frameColour, light, width, height);
|
||||
renderFrame(transform, collector, family, frameColour, light, width, height);
|
||||
|
||||
// Render the light
|
||||
var lightColour = computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState();
|
||||
renderLight(transform, bufferSource, lightColour, width, height);
|
||||
renderLight(transform, collector, lightColour, width, height);
|
||||
|
||||
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT));
|
||||
if (terminal == null) {
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, width, height);
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(transform, collector, 0, 0, width, height);
|
||||
} else {
|
||||
FixedWidthFontRenderer.drawTerminal(quadEmitter, MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
||||
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) ->
|
||||
FixedWidthFontRenderer.drawTerminal(pose.pose(), buffer, MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN));
|
||||
}
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private static void renderFrame(Matrix4f transform, MultiBufferSource render, ComputerFamily family, int colour, int light, int width, int height) {
|
||||
private static void renderFrame(PoseStack transform, SubmitNodeCollector submit, ComputerFamily family, int colour, int light, int width, int height) {
|
||||
var textures = colour != -1 ? GuiSprites.COMPUTER_COLOUR : GuiSprites.getComputerTextures(family);
|
||||
var spriteRenderer = new SpriteRenderer(transform, render, 0, light, colour);
|
||||
var spriteRenderer = new SpriteRenderer(transform, submit, 0, light, colour);
|
||||
renderBorder(spriteRenderer, textures, width, height);
|
||||
}
|
||||
|
||||
private static void renderBorder(SpriteRenderer renderer, GuiSprites.ComputerTextures textures, int width, int height) {
|
||||
var sprites = Minecraft.getInstance().getGuiSprites();
|
||||
var sprites = Minecraft.getInstance().getAtlasManager().getAtlasOrThrow(AtlasIds.GUI);
|
||||
|
||||
// Find our border, forcing it to be a nine-sliced texture.
|
||||
var borderSprite = sprites.getSprite(textures.border());
|
||||
var borderSlice = getSlice(sprites.getSpriteScaling(borderSprite), DEFAULT_BORDER);
|
||||
var borderSlice = getSlice(borderSprite, DEFAULT_BORDER);
|
||||
var borderBounds = borderSlice.border();
|
||||
|
||||
// And take the separate bottom bit of the pocket computer.
|
||||
var bottomTexture = textures.pocketBottom();
|
||||
if (bottomTexture == null) throw new NullPointerException(textures + " has no pocket texture");
|
||||
var bottomSprite = sprites.getSprite(bottomTexture);
|
||||
var bottomSlice = getSlice(sprites.getSpriteScaling(bottomSprite), DEFAULT_BOTTOM);
|
||||
var bottomSlice = getSlice(bottomSprite, DEFAULT_BOTTOM);
|
||||
var bottomBounds = bottomSlice.border();
|
||||
|
||||
// Now draw a nine-sliced texture, by stitching together the top parts of the border with the pocket bottom.
|
||||
@@ -157,13 +158,12 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
||||
);
|
||||
}
|
||||
|
||||
private static void renderLight(PoseStack transform, MultiBufferSource render, int colour, int width, int height) {
|
||||
var buffer = render.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
|
||||
FixedWidthFontRenderer.drawQuad(
|
||||
FixedWidthFontRenderer.toVertexConsumer(transform, buffer),
|
||||
private static void renderLight(PoseStack transform, SubmitNodeCollector render, int colour, int width, int height) {
|
||||
render.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> FixedWidthFontRenderer.drawQuad(
|
||||
pose.pose(), buffer,
|
||||
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
|
||||
ARGB.opaque(colour), LightTexture.FULL_BRIGHT
|
||||
);
|
||||
));
|
||||
}
|
||||
|
||||
private static final GuiSpriteScaling.NineSlice DEFAULT_BORDER = new GuiSpriteScaling.NineSlice(
|
||||
@@ -177,4 +177,8 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
||||
private static GuiSpriteScaling.NineSlice getSlice(GuiSpriteScaling scaling, GuiSpriteScaling.NineSlice fallback) {
|
||||
return scaling instanceof GuiSpriteScaling.NineSlice slice ? slice : fallback;
|
||||
}
|
||||
|
||||
private static GuiSpriteScaling.NineSlice getSlice(TextureAtlasSprite sprite, GuiSpriteScaling.NineSlice fallback) {
|
||||
return getSlice(sprite.contents().getAdditionalMetadata(GuiMetadataSection.TYPE).orElse(GuiMetadataSection.DEFAULT).scaling(), fallback);
|
||||
}
|
||||
}
|
||||
|
@@ -6,9 +6,10 @@ package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
@@ -28,26 +29,26 @@ public final class PrintoutItemRenderer extends ItemMapLikeRenderer {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) {
|
||||
protected void renderItem(PoseStack transform, SubmitNodeCollector collector, ItemStack stack, int light) {
|
||||
transform.mulPose(Axis.XP.rotationDegrees(180f));
|
||||
transform.scale(0.42f, 0.42f, -0.42f);
|
||||
transform.translate(-0.5f, -0.48f, 0.0f);
|
||||
|
||||
drawPrintout(transform, render, PrintoutData.getOrEmpty(stack), stack.getItem() == ModRegistry.Items.PRINTED_BOOK.get(), light);
|
||||
drawPrintout(transform, collector, PrintoutData.getOrEmpty(stack), stack.getItem() == ModRegistry.Items.PRINTED_BOOK.get(), light);
|
||||
}
|
||||
|
||||
public static void onRenderInFrame(PoseStack transform, MultiBufferSource render, ItemFrameRenderState frame, PrintoutData data, boolean isBook, int packedLight) {
|
||||
public static void onRenderInFrame(PoseStack transform, SubmitNodeCollector collector, ItemFrameRenderState frame, PrintoutData data, boolean isBook) {
|
||||
// Move a little bit forward to ensure we're not clipping with the frame
|
||||
transform.translate(0.0f, 0.0f, -0.001f);
|
||||
transform.mulPose(Axis.ZP.rotationDegrees(180f));
|
||||
transform.scale(0.95f, 0.95f, -0.95f);
|
||||
transform.translate(-0.5f, -0.5f, 0.0f);
|
||||
|
||||
var light = frame.isGlowFrame ? 0xf000d2 : packedLight; // See getLightCoords.
|
||||
drawPrintout(transform, render, data, isBook, light);
|
||||
var light = frame.isGlowFrame ? 0xf000d2 : frame.lightCoords; // See getLightCoords.
|
||||
drawPrintout(transform, collector, data, isBook, light);
|
||||
}
|
||||
|
||||
private static void drawPrintout(PoseStack transform, MultiBufferSource render, PrintoutData pageData, boolean book, int light) {
|
||||
private static void drawPrintout(PoseStack transform, SubmitNodeCollector collector, PrintoutData pageData, boolean book, int light) {
|
||||
var pages = pageData.pages();
|
||||
|
||||
double width = LINE_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
|
||||
@@ -71,7 +72,7 @@ public final class PrintoutItemRenderer extends ItemMapLikeRenderer {
|
||||
transform.scale(scale, scale, scale);
|
||||
transform.translate((max - width) / 2.0, (max - height) / 2.0, 0.0);
|
||||
|
||||
drawBorder(transform, render, 0, 0, -0.01f, 0, pages, book, light);
|
||||
drawText(transform, render, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, pageData.lines());
|
||||
collector.submitCustomGeometry(transform, BACKGROUND, (matrix, buffer) -> drawBorder(matrix.pose(), buffer, 0, 0, -0.01f, 0, pages, book, light));
|
||||
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (matrix, buffer) -> drawText(matrix.pose(), buffer, X_TEXT_MARGIN, Y_TEXT_MARGIN, 0, light, pageData.lines()));
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ public final class PrintoutRenderer {
|
||||
* Printout's background texture. {@link RenderType#text(ResourceLocation)} is a <em>little</em> questionable, but
|
||||
* it is what maps use, so should behave the same as vanilla in both item frames and in-hand.
|
||||
*/
|
||||
private static final RenderType BACKGROUND = RenderType.text(ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/printout.png"));
|
||||
public static final RenderType BACKGROUND = RenderType.text(ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/printout.png"));
|
||||
|
||||
private static final float BG_SIZE = 256.0f;
|
||||
|
||||
@@ -74,21 +74,20 @@ public final class PrintoutRenderer {
|
||||
|
||||
public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours) {
|
||||
var buffer = bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
|
||||
var emitter = FixedWidthFontRenderer.toVertexConsumer(transform, buffer);
|
||||
for (var line = 0; line < LINES_PER_PAGE && line < text.length; line++) {
|
||||
FixedWidthFontRenderer.drawString(emitter,
|
||||
FixedWidthFontRenderer.drawString(
|
||||
transform.last().pose(), buffer,
|
||||
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line],
|
||||
Palette.DEFAULT, light
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, List<PrintoutData.Line> lines) {
|
||||
var buffer = bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
|
||||
var emitter = FixedWidthFontRenderer.toVertexConsumer(transform, buffer);
|
||||
public static void drawText(Matrix4f matrix4f, VertexConsumer buffer, int x, int y, int start, int light, List<PrintoutData.Line> lines) {
|
||||
for (var line = 0; line < LINES_PER_PAGE && line < lines.size(); line++) {
|
||||
var lineContents = lines.get(start + line);
|
||||
FixedWidthFontRenderer.drawString(emitter,
|
||||
FixedWidthFontRenderer.drawString(
|
||||
matrix4f, buffer,
|
||||
x, y + line * FONT_HEIGHT,
|
||||
new TextBuffer(lineContents.text()), new TextBuffer(lineContents.foreground()),
|
||||
Palette.DEFAULT, light
|
||||
@@ -96,13 +95,10 @@ public final class PrintoutRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawBorder(PoseStack transform, MultiBufferSource bufferSource, float x, float y, float z, int page, int pages, boolean isBook, int light) {
|
||||
var matrix = transform.last().pose();
|
||||
public static void drawBorder(Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, int page, int pages, boolean isBook, int light) {
|
||||
var leftPages = page;
|
||||
var rightPages = pages - page - 1;
|
||||
|
||||
var buffer = bufferSource.getBuffer(BACKGROUND);
|
||||
|
||||
if (isBook) {
|
||||
// Border
|
||||
var offset = offsetAt(pages);
|
||||
|
@@ -4,13 +4,12 @@
|
||||
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
|
||||
/**
|
||||
@@ -21,17 +20,15 @@ import org.joml.Matrix4f;
|
||||
* sheet.
|
||||
*/
|
||||
public class SpriteRenderer {
|
||||
public static final ResourceLocation TEXTURE = ResourceLocation.withDefaultNamespace("textures/atlas/gui.png");
|
||||
|
||||
private final Matrix4f transform;
|
||||
private final MultiBufferSource buffers;
|
||||
private final PoseStack transform;
|
||||
private final SubmitNodeCollector submit;
|
||||
private final int light;
|
||||
private final int z;
|
||||
private final int colour;
|
||||
|
||||
public SpriteRenderer(Matrix4f transform, MultiBufferSource buffers, int z, int light, int colour) {
|
||||
public SpriteRenderer(PoseStack transform, SubmitNodeCollector submit, int z, int light, int colour) {
|
||||
this.transform = transform;
|
||||
this.buffers = buffers;
|
||||
this.submit = submit;
|
||||
this.z = z;
|
||||
this.light = light;
|
||||
this.colour = colour;
|
||||
@@ -47,11 +44,12 @@ public class SpriteRenderer {
|
||||
var v0 = sprite.getV((float) spriteY / spriteHeight);
|
||||
var v1 = sprite.getV((float) (spriteY + height) / spriteHeight);
|
||||
|
||||
var vertices = buffers.getBuffer(RenderType.text(sprite.atlasLocation()));
|
||||
vertices.addVertex(transform, x0, y1, z).setColor(colour).setUv(u0, v1).setLight(light);
|
||||
vertices.addVertex(transform, x1, y1, z).setColor(colour).setUv(u1, v1).setLight(light);
|
||||
vertices.addVertex(transform, x1, y0, z).setColor(colour).setUv(u1, v0).setLight(light);
|
||||
vertices.addVertex(transform, x0, y0, z).setColor(colour).setUv(u0, v0).setLight(light);
|
||||
submit.submitCustomGeometry(transform, RenderType.text(sprite.atlasLocation()), (t, vertices) -> {
|
||||
vertices.addVertex(t, x0, y1, z).setColor(colour).setUv(u0, v1).setLight(light);
|
||||
vertices.addVertex(t, x1, y1, z).setColor(colour).setUv(u1, v1).setLight(light);
|
||||
vertices.addVertex(t, x1, y0, z).setColor(colour).setUv(u1, v0).setLight(light);
|
||||
vertices.addVertex(t, x0, y0, z).setColor(colour).setUv(u0, v0).setLight(light);
|
||||
});
|
||||
}
|
||||
|
||||
public void blitTiled(
|
||||
|
@@ -4,9 +4,12 @@
|
||||
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import com.google.errorprone.annotations.concurrent.LazyInit;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.StandaloneModel;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.client.ClientRegistry;
|
||||
import dan200.computercraft.client.turtle.TurtleOverlay;
|
||||
@@ -16,111 +19,147 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.Holiday;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.block.model.ItemTransform;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ARGB;
|
||||
import net.minecraft.util.CommonColors;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity, TurtleBlockEntityRenderer.State> {
|
||||
public static final ResourceLocation NORMAL_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_normal");
|
||||
public static final ResourceLocation ADVANCED_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_advanced");
|
||||
public static final ResourceLocation COLOUR_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
|
||||
|
||||
private final BlockEntityRenderDispatcher renderer;
|
||||
private final Font font;
|
||||
private final ItemModelResolver itemModelResolver;
|
||||
|
||||
public TurtleBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
|
||||
renderer = context.getBlockEntityRenderDispatcher();
|
||||
font = context.getFont();
|
||||
itemModelResolver = context.itemModelResolver();
|
||||
}
|
||||
|
||||
public static final class State extends BlockEntityRenderState {
|
||||
private @Nullable String label;
|
||||
private Vec3 offset = Vec3.ZERO;
|
||||
private int colour;
|
||||
private float yaw;
|
||||
private @LazyInit StandaloneModel model;
|
||||
private @Nullable StandaloneModel overlay;
|
||||
private @Nullable StandaloneModel elfOverlay;
|
||||
|
||||
private float leftAngle;
|
||||
private final ItemStackRenderState leftUpgrade = new ItemStackRenderState();
|
||||
|
||||
private float rightAngle;
|
||||
private final ItemStackRenderState rightUpgrade = new ItemStackRenderState();
|
||||
|
||||
private State() {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, Vec3 camera) {
|
||||
public State createRenderState() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractRenderState(TurtleBlockEntity turtle, State state, float partialTicks, Vec3 camera, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
|
||||
BlockEntityRenderer.super.extractRenderState(turtle, state, partialTicks, camera, crumblingOverlay);
|
||||
|
||||
var modelManager = Minecraft.getInstance().getModelManager();
|
||||
|
||||
var hit = Minecraft.getInstance().hitResult;
|
||||
state.label = hit != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())
|
||||
? turtle.getLabel() : null;
|
||||
state.colour = turtle.getColour();
|
||||
state.offset = turtle.getRenderOffset(partialTicks);
|
||||
state.yaw = turtle.getRenderYaw(partialTicks);
|
||||
|
||||
var modelLocation = state.colour == -1
|
||||
? (turtle.getFamily() == ComputerFamily.NORMAL ? NORMAL_TURTLE_MODEL : ADVANCED_TURTLE_MODEL)
|
||||
: COLOUR_TURTLE_MODEL;
|
||||
state.model = ClientRegistry.getModel(modelManager, modelLocation);
|
||||
|
||||
var overlay = TurtleOverlayManager.get(modelManager, turtle.getOverlay());
|
||||
state.overlay = overlay == null ? null : overlay.model();
|
||||
state.elfOverlay = Holiday.getCurrent() == Holiday.CHRISTMAS && (overlay == null || overlay.showElfOverlay())
|
||||
? ClientRegistry.getModel(modelManager, TurtleOverlay.ELF_MODEL)
|
||||
: null;
|
||||
|
||||
state.leftAngle = turtle.getToolRenderAngle(TurtleSide.LEFT, partialTicks);
|
||||
extractUpgrade(turtle.getAccess(), TurtleSide.LEFT, state.leftUpgrade);
|
||||
|
||||
state.rightAngle = turtle.getToolRenderAngle(TurtleSide.RIGHT, partialTicks);
|
||||
extractUpgrade(turtle.getAccess(), TurtleSide.RIGHT, state.rightUpgrade);
|
||||
}
|
||||
|
||||
private void extractUpgrade(ITurtleAccess turtle, TurtleSide side, ItemStackRenderState state) {
|
||||
state.clear();
|
||||
var upgrade = turtle.getUpgradeWithData(side);
|
||||
if (upgrade == null) return;
|
||||
|
||||
TurtleUpgradeModelManager.get(Minecraft.getInstance().getModelManager(), upgrade.holder())
|
||||
.renderForItem(upgrade, side, state, itemModelResolver, ItemTransform.NO_TRANSFORM, 31);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(State state, PoseStack transform, SubmitNodeCollector collector, CameraRenderState camera) {
|
||||
transform.pushPose();
|
||||
|
||||
// Translate the turtle first, so the label moves with it.
|
||||
var offset = turtle.getRenderOffset(partialTicks);
|
||||
transform.translate(offset.x, offset.y, offset.z);
|
||||
transform.translate(state.offset);
|
||||
|
||||
// Render the label
|
||||
var label = turtle.getLabel();
|
||||
var hit = renderer.cameraHitResult;
|
||||
if (label != null && hit != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())) {
|
||||
var mc = Minecraft.getInstance();
|
||||
var font = this.font;
|
||||
|
||||
transform.pushPose();
|
||||
transform.translate(0.5, 1.2, 0.5);
|
||||
transform.mulPose(mc.getEntityRenderDispatcher().cameraOrientation());
|
||||
transform.scale(0.025f, -0.025f, 0.025f);
|
||||
|
||||
var matrix = transform.last().pose();
|
||||
var opacity = (int) (mc.options.getBackgroundOpacity(0.25f) * 255) << 24;
|
||||
var width = -font.width(label) / 2.0f;
|
||||
font.drawInBatch(label, width, 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
|
||||
font.drawInBatch(label, width, 0, CommonColors.WHITE, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
||||
|
||||
transform.popPose();
|
||||
if (state.label != null) {
|
||||
collector.submitNameTag(
|
||||
transform, new Vec3(0.5, 1.2, 0.5), 0, Component.literal(state.label), false, state.lightCoords,
|
||||
camera.pos.distanceToSqr(Vec3.atCenterOf(state.blockPos)), // TODO: Should we read camera from the render state instead?
|
||||
camera
|
||||
);
|
||||
}
|
||||
|
||||
// Then apply rotation and flip if needed.
|
||||
transform.translate(0.5f, 0.5f, 0.5f);
|
||||
var yaw = turtle.getRenderYaw(partialTicks);
|
||||
transform.mulPose(Axis.YP.rotationDegrees(180.0f - yaw));
|
||||
transform.mulPose(Axis.YP.rotationDegrees(180.0f - state.yaw));
|
||||
transform.translate(-0.5f, -0.5f, -0.5f);
|
||||
|
||||
// Render the turtle
|
||||
var colour = turtle.getColour();
|
||||
var overlay = TurtleOverlayManager.get(Minecraft.getInstance().getModelManager(), turtle.getOverlay());
|
||||
state.model.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY, state.colour == -1 ? null : new int[]{ ARGB.opaque(state.colour) }, state.breakProgress);
|
||||
|
||||
if (colour == -1) {
|
||||
renderModel(transform, buffers, lightmapCoord, overlayLight, turtle.getFamily() == ComputerFamily.NORMAL ? NORMAL_TURTLE_MODEL : ADVANCED_TURTLE_MODEL, null);
|
||||
} else {
|
||||
// Otherwise render it using the colour item.
|
||||
renderModel(transform, buffers, lightmapCoord, overlayLight, COLOUR_TURTLE_MODEL, new int[]{ ARGB.opaque(colour) });
|
||||
if (state.overlay != null) {
|
||||
state.overlay.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY);
|
||||
}
|
||||
if (state.elfOverlay != null) {
|
||||
state.elfOverlay.submit(transform, collector, state.lightCoords, OverlayTexture.NO_OVERLAY);
|
||||
}
|
||||
|
||||
// Render the overlay
|
||||
if (overlay != null) overlay.model().render(transform, buffers, lightmapCoord, overlayLight);
|
||||
|
||||
// And the Christmas overlay.
|
||||
var showChristmas = Holiday.getCurrent() == Holiday.CHRISTMAS && (overlay == null || overlay.showElfOverlay());
|
||||
if (showChristmas) renderModel(transform, buffers, lightmapCoord, overlayLight, TurtleOverlay.ELF_MODEL, null);
|
||||
|
||||
// Render the upgrades
|
||||
renderUpgrade(transform, buffers, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks);
|
||||
renderUpgrade(transform, buffers, lightmapCoord, overlayLight, turtle, TurtleSide.RIGHT, partialTicks);
|
||||
submitUpgrade(transform, collector, state.lightCoords, state.leftAngle, state.leftUpgrade);
|
||||
submitUpgrade(transform, collector, state.lightCoords, state.rightAngle, state.rightUpgrade);
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private void renderUpgrade(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, TurtleBlockEntity turtle, TurtleSide side, float f) {
|
||||
var upgrade = turtle.getAccess().getUpgradeWithData(side);
|
||||
if (upgrade == null) return;
|
||||
private void submitUpgrade(PoseStack transform, SubmitNodeCollector collector, int lightmapCoord, float angle, ItemStackRenderState state) {
|
||||
if (state.isEmpty()) return;
|
||||
transform.pushPose();
|
||||
|
||||
var toolAngle = turtle.getToolRenderAngle(side, f);
|
||||
// Swing the tool
|
||||
transform.translate(0.0f, 0.5f, 0.5f);
|
||||
transform.mulPose(Axis.XN.rotationDegrees(toolAngle));
|
||||
transform.mulPose(Axis.XN.rotationDegrees(angle));
|
||||
transform.translate(0.0f, -0.5f, -0.5f);
|
||||
|
||||
TurtleUpgradeModelManager.get(Minecraft.getInstance().getModelManager(), upgrade.holder())
|
||||
.renderForLevel(upgrade, side, turtle.getAccess(), transform, buffers, lightmapCoord, overlayLight);
|
||||
// Then reposition for rendering the item
|
||||
transform.translate(0.5f, 0.5f, 0.5f);
|
||||
state.submit(transform, collector, lightmapCoord, OverlayTexture.NO_OVERLAY, 0);
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private void renderModel(PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight, ResourceLocation modelLocation, int @Nullable [] tints) {
|
||||
var modelManager = Minecraft.getInstance().getModelManager();
|
||||
ClientRegistry.getModel(modelManager, modelLocation).render(transform, buffers, lightmapCoord, overlayLight, tints);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -4,104 +4,81 @@
|
||||
|
||||
package dan200.computercraft.client.render.monitor;
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import dan200.computercraft.annotations.ForgeOverride;
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.client.integration.ShaderMod;
|
||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderPipelines;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.fog.FogRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector4f;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
|
||||
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity> {
|
||||
public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBlockEntity, MonitorBlockEntityRenderer.State> {
|
||||
/**
|
||||
* {@link MonitorBlockEntity#RENDER_MARGIN}, but a tiny bit of additional padding to ensure that there is no space between
|
||||
* the monitor frame and contents.
|
||||
*/
|
||||
private static final float MARGIN = (float) (MonitorBlockEntity.RENDER_MARGIN * 1.1);
|
||||
|
||||
private static @Nullable ByteBuffer backingBuffer;
|
||||
|
||||
public MonitorBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MonitorBlockEntity monitor, float partialTicks, PoseStack transform, MultiBufferSource bufferSource, int lightmapCoord, int overlayLight, Vec3 camera) {
|
||||
// Render from the origin monitor
|
||||
var originTerminal = monitor.getOriginClientMonitor();
|
||||
if (originTerminal == null) return;
|
||||
public State createRenderState() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
var origin = originTerminal.getOrigin();
|
||||
var renderState = originTerminal.getRenderState(MonitorRenderState::new);
|
||||
var monitorPos = monitor.getBlockPos();
|
||||
@Override
|
||||
public void extractRenderState(MonitorBlockEntity monitor, State state, float f, Vec3 camera, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) {
|
||||
BlockEntityRenderer.super.extractRenderState(monitor, state, f, camera, crumblingOverlay);
|
||||
|
||||
// Ensure each monitor terminal is rendered only once. We allow rendering a specific tile
|
||||
// multiple times in a single frame to ensure compatibility with shaders which may run a
|
||||
// pass multiple times.
|
||||
var renderFrame = FrameInfo.getRenderFrame();
|
||||
if (renderState.lastRenderFrame == renderFrame && !monitorPos.equals(renderState.lastRenderPos)) {
|
||||
return;
|
||||
}
|
||||
state.direction = monitor.getDirection();
|
||||
state.front = monitor.getFront();
|
||||
state.width = monitor.getWidth();
|
||||
state.height = monitor.getHeight();
|
||||
state.terminal = monitor.getOriginClientMonitor();
|
||||
}
|
||||
|
||||
renderState.lastRenderFrame = renderFrame;
|
||||
renderState.lastRenderPos = monitorPos;
|
||||
|
||||
var originPos = origin.getBlockPos();
|
||||
@Override
|
||||
public void submit(State state, PoseStack transform, SubmitNodeCollector collector, CameraRenderState camera) {
|
||||
if (state.terminal == null) return;
|
||||
|
||||
// Determine orientation
|
||||
var dir = origin.getDirection();
|
||||
var front = origin.getFront();
|
||||
var dir = state.direction;
|
||||
var front = state.front;
|
||||
var yaw = dir.toYRot();
|
||||
var pitch = DirectionUtil.toPitchAngle(front);
|
||||
|
||||
// Setup initial transform
|
||||
transform.pushPose();
|
||||
transform.translate(
|
||||
originPos.getX() - monitorPos.getX() + 0.5,
|
||||
originPos.getY() - monitorPos.getY() + 0.5,
|
||||
originPos.getZ() - monitorPos.getZ() + 0.5
|
||||
);
|
||||
transform.translate(0.5, 0.5, 0.5);
|
||||
|
||||
transform.mulPose(Axis.YN.rotationDegrees(yaw));
|
||||
transform.mulPose(Axis.XP.rotationDegrees(pitch));
|
||||
transform.translate(
|
||||
-0.5 + MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN,
|
||||
origin.getHeight() - 0.5 - (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN) + 0,
|
||||
state.height - 0.5 - (MonitorBlockEntity.RENDER_BORDER + MonitorBlockEntity.RENDER_MARGIN) + 0,
|
||||
0.5
|
||||
);
|
||||
var xSize = origin.getWidth() - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
||||
var ySize = origin.getHeight() - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
||||
var xSize = state.width - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
||||
var ySize = state.height - 2.0 * (MonitorBlockEntity.RENDER_MARGIN + MonitorBlockEntity.RENDER_BORDER);
|
||||
|
||||
// Draw the contents
|
||||
var terminal = originTerminal.getTerminal();
|
||||
if (terminal != null && !ShaderMod.get().isRenderingShadowPass()) {
|
||||
var terminal = state.terminal.getTerminal();
|
||||
if (terminal != null) {
|
||||
// Draw a terminal
|
||||
int width = terminal.getWidth(), height = terminal.getHeight();
|
||||
int pixelWidth = width * FONT_WIDTH, pixelHeight = height * FONT_HEIGHT;
|
||||
@@ -110,158 +87,25 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
transform.pushPose();
|
||||
transform.scale((float) xScale, (float) -yScale, 1.0f);
|
||||
|
||||
var matrix = transform.last().pose();
|
||||
var xMargin = (float) (MARGIN / xScale);
|
||||
var yMargin = (float) (MARGIN / yScale);
|
||||
|
||||
renderTerminal(matrix, originTerminal, renderState, terminal, (float) (MARGIN / xScale), (float) (MARGIN / yScale));
|
||||
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> {
|
||||
FixedWidthFontRenderer.drawTerminalBackground(pose.pose(), buffer, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin);
|
||||
});
|
||||
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, (pose, buffer) -> {
|
||||
FixedWidthFontRenderer.drawTerminalForeground(pose.pose(), buffer, 0, 0, terminal);
|
||||
FixedWidthFontRenderer.drawCursor(pose.pose(), buffer, 0, 0, terminal);
|
||||
});
|
||||
|
||||
transform.popPose();
|
||||
} else {
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(
|
||||
FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT)),
|
||||
-MARGIN, MARGIN,
|
||||
(float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)
|
||||
);
|
||||
FixedWidthFontRenderer.drawEmptyTerminal(transform, collector, -MARGIN, MARGIN, (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2));
|
||||
}
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private static void renderTerminal(
|
||||
Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
|
||||
) {
|
||||
var redraw = monitor.pollTerminalChanged();
|
||||
if (renderState.vertexBuffer == null) redraw = true;
|
||||
|
||||
if (redraw) {
|
||||
// Cursor, Foreground, Background+Margin
|
||||
var maxQuadCount = 1 + (terminal.getWidth() * terminal.getHeight()) + ((terminal.getWidth() + 2) * (terminal.getHeight() + 2));
|
||||
var maxVertexCount = 4 * maxQuadCount;
|
||||
var sink = ShaderMod.get().getQuadEmitter(maxQuadCount, MonitorBlockEntityRenderer::getBuffer);
|
||||
|
||||
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin);
|
||||
var vertexCountAfterBackground = sink.vertexCount();
|
||||
|
||||
DirectFixedWidthFontRenderer.drawTerminalForeground(sink, 0, 0, terminal);
|
||||
var vertexCountAfterForeground = sink.vertexCount();
|
||||
|
||||
DirectFixedWidthFontRenderer.drawCursor(sink, 0, 0, terminal);
|
||||
var vertexCountAfterCursor = sink.vertexCount();
|
||||
|
||||
if (vertexCountAfterCursor > maxVertexCount) {
|
||||
throw new IllegalStateException("Drew too many vertices. Expected " + maxVertexCount + ", drew " + vertexCountAfterCursor);
|
||||
}
|
||||
|
||||
if (vertexCountAfterCursor != 0) {
|
||||
renderState.register();
|
||||
|
||||
var commandEncoder = RenderSystem.getDevice().createCommandEncoder();
|
||||
|
||||
var resultBuffer = sink.byteBuffer().flip();
|
||||
|
||||
// Ensure our buffer contains the correct number of vertices.
|
||||
if (resultBuffer.remaining() != sink.format().getVertexSize() * vertexCountAfterCursor) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Mismatched vertex count. Buffer is %d bytes long, but was expected to be %d (vertex size) * %d (vertex count) = %d bytes.",
|
||||
resultBuffer.limit(), sink.format().getVertexSize(), vertexCountAfterCursor, sink.format().getVertexSize() * vertexCountAfterCursor
|
||||
));
|
||||
}
|
||||
|
||||
// Upload the buffer, reallocating if required.
|
||||
if (renderState.vertexBuffer == null || resultBuffer.remaining() > renderState.vertexBuffer.size()) {
|
||||
if (renderState.vertexBuffer != null) {
|
||||
renderState.vertexBuffer.close();
|
||||
renderState.vertexBuffer = null;
|
||||
}
|
||||
renderState.vertexBuffer = RenderSystem.getDevice().createBuffer(
|
||||
() -> "Monitor at " + monitor.getOrigin().getBlockPos(), GpuBuffer.USAGE_VERTEX | GpuBuffer.USAGE_COPY_DST, resultBuffer
|
||||
);
|
||||
} else if (!renderState.vertexBuffer.isClosed()) {
|
||||
commandEncoder.writeToBuffer(renderState.vertexBuffer.slice(), resultBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
renderState.vertexCountAfterBackground = vertexCountAfterBackground;
|
||||
renderState.vertexCountAfterForeground = vertexCountAfterForeground;
|
||||
renderState.vertexCountAfterCursor = vertexCountAfterCursor;
|
||||
}
|
||||
|
||||
if (renderState.vertexCountAfterCursor == 0) return;
|
||||
|
||||
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
|
||||
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
|
||||
// normal render distance (~200), and the edges of the monitor fade out due to fog.
|
||||
// There's not really a good way around this, at least without using a custom render type (which the VBO
|
||||
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
|
||||
// absurdly high value.
|
||||
var oldFog = RenderSystem.getShaderFog();
|
||||
RenderSystem.setShaderFog(Minecraft.getInstance().gameRenderer.fogRenderer.getBuffer(FogRenderer.FogMode.NONE));
|
||||
|
||||
// Compose the existing model view matrix with our transformation matrix.
|
||||
RenderSystem.getModelViewStack().pushMatrix();
|
||||
RenderSystem.getModelViewStack().mul(matrix);
|
||||
|
||||
// Render background geometry
|
||||
drawWithShader(renderState, FixedWidthFontRenderer.TERMINAL_TEXT, RenderPipelines.TEXT, 0, renderState.vertexCountAfterBackground);
|
||||
drawWithShader(
|
||||
renderState, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, RenderPipelines.TEXT_POLYGON_OFFSET, renderState.vertexCountAfterBackground,
|
||||
(
|
||||
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
|
||||
? renderState.vertexCountAfterCursor : renderState.vertexCountAfterForeground
|
||||
) - renderState.vertexCountAfterBackground
|
||||
);
|
||||
|
||||
// Clear state
|
||||
RenderSystem.getModelViewStack().popMatrix();
|
||||
RenderSystem.setShaderFog(oldFog);
|
||||
}
|
||||
|
||||
private static void drawWithShader(MonitorRenderState renderState, RenderType renderType, RenderPipeline pipeline, int vertexOffset, int vertexCount) {
|
||||
if (renderState.vertexBuffer == null) {
|
||||
throw new IllegalStateException("MonitorRenderState has not been initialised");
|
||||
}
|
||||
if (vertexCount == 0) return;
|
||||
|
||||
var transforms = RenderSystem.getDynamicUniforms().writeTransform(
|
||||
RenderSystem.getModelViewMatrix(),
|
||||
new Vector4f(1.0F, 1.0F, 1.0F, 1.0F),
|
||||
RenderSystem.getModelOffset(),
|
||||
RenderSystem.getTextureMatrix(),
|
||||
RenderSystem.getShaderLineWidth()
|
||||
);
|
||||
|
||||
renderType.setupRenderState();
|
||||
|
||||
var autoStorageBuffer = RenderSystem.getSequentialBuffer(renderType.mode());
|
||||
var indexCount = FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(vertexCount);
|
||||
var indexBuffer = autoStorageBuffer.getBuffer(indexCount);
|
||||
|
||||
var target = Minecraft.getInstance().getMainRenderTarget();
|
||||
var colourTarget = RenderSystem.outputColorTextureOverride != null ? RenderSystem.outputColorTextureOverride : target.getColorTextureView();
|
||||
var depthTarget = target.useDepth
|
||||
? (RenderSystem.outputDepthTextureOverride != null ? RenderSystem.outputDepthTextureOverride : target.getDepthTextureView())
|
||||
: null;
|
||||
|
||||
try (var renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
|
||||
() -> "Monitor", colourTarget, OptionalInt.empty(), depthTarget, OptionalDouble.empty()
|
||||
)) {
|
||||
renderPass.setPipeline(pipeline);
|
||||
|
||||
RenderSystem.bindDefaultUniforms(renderPass);
|
||||
renderPass.setUniform("DynamicTransforms", transforms);
|
||||
renderPass.setVertexBuffer(0, renderState.vertexBuffer);
|
||||
renderPass.setIndexBuffer(indexBuffer, autoStorageBuffer.type());
|
||||
|
||||
for (var j = 0; j < 12; j++) {
|
||||
var gpuTexture = RenderSystem.getShaderTexture(j);
|
||||
if (gpuTexture != null) renderPass.bindSampler("Sampler" + j, gpuTexture);
|
||||
}
|
||||
|
||||
renderPass.drawIndexed(vertexOffset, 0, indexCount, 1);
|
||||
}
|
||||
|
||||
renderType.clearRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewDistance() {
|
||||
return Config.monitorDistance;
|
||||
@@ -272,13 +116,19 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
return monitor.getRenderBoundingBox();
|
||||
}
|
||||
|
||||
private static ByteBuffer getBuffer(int capacity) {
|
||||
var buffer = backingBuffer;
|
||||
if (buffer == null || buffer.capacity() < capacity) {
|
||||
buffer = backingBuffer = buffer == null ? MemoryUtil.memAlloc(capacity) : MemoryUtil.memRealloc(buffer, capacity);
|
||||
}
|
||||
@Override
|
||||
public boolean shouldRender(MonitorBlockEntity monitor, Vec3 camera) {
|
||||
return BlockEntityRenderer.super.shouldRender(monitor, camera) && monitor.getXIndex() == 0 && monitor.getYIndex() == 0;
|
||||
}
|
||||
|
||||
buffer.clear();
|
||||
return buffer;
|
||||
public static final class State extends BlockEntityRenderState {
|
||||
private Direction direction = Direction.NORTH;
|
||||
private Direction front = Direction.NORTH;
|
||||
private int width;
|
||||
private int height;
|
||||
private @Nullable ClientMonitor terminal;
|
||||
|
||||
private State() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ARGB;
|
||||
import org.joml.Matrix4f;
|
||||
@@ -67,7 +68,7 @@ public final class FixedWidthFontRenderer {
|
||||
return 15 - Terminal.getColour(c, def);
|
||||
}
|
||||
|
||||
private static void drawChar(QuadEmitter emitter, float x, float y, int index, int colour, int light) {
|
||||
private static void drawChar(Matrix4f matrix, VertexConsumer buffer, float x, float y, int index, int colour, int light) {
|
||||
// Short circuit to avoid the common case - the texture should be blank here after all.
|
||||
if (index == '\0' || index == ' ') return;
|
||||
|
||||
@@ -78,30 +79,30 @@ public final class FixedWidthFontRenderer {
|
||||
var yStart = 1 + row * (FONT_HEIGHT + 2);
|
||||
|
||||
quad(
|
||||
emitter, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, 0, colour,
|
||||
matrix, buffer, x, y, x + FONT_WIDTH, y + FONT_HEIGHT, 0, colour,
|
||||
xStart / WIDTH, yStart / WIDTH, (xStart + FONT_WIDTH) / WIDTH, (yStart + FONT_HEIGHT) / WIDTH, light
|
||||
);
|
||||
}
|
||||
|
||||
public static void drawQuad(QuadEmitter emitter, float x, float y, float z, float width, float height, int colour, int light) {
|
||||
quad(emitter, x, y, x + width, y + height, z, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, light);
|
||||
public static void drawQuad(Matrix4f matrix, VertexConsumer buffer, float x, float y, float z, float width, float height, int colour, int light) {
|
||||
quad(matrix, buffer, x, y, x + width, y + height, z, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, light);
|
||||
}
|
||||
|
||||
private static void drawQuad(QuadEmitter emitter, float x, float y, float width, float height, Palette palette, char colourIndex, int light) {
|
||||
private static void drawQuad(Matrix4f matrix, VertexConsumer buffer, float x, float y, float width, float height, Palette palette, char colourIndex, int light) {
|
||||
var colour = palette.getRenderColours(getColour(colourIndex, Colour.BLACK));
|
||||
drawQuad(emitter, x, y, 0, width, height, colour, light);
|
||||
drawQuad(matrix, buffer, x, y, 0, width, height, colour, light);
|
||||
}
|
||||
|
||||
private static void drawBackground(
|
||||
QuadEmitter emitter, float x, float y, TextBuffer backgroundColour, Palette palette,
|
||||
Matrix4f matrix, VertexConsumer buffer, float x, float y, TextBuffer backgroundColour, Palette palette,
|
||||
float leftMarginSize, float rightMarginSize, float height, int light
|
||||
) {
|
||||
if (leftMarginSize > 0) {
|
||||
drawQuad(emitter, x - leftMarginSize, y, leftMarginSize, height, palette, backgroundColour.charAt(0), light);
|
||||
drawQuad(matrix, buffer, x - leftMarginSize, y, leftMarginSize, height, palette, backgroundColour.charAt(0), light);
|
||||
}
|
||||
|
||||
if (rightMarginSize > 0) {
|
||||
drawQuad(emitter, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, backgroundColour.charAt(backgroundColour.length() - 1), light);
|
||||
drawQuad(matrix, buffer, x + backgroundColour.length() * FONT_WIDTH, y, rightMarginSize, height, palette, backgroundColour.charAt(backgroundColour.length() - 1), light);
|
||||
}
|
||||
|
||||
// Batch together runs of identical background cells.
|
||||
@@ -112,7 +113,7 @@ public final class FixedWidthFontRenderer {
|
||||
if (colourIndex == blockColour) continue;
|
||||
|
||||
if (blockColour != '\0') {
|
||||
drawQuad(emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, blockColour, light);
|
||||
drawQuad(matrix, buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (i - blockStart), height, palette, blockColour, light);
|
||||
}
|
||||
|
||||
blockColour = colourIndex;
|
||||
@@ -120,22 +121,22 @@ public final class FixedWidthFontRenderer {
|
||||
}
|
||||
|
||||
if (blockColour != '\0') {
|
||||
drawQuad(emitter, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, blockColour, light);
|
||||
drawQuad(matrix, buffer, x + blockStart * FONT_WIDTH, y, FONT_WIDTH * (backgroundColour.length() - blockStart), height, palette, blockColour, light);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawString(QuadEmitter emitter, float x, float y, TextBuffer text, TextBuffer textColour, Palette palette, int light) {
|
||||
public static void drawString(Matrix4f matrix, VertexConsumer buffer, float x, float y, TextBuffer text, TextBuffer textColour, Palette palette, int light) {
|
||||
for (var i = 0; i < text.length(); i++) {
|
||||
var colour = palette.getRenderColours(getColour(textColour.charAt(i), Colour.BLACK));
|
||||
|
||||
int index = text.charAt(i);
|
||||
if (index > 255) index = '?';
|
||||
drawChar(emitter, x + i * FONT_WIDTH, y, index, colour, light);
|
||||
drawChar(matrix, buffer, x + i * FONT_WIDTH, y, index, colour, light);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void drawTerminalForeground(QuadEmitter emitter, float x, float y, Terminal terminal) {
|
||||
public static void drawTerminalForeground(Matrix4f matrix, VertexConsumer buffer, float x, float y, Terminal terminal) {
|
||||
var palette = terminal.getPalette();
|
||||
var height = terminal.getHeight();
|
||||
|
||||
@@ -143,14 +144,14 @@ public final class FixedWidthFontRenderer {
|
||||
for (var i = 0; i < height; i++) {
|
||||
var rowY = y + FONT_HEIGHT * i;
|
||||
drawString(
|
||||
emitter, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i),
|
||||
matrix, buffer, x, rowY, terminal.getLine(i), terminal.getTextColourLine(i),
|
||||
palette, LightTexture.FULL_BRIGHT
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawTerminalBackground(
|
||||
QuadEmitter emitter, float x, float y, Terminal terminal,
|
||||
Matrix4f matrix, VertexConsumer buffer, float x, float y, Terminal terminal,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
) {
|
||||
var palette = terminal.getPalette();
|
||||
@@ -158,12 +159,12 @@ public final class FixedWidthFontRenderer {
|
||||
|
||||
// Top and bottom margins
|
||||
drawBackground(
|
||||
emitter, x, y - topMarginSize, terminal.getBackgroundColourLine(0), palette,
|
||||
matrix, buffer, x, y - topMarginSize, terminal.getBackgroundColourLine(0), palette,
|
||||
leftMarginSize, rightMarginSize, topMarginSize, LightTexture.FULL_BRIGHT
|
||||
);
|
||||
|
||||
drawBackground(
|
||||
emitter, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine(height - 1), palette,
|
||||
matrix, buffer, x, y + height * FONT_HEIGHT, terminal.getBackgroundColourLine(height - 1), palette,
|
||||
leftMarginSize, rightMarginSize, bottomMarginSize, LightTexture.FULL_BRIGHT
|
||||
);
|
||||
|
||||
@@ -171,7 +172,7 @@ public final class FixedWidthFontRenderer {
|
||||
for (var i = 0; i < height; i++) {
|
||||
var rowY = y + FONT_HEIGHT * i;
|
||||
drawBackground(
|
||||
emitter, x, rowY, terminal.getBackgroundColourLine(i), palette,
|
||||
matrix, buffer, x, rowY, terminal.getBackgroundColourLine(i), palette,
|
||||
leftMarginSize, rightMarginSize, FONT_HEIGHT, LightTexture.FULL_BRIGHT
|
||||
);
|
||||
}
|
||||
@@ -185,52 +186,40 @@ public final class FixedWidthFontRenderer {
|
||||
return cursorX >= 0 && cursorX < terminal.getWidth() && cursorY >= 0 && cursorY < terminal.getHeight();
|
||||
}
|
||||
|
||||
public static void drawCursor(QuadEmitter emitter, float x, float y, Terminal terminal) {
|
||||
public static void drawCursor(Matrix4f matrix, VertexConsumer buffer, float x, float y, Terminal terminal) {
|
||||
if (isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()) {
|
||||
var colour = terminal.getPalette().getRenderColours(15 - terminal.getTextColour());
|
||||
drawChar(emitter, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, LightTexture.FULL_BRIGHT);
|
||||
drawChar(matrix, buffer, x + terminal.getCursorX() * FONT_WIDTH, y + terminal.getCursorY() * FONT_HEIGHT, '_', colour, LightTexture.FULL_BRIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
public static void drawTerminal(
|
||||
QuadEmitter emitter, float x, float y, Terminal terminal,
|
||||
Matrix4f matrix, VertexConsumer buffer, float x, float y, Terminal terminal,
|
||||
float topMarginSize, float bottomMarginSize, float leftMarginSize, float rightMarginSize
|
||||
) {
|
||||
drawTerminalBackground(
|
||||
emitter, x, y, terminal,
|
||||
matrix, buffer, x, y, terminal,
|
||||
topMarginSize, bottomMarginSize, leftMarginSize, rightMarginSize
|
||||
);
|
||||
|
||||
// Render the foreground with a slight offset. By calling .translate() on the matrix itself, we're translating
|
||||
// in screen space, rather than in model/view space.
|
||||
// It's definitely not perfect, but better than z fighting!
|
||||
var transformBackup = new Matrix4f(emitter.poseMatrix());
|
||||
emitter.poseMatrix().translate(new Vector3f(0, 0, Z_OFFSET));
|
||||
var offsetMatrix = new Matrix4f(matrix).translate(new Vector3f(0, 0, Z_OFFSET));
|
||||
|
||||
drawTerminalForeground(emitter, x, y, terminal);
|
||||
drawCursor(emitter, x, y, terminal);
|
||||
|
||||
emitter.poseMatrix().set(transformBackup);
|
||||
drawTerminalForeground(offsetMatrix, buffer, x, y, terminal);
|
||||
drawCursor(offsetMatrix, buffer, x, y, terminal);
|
||||
}
|
||||
|
||||
public static void drawEmptyTerminal(QuadEmitter emitter, float x, float y, float width, float height) {
|
||||
drawQuad(emitter, x, y, 0, width, height, BLACK, LightTexture.FULL_BRIGHT);
|
||||
public static void drawEmptyTerminal(PoseStack transform, SubmitNodeCollector collector, float x, float y, float width, float height) {
|
||||
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) ->
|
||||
drawQuad(pose.pose(), buffer, x, y, 0, width, height, BLACK, LightTexture.FULL_BRIGHT));
|
||||
}
|
||||
|
||||
public record QuadEmitter(Matrix4f poseMatrix, VertexConsumer consumer) {
|
||||
}
|
||||
|
||||
public static QuadEmitter toVertexConsumer(PoseStack transform, VertexConsumer consumer) {
|
||||
return new QuadEmitter(transform.last().pose(), consumer);
|
||||
}
|
||||
|
||||
private static void quad(QuadEmitter c, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2, int light) {
|
||||
var poseMatrix = c.poseMatrix();
|
||||
var consumer = c.consumer();
|
||||
|
||||
consumer.addVertex(poseMatrix, x1, y1, z).setColor(colour).setUv(u1, v1).setLight(light);
|
||||
consumer.addVertex(poseMatrix, x1, y2, z).setColor(colour).setUv(u1, v2).setLight(light);
|
||||
consumer.addVertex(poseMatrix, x2, y2, z).setColor(colour).setUv(u2, v2).setLight(light);
|
||||
consumer.addVertex(poseMatrix, x2, y1, z).setColor(colour).setUv(u2, v1).setLight(light);
|
||||
private static void quad(Matrix4f matrix, VertexConsumer buffer, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2, int light) {
|
||||
buffer.addVertex(matrix, x1, y1, z).setColor(colour).setUv(u1, v1).setLight(light);
|
||||
buffer.addVertex(matrix, x1, y2, z).setColor(colour).setUv(u1, v2).setLight(light);
|
||||
buffer.addVertex(matrix, x2, y2, z).setColor(colour).setUv(u2, v2).setLight(light);
|
||||
buffer.addVertex(matrix, x2, y1, z).setColor(colour).setUv(u2, v1).setLight(light);
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.client.gui.GuiSprites;
|
||||
import dan200.computercraft.client.model.LecternPocketModel;
|
||||
import dan200.computercraft.client.model.LecternPrintoutModel;
|
||||
import dan200.computercraft.client.model.LecternPrintoutModelDefinitions;
|
||||
import dan200.computercraft.client.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.data.client.BlockModelProvider;
|
||||
import dan200.computercraft.data.client.ItemModelProvider;
|
||||
@@ -21,9 +21,9 @@ import net.minecraft.client.data.models.ItemModelGenerators;
|
||||
import net.minecraft.client.renderer.texture.atlas.SpriteSource;
|
||||
import net.minecraft.client.renderer.texture.atlas.SpriteSources;
|
||||
import net.minecraft.client.renderer.texture.atlas.sources.SingleFile;
|
||||
import net.minecraft.client.resources.model.AtlasIds;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.RegistrySetBuilder;
|
||||
import net.minecraft.data.AtlasIds;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.registries.RegistryPatchGenerator;
|
||||
@@ -71,9 +71,9 @@ public final class DataProviders {
|
||||
|
||||
generator.addFromCodec("Block atlases", PackOutput.Target.RESOURCE_PACK, "atlases", SpriteSources.FILE_CODEC, out -> {
|
||||
out.accept(AtlasIds.BLOCKS, makeSprites(Stream.of(
|
||||
LecternPrintoutModel.TEXTURE,
|
||||
LecternPocketModel.TEXTURE_NORMAL, LecternPocketModel.TEXTURE_ADVANCED,
|
||||
LecternPocketModel.TEXTURE_COLOUR, LecternPocketModel.TEXTURE_FRAME, LecternPocketModel.TEXTURE_LIGHT
|
||||
LecternPrintoutModelDefinitions.MATERIAL.texture(),
|
||||
LecternPocketModel.MATERIAL_NORMAL.texture(), LecternPocketModel.MATERIAL_ADVANCED.texture(),
|
||||
LecternPocketModel.MATERIAL_COLOUR.texture(), LecternPocketModel.MATERIAL_FRAME.texture(), LecternPocketModel.MATERIAL_LIGHT.texture()
|
||||
)));
|
||||
|
||||
out.accept(AtlasIds.GUI, makeSprites(
|
||||
|
@@ -23,6 +23,7 @@ import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer;
|
||||
import net.minecraft.world.level.storage.loot.functions.CopyComponentsFunction;
|
||||
import net.minecraft.world.level.storage.loot.functions.CopyNameFunction;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||
import net.minecraft.world.level.storage.loot.predicates.AnyOfCondition;
|
||||
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition;
|
||||
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition;
|
||||
@@ -92,7 +93,7 @@ class LootTableProvider {
|
||||
private static void namedBlockDrop(BiConsumer<ResourceKey<LootTable>, LootTable.Builder> add, Supplier<? extends Block> wrapper) {
|
||||
blockDrop(
|
||||
add, wrapper,
|
||||
LootItem.lootTableItem(wrapper.get()).apply(CopyNameFunction.copyName(CopyNameFunction.NameSource.BLOCK_ENTITY)),
|
||||
LootItem.lootTableItem(wrapper.get()).apply(CopyNameFunction.copyName(new CopyNameFunction.Source(LootContextParams.BLOCK_ENTITY))),
|
||||
ExplosionCondition.survivesExplosion()
|
||||
);
|
||||
}
|
||||
@@ -100,7 +101,7 @@ class LootTableProvider {
|
||||
private static void computerDrop(BiConsumer<ResourceKey<LootTable>, LootTable.Builder> add, Supplier<? extends Block> block) {
|
||||
blockDrop(
|
||||
add, block,
|
||||
LootItem.lootTableItem(block.get()).apply(CopyComponentsFunction.copyComponents(CopyComponentsFunction.Source.BLOCK_ENTITY)),
|
||||
LootItem.lootTableItem(block.get()).apply(CopyComponentsFunction.copyComponentsFromBlockEntity(LootContextParams.BLOCK_ENTITY)),
|
||||
AnyOfCondition.anyOf(
|
||||
BlockNamedEntityLootCondition.BUILDER,
|
||||
HasComputerIdLootCondition.BUILDER,
|
||||
|
@@ -447,7 +447,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
}
|
||||
|
||||
private static ItemStack playerHead(String name, String uuid) {
|
||||
return DataComponentUtil.createStack(Items.PLAYER_HEAD, DataComponents.PROFILE, new ResolvableProfile(new GameProfile(UUID.fromString(uuid), name)));
|
||||
return DataComponentUtil.createStack(Items.PLAYER_HEAD, DataComponents.PROFILE, ResolvableProfile.createResolved(new GameProfile(UUID.fromString(uuid), name)));
|
||||
}
|
||||
|
||||
private ShapedSpecBuilder customShaped(RecipeCategory category, ItemStack result) {
|
||||
|
@@ -50,14 +50,20 @@ public enum UserLevel implements Predicate<CommandSourceStack> {
|
||||
|
||||
public static boolean isOwner(CommandSourceStack source) {
|
||||
var server = source.getServer();
|
||||
|
||||
// While CommandSourceStack.getServer is non-nullable, that's a lie for permission checks. When loading
|
||||
// .mcfunction files, ServerFunctionLibrary constructs an instance with an empty server. In that case, return
|
||||
// false — we don't want to treat functions as an owner!
|
||||
if (server == null) return false;
|
||||
|
||||
var player = source.getPlayer();
|
||||
return server.isDedicatedServer()
|
||||
? source.getEntity() == null && source.hasPermission(4) && source.getTextName().equals("Server")
|
||||
: player != null && server.isSingleplayerOwner(player.getGameProfile());
|
||||
: player != null && server.isSingleplayerOwner(player.nameAndId());
|
||||
}
|
||||
|
||||
public static boolean isOwner(ServerPlayer player) {
|
||||
var server = player.getServer();
|
||||
return server != null && server.isSingleplayerOwner(player.getGameProfile());
|
||||
var server = player.level().getServer();
|
||||
return server != null && server.isSingleplayerOwner(player.nameAndId());
|
||||
}
|
||||
}
|
||||
|
@@ -50,7 +50,7 @@ public abstract class HorizontalContainerBlock extends BaseEntityBlock {
|
||||
|
||||
@Override
|
||||
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
||||
if (level.isClientSide) return InteractionResult.SUCCESS;
|
||||
if (level.isClientSide()) return InteractionResult.SUCCESS;
|
||||
|
||||
if (level.getBlockEntity(pos) instanceof BaseContainerBlockEntity container) {
|
||||
player.openMenu(container);
|
||||
@@ -65,7 +65,7 @@ public abstract class HorizontalContainerBlock extends BaseEntityBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos pPos) {
|
||||
protected final int getAnalogOutputSignal(BlockState pBlockState, Level pLevel, BlockPos pPos, Direction direction) {
|
||||
return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(pLevel.getBlockEntity(pPos));
|
||||
}
|
||||
|
||||
|
@@ -112,7 +112,7 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
||||
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
||||
if (!player.isCrouching() && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
||||
// Regular right click to activate computer
|
||||
if (!level.isClientSide && computer.isUsable(player)) {
|
||||
if (!level.isClientSide() && computer.isUsable(player)) {
|
||||
var serverComputer = computer.createServerComputer();
|
||||
serverComputer.turnOn();
|
||||
|
||||
@@ -143,7 +143,7 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
||||
@Override
|
||||
@Nullable
|
||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, this.type.get(), serverTicker);
|
||||
return level.isClientSide() ? null : BlockEntityHelpers.createTickerHelper(type, this.type.get(), serverTicker);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@@ -67,7 +67,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
}
|
||||
|
||||
protected void unload() {
|
||||
if (getLevel().isClientSide) return;
|
||||
if (getLevel().isClientSide()) return;
|
||||
|
||||
var computer = getServerComputer();
|
||||
if (computer != null) computer.close();
|
||||
@@ -91,7 +91,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
}
|
||||
|
||||
protected void serverTick() {
|
||||
if (getLevel().isClientSide) return;
|
||||
if (getLevel().isClientSide()) return;
|
||||
if (computerID < 0 && !startOn) return; // Don't tick if we don't need a computer!
|
||||
|
||||
var computer = createServerComputer();
|
||||
@@ -157,7 +157,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
@Override
|
||||
public final void loadAdditional(ValueInput nbt) {
|
||||
super.loadAdditional(nbt);
|
||||
if (level != null && level.isClientSide) {
|
||||
if (level != null && level.isClientSide()) {
|
||||
loadClient(nbt);
|
||||
} else {
|
||||
loadServer(nbt);
|
||||
@@ -340,14 +340,14 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
}
|
||||
|
||||
public final void setComputerID(int id) {
|
||||
if (getLevel().isClientSide || computerID == id) return;
|
||||
if (getLevel().isClientSide() || computerID == id) return;
|
||||
|
||||
computerID = id;
|
||||
BlockEntityHelpers.updateBlock(this);
|
||||
}
|
||||
|
||||
public final void setLabel(@Nullable String label) {
|
||||
if (getLevel().isClientSide || Objects.equals(this.label, label)) return;
|
||||
if (getLevel().isClientSide() || Objects.equals(this.label, label)) return;
|
||||
|
||||
this.label = label;
|
||||
var computer = getServerComputer();
|
||||
@@ -386,7 +386,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
|
||||
@Nullable
|
||||
public ServerComputer getServerComputer() {
|
||||
return getLevel().isClientSide || getLevel().getServer() == null ? null : ServerContext.get(getLevel().getServer()).registry().get(instanceID);
|
||||
return getLevel().isClientSide() || getLevel().getServer() == null ? null : ServerContext.get(getLevel().getServer()).registry().get(instanceID);
|
||||
}
|
||||
|
||||
// Networking stuff
|
||||
|
@@ -45,7 +45,7 @@ public enum ComputerFamily {
|
||||
}
|
||||
|
||||
private static boolean checkCommandUsable(Player player) {
|
||||
var server = player.getServer();
|
||||
var server = player.level().getServer();
|
||||
if (server == null || !server.isCommandBlockEnabled()) {
|
||||
player.displayClientMessage(Component.translatable("advMode.notEnabled"), true);
|
||||
return false;
|
||||
|
@@ -5,11 +5,14 @@
|
||||
package dan200.computercraft.shared.container;
|
||||
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.ContainerUser;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -69,12 +72,12 @@ public interface InventoryDelegate extends Container {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void startOpen(Player player) {
|
||||
default void startOpen(ContainerUser player) {
|
||||
getInventory().startOpen(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void stopOpen(Player player) {
|
||||
default void stopOpen(ContainerUser player) {
|
||||
getInventory().stopOpen(player);
|
||||
}
|
||||
|
||||
@@ -102,4 +105,24 @@ public interface InventoryDelegate extends Container {
|
||||
default boolean hasAnyMatching(Predicate<ItemStack> predicate) {
|
||||
return getInventory().hasAnyMatching(predicate);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getMaxStackSize(ItemStack stack) {
|
||||
return getInventory().getMaxStackSize(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<ContainerUser> getEntitiesWithContainerOpen() {
|
||||
return getInventory().getEntitiesWithContainerOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean canTakeItem(Container target, int slot, ItemStack stack) {
|
||||
return getInventory().canTakeItem(target, slot, stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
default Iterator<ItemStack> iterator() {
|
||||
return getInventory().iterator();
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.stats.Stats;
|
||||
import net.minecraft.util.RandomSource;
|
||||
@@ -55,7 +56,7 @@ public class CustomLecternBlock extends LecternBlock {
|
||||
*/
|
||||
public static InteractionResult tryPlaceItem(Player player, Level level, BlockPos pos, BlockState blockState, ItemStack item) {
|
||||
if (item.getItem() instanceof PrintoutItem || item.getItem() instanceof PocketComputerItem) {
|
||||
if (!level.isClientSide) replaceLectern(player, level, pos, blockState, item);
|
||||
if (!level.isClientSide()) replaceLectern(player, level, pos, blockState, item);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@@ -129,13 +130,13 @@ public class CustomLecternBlock extends LecternBlock {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos pos) {
|
||||
protected int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos pos, Direction direction) {
|
||||
return level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern ? lectern.getRedstoneSignal() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hit) {
|
||||
if (!level.isClientSide && level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern) {
|
||||
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof CustomLecternBlockEntity lectern) {
|
||||
if (player.isSecondaryUseActive()) {
|
||||
// When shift+clicked with an empty hand, drop the item and replace with the normal lectern.
|
||||
clearLectern(level, pos, state);
|
||||
@@ -152,7 +153,7 @@ public class CustomLecternBlock extends LecternBlock {
|
||||
|
||||
@Override
|
||||
public @Nullable <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) {
|
||||
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.LECTERN.get(), serverTicker);
|
||||
return level.isClientSide() ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.LECTERN.get(), serverTicker);
|
||||
}
|
||||
|
||||
private static final BlockEntityTicker<CustomLecternBlockEntity> serverTicker = (level, pos, state, lectern) -> lectern.tick();
|
||||
|
@@ -23,7 +23,7 @@ public class PrintoutItem extends Item {
|
||||
@Override
|
||||
public InteractionResult use(Level world, Player player, InteractionHand hand) {
|
||||
var stack = player.getItemInHand(hand);
|
||||
if (!world.isClientSide) {
|
||||
if (!world.isClientSide()) {
|
||||
var title = PrintoutData.getOrEmpty(stack).title();
|
||||
var displayTitle = Strings.isNullOrEmpty(title) ? stack.getDisplayName() : Component.literal(title);
|
||||
player.openMenu(new SimpleMenuProvider((id, playerInventory, p) -> PrintoutMenu.createInHand(id, p, hand), displayTitle));
|
||||
|
@@ -58,7 +58,7 @@ public class DiskDriveBlock extends HorizontalContainerBlock {
|
||||
var blockPos = context.getClickedPos();
|
||||
var blockState = level.getBlockState(blockPos);
|
||||
if (blockState.is(ModRegistry.Blocks.DISK_DRIVE.get()) && blockState.getValue(STATE) == DiskDriveState.EMPTY) {
|
||||
if (!level.isClientSide && level.getBlockEntity(blockPos) instanceof DiskDriveBlockEntity drive && drive.getDiskStack().isEmpty()) {
|
||||
if (!level.isClientSide() && level.getBlockEntity(blockPos) instanceof DiskDriveBlockEntity drive && drive.getDiskStack().isEmpty()) {
|
||||
drive.setDiskStack(context.getItemInHand().split(1));
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
@@ -76,6 +76,6 @@ public class DiskDriveBlock extends HorizontalContainerBlock {
|
||||
@Override
|
||||
@Nullable
|
||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||
return level.isClientSide ? null : BaseEntityBlock.createTickerHelper(type, ModRegistry.BlockEntities.DISK_DRIVE.get(), serverTicker);
|
||||
return level.isClientSide() ? null : BaseEntityBlock.createTickerHelper(type, ModRegistry.BlockEntities.DISK_DRIVE.get(), serverTicker);
|
||||
}
|
||||
}
|
||||
|
@@ -162,7 +162,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity imp
|
||||
|
||||
@Override
|
||||
public void setChanged() {
|
||||
if (level != null && !level.isClientSide) updateMedia();
|
||||
if (level != null && !level.isClientSide()) updateMedia();
|
||||
super.setChanged();
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity imp
|
||||
}
|
||||
|
||||
private void ejectContents() {
|
||||
if (getLevel().isClientSide) return;
|
||||
if (getLevel().isClientSide()) return;
|
||||
|
||||
var stack = getDiskStack();
|
||||
if (stack.isEmpty()) return;
|
||||
|
@@ -40,7 +40,7 @@ public abstract class AbstractEnergyMethods<T> implements GenericPeripheral {
|
||||
* @return The energy stored in this block, in FE.
|
||||
*/
|
||||
@LuaFunction(mainThread = true)
|
||||
public abstract int getEnergy(T energy);
|
||||
public abstract long getEnergy(T energy);
|
||||
|
||||
/**
|
||||
* Get the maximum amount of energy this block can store.
|
||||
@@ -49,5 +49,5 @@ public abstract class AbstractEnergyMethods<T> implements GenericPeripheral {
|
||||
* @return The energy capacity of this block.
|
||||
*/
|
||||
@LuaFunction(mainThread = true)
|
||||
public abstract int getEnergyCapacity(T energy);
|
||||
public abstract long getEnergyCapacity(T energy);
|
||||
}
|
||||
|
@@ -102,7 +102,7 @@ public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityB
|
||||
return false;
|
||||
}
|
||||
|
||||
return world.setBlock(pos, fluid.createLegacyBlock(), world.isClientSide ? UPDATE_ALL_IMMEDIATE : UPDATE_ALL);
|
||||
return world.setBlock(pos, fluid.createLegacyBlock(), world.isClientSide() ? UPDATE_ALL_IMMEDIATE : UPDATE_ALL);
|
||||
}
|
||||
|
||||
public boolean onCustomDestroyBlock(BlockState state, Level world, BlockPos pos, Player player) {
|
||||
@@ -130,7 +130,7 @@ public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityB
|
||||
world.setBlockAndUpdate(pos, correctConnections(world, pos, newState));
|
||||
|
||||
cable.connectionsChanged();
|
||||
if (!world.isClientSide && !player.getAbilities().instabuild) {
|
||||
if (!world.isClientSide() && !player.getAbilities().instabuild) {
|
||||
Block.popResource(world, pos, item);
|
||||
}
|
||||
|
||||
|
@@ -80,7 +80,7 @@ public class CableBlockEntity extends BlockEntity {
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
modem.removed();
|
||||
if (level == null || !level.isClientSide) node.remove();
|
||||
if (level == null || !level.isClientSide()) node.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,7 +108,7 @@ public class CableBlockEntity extends BlockEntity {
|
||||
|
||||
void neighborChanged() {
|
||||
var dir = getModemDirection();
|
||||
if (!getLevel().isClientSide && dir != null && isPeripheralOn()) queueRefreshPeripheral();
|
||||
if (!getLevel().isClientSide() && dir != null && isPeripheralOn()) queueRefreshPeripheral();
|
||||
}
|
||||
|
||||
void queueRefreshPeripheral() {
|
||||
@@ -119,7 +119,7 @@ public class CableBlockEntity extends BlockEntity {
|
||||
InteractionResult use(Player player) {
|
||||
if (!canAttachPeripheral()) return InteractionResult.FAIL;
|
||||
|
||||
if (getLevel().isClientSide) return InteractionResult.SUCCESS;
|
||||
if (getLevel().isClientSide()) return InteractionResult.SUCCESS;
|
||||
|
||||
var oldName = peripheral.getConnectedName();
|
||||
if (isPeripheralOn()) {
|
||||
@@ -167,7 +167,7 @@ public class CableBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
void blockTick() {
|
||||
if (getLevel().isClientSide) return;
|
||||
if (getLevel().isClientSide()) return;
|
||||
|
||||
if (refreshPeripheral) {
|
||||
refreshPeripheral = false;
|
||||
@@ -185,7 +185,7 @@ public class CableBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
void connectionsChanged() {
|
||||
if (getLevel().isClientSide) return;
|
||||
if (getLevel().isClientSide()) return;
|
||||
refreshConnections = false;
|
||||
|
||||
var state = getBlockState();
|
||||
|
@@ -97,7 +97,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
||||
for (var modem : modems) {
|
||||
if (modem != null) modem.removed();
|
||||
}
|
||||
if (level == null || !level.isClientSide) node.remove();
|
||||
if (level == null || !level.isClientSide()) node.remove();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -120,7 +120,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
||||
|
||||
public InteractionResult use(Player player) {
|
||||
if (player.isCrouching() || !player.mayBuild()) return InteractionResult.PASS;
|
||||
if (getLevel().isClientSide) return InteractionResult.SUCCESS;
|
||||
if (getLevel().isClientSide()) return InteractionResult.SUCCESS;
|
||||
|
||||
// On server, we interacted if a peripheral was found
|
||||
var oldPeriphNames = getConnectedPeripheralNames();
|
||||
@@ -167,7 +167,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
void blockTick() {
|
||||
if (getLevel().isClientSide) return;
|
||||
if (getLevel().isClientSide()) return;
|
||||
|
||||
if (invalidSides != 0) {
|
||||
var oldInvalidSides = invalidSides;
|
||||
@@ -194,7 +194,7 @@ public class WiredModemFullBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
private void connectionsChanged() {
|
||||
if (getLevel().isClientSide) return;
|
||||
if (getLevel().isClientSide()) return;
|
||||
refreshConnections = false;
|
||||
|
||||
var world = getLevel();
|
||||
|
@@ -95,7 +95,7 @@ public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBl
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
if (!level.isClientSide) {
|
||||
if (!level.isClientSide()) {
|
||||
monitor.monitorTouched(
|
||||
(float) (hit.getLocation().x - hit.getBlockPos().getX()),
|
||||
(float) (hit.getLocation().y - hit.getBlockPos().getY()),
|
||||
@@ -111,7 +111,7 @@ public class MonitorBlock extends HorizontalDirectionalBlock implements EntityBl
|
||||
super.setPlacedBy(world, pos, blockState, livingEntity, itemStack);
|
||||
|
||||
var entity = world.getBlockEntity(pos);
|
||||
if (entity instanceof MonitorBlockEntity monitor && !world.isClientSide) {
|
||||
if (entity instanceof MonitorBlockEntity monitor && !world.isClientSide()) {
|
||||
// Defer the block update if we're being placed by another TE. See #691
|
||||
if (livingEntity == null || (livingEntity instanceof ServerPlayer player && PlatformHelper.get().isFakePlayer(player))) {
|
||||
monitor.updateNeighborsDeferred();
|
||||
|
@@ -99,7 +99,7 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
public void preRemoveSideEffects(BlockPos blockPos, BlockState blockState) {
|
||||
super.preRemoveSideEffects(blockPos, blockState);
|
||||
isRemoving = true;
|
||||
if (level != null && !getLevel().isClientSide) contractNeighbours();
|
||||
if (level != null && !getLevel().isClientSide()) contractNeighbours();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,7 +129,7 @@ public class MonitorBlockEntity extends BlockEntity {
|
||||
width = nbt.getIntOr(NBT_WIDTH, 1);
|
||||
height = nbt.getIntOr(NBT_HEIGHT, 1);
|
||||
|
||||
if (level != null && level.isClientSide) onClientLoad(oldXIndex, oldYIndex);
|
||||
if (level != null && level.isClientSide()) onClientLoad(oldXIndex, oldYIndex);
|
||||
}
|
||||
|
||||
void blockTick() {
|
||||
|
@@ -1,32 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.peripheral.monitor;
|
||||
|
||||
/**
|
||||
* The render type to use for monitors.
|
||||
*
|
||||
* @see dan200.computercraft.client.render.TileEntityMonitorRenderer
|
||||
* @see ClientMonitor
|
||||
*/
|
||||
public enum MonitorRenderer {
|
||||
/**
|
||||
* Determine the best monitor backend.
|
||||
*/
|
||||
BEST,
|
||||
|
||||
/**
|
||||
* Render using texture buffer objects.
|
||||
*
|
||||
* @see org.lwjgl.opengl.GL31#glTexBuffer(int, int, int)
|
||||
*/
|
||||
TBO,
|
||||
|
||||
/**
|
||||
* Render using VBOs.
|
||||
*
|
||||
* @see com.mojang.blaze3d.vertex.VertexBuffer
|
||||
*/
|
||||
VBO,
|
||||
}
|
@@ -50,7 +50,7 @@ public class SpeakerBlock extends HorizontalDirectionalBlock implements EntityBl
|
||||
@Override
|
||||
@Nullable
|
||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||
return level.isClientSide ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.SPEAKER.get(), serverTicker);
|
||||
return level.isClientSide() ? null : BlockEntityHelpers.createTickerHelper(type, ModRegistry.BlockEntities.SPEAKER.get(), serverTicker);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@@ -9,6 +9,7 @@ import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@@ -30,7 +31,7 @@ public class SpeakerBlockEntity extends BlockEntity {
|
||||
@Override
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
if (level != null && !level.isClientSide) {
|
||||
if (level != null && !level.isClientSide()) {
|
||||
ServerNetworking.sendToAllPlayers(new SpeakerStopClientMessage(peripheral.getSource()), Nullability.assertNonNull(getLevel().getServer()));
|
||||
}
|
||||
}
|
||||
@@ -47,7 +48,12 @@ public class SpeakerBlockEntity extends BlockEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeakerPosition getPosition() {
|
||||
protected ServerLevel getLevel() {
|
||||
return (ServerLevel) speaker.getLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpeakerPosition getPosition() {
|
||||
return SpeakerPosition.of(speaker.getLevel(), Vec3.atCenterOf(speaker.getBlockPos()));
|
||||
}
|
||||
|
||||
|
@@ -32,7 +32,10 @@ import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.block.state.properties.NoteBlockInstrument;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static dan200.computercraft.api.lua.LuaValues.checkFinite;
|
||||
|
||||
@@ -155,7 +158,9 @@ public abstract class SpeakerPeripheral implements IPeripheral {
|
||||
}
|
||||
}
|
||||
|
||||
public abstract SpeakerPosition getPosition();
|
||||
protected abstract ServerLevel getLevel();
|
||||
|
||||
protected abstract SpeakerPosition getPosition();
|
||||
|
||||
public UUID getSource() {
|
||||
return source;
|
||||
@@ -255,7 +260,7 @@ public abstract class SpeakerPeripheral implements IPeripheral {
|
||||
// Prevent playing music discs.
|
||||
var soundEvent = BuiltInRegistries.SOUND_EVENT.getValue(identifier);
|
||||
// TODO: Build a set of sound events at server startup, and cache this.
|
||||
var level = Objects.requireNonNull(getPosition().level());
|
||||
var level = getLevel();
|
||||
if (soundEvent != null && level.registryAccess().lookupOrThrow(Registries.JUKEBOX_SONG).stream().anyMatch(x -> x.soundEvent().value() == soundEvent)) {
|
||||
return false;
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@ package dan200.computercraft.shared.peripheral.speaker;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
||||
|
||||
/**
|
||||
@@ -16,8 +15,6 @@ import net.minecraft.server.level.ServerLevel;
|
||||
public abstract class UpgradeSpeakerPeripheral extends SpeakerPeripheral {
|
||||
public static final String ADJECTIVE = "upgrade.computercraft.speaker.adjective";
|
||||
|
||||
protected abstract ServerLevel getLevel();
|
||||
|
||||
@Override
|
||||
public void detach(IComputerAccess computer) {
|
||||
super.detach(computer);
|
||||
|
@@ -111,7 +111,7 @@ public class PocketComputerItem extends Item {
|
||||
@ForgeOverride
|
||||
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
|
||||
var level = entity.level();
|
||||
if (level.isClientSide || level.getServer() == null) return false;
|
||||
if (level.isClientSide() || level.getServer() == null) return false;
|
||||
|
||||
// If we're an item entity, tick an already existing computer (as to update the position), but do not keep the
|
||||
// computer alive.
|
||||
@@ -123,7 +123,7 @@ public class PocketComputerItem extends Item {
|
||||
@Override
|
||||
public InteractionResult use(Level world, Player player, InteractionHand hand) {
|
||||
var stack = player.getItemInHand(hand);
|
||||
if (!world.isClientSide) {
|
||||
if (!world.isClientSide()) {
|
||||
var holder = new PocketHolder.PlayerHolder((ServerPlayer) player, InventoryUtil.getHandSlot(player, hand));
|
||||
var brain = getOrCreateBrain((ServerLevel) world, holder, stack);
|
||||
var computer = brain.computer();
|
||||
|
@@ -11,10 +11,10 @@ import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public final class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral {
|
||||
final class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral {
|
||||
private final IPocketAccess access;
|
||||
|
||||
public PocketSpeakerPeripheral(IPocketAccess access) {
|
||||
PocketSpeakerPeripheral(IPocketAccess access) {
|
||||
this.access = access;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public final class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeakerPosition getPosition() {
|
||||
protected SpeakerPosition getPosition() {
|
||||
var entity = access.getEntity();
|
||||
return entity == null ? SpeakerPosition.of(access.getLevel(), access.getPosition()) : SpeakerPosition.of(entity);
|
||||
}
|
||||
|
@@ -125,7 +125,7 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
||||
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity entity, ItemStack stack) {
|
||||
super.setPlacedBy(level, pos, state, entity, stack);
|
||||
|
||||
if (!level.isClientSide && level.getBlockEntity(pos) instanceof TurtleBlockEntity turtle && entity instanceof Player player) {
|
||||
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof TurtleBlockEntity turtle && entity instanceof Player player) {
|
||||
turtle.setOwningPlayer(player.getGameProfile());
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
||||
protected InteractionResult useItemOn(ItemStack currentItem, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||
if (currentItem.getItem() == Items.NAME_TAG && currentItem.has(DataComponents.CUSTOM_NAME) && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
||||
// Label to rename computer
|
||||
if (!level.isClientSide) {
|
||||
if (!level.isClientSide()) {
|
||||
computer.setLabel(currentItem.getHoverName().getString());
|
||||
currentItem.shrink(1);
|
||||
}
|
||||
@@ -157,6 +157,6 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
||||
@Override
|
||||
@Nullable
|
||||
public <U extends BlockEntity> BlockEntityTicker<U> getTicker(Level level, BlockState state, BlockEntityType<U> type) {
|
||||
return level.isClientSide ? BlockEntityHelpers.createTickerHelper(type, this.type.get(), clientTicker) : super.getTicker(level, state, type);
|
||||
return level.isClientSide() ? BlockEntityHelpers.createTickerHelper(type, this.type.get(), clientTicker) : super.getTicker(level, state, type);
|
||||
}
|
||||
}
|
||||
|
@@ -6,7 +6,6 @@ package dan200.computercraft.shared.turtle.core;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.api.lua.ILuaCallback;
|
||||
import dan200.computercraft.api.lua.MethodResult;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
@@ -28,7 +27,6 @@ import dan200.computercraft.shared.util.Holiday;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.UUIDUtil;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@@ -65,15 +63,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
private static final String NBT_SLOT = "Slot";
|
||||
|
||||
/**
|
||||
* {@link net.minecraft.world.item.component.ResolvableProfile#CODEC}, but resolving to a {@link GameProfile}
|
||||
* directly. We don't use {@link ExtraCodecs#GAME_PROFILE}, as that encodes the UUID as a string, not an int array.
|
||||
*/
|
||||
private static final Codec<GameProfile> GAME_PROFILE_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
UUIDUtil.CODEC.fieldOf("id").forGetter(GameProfile::getId),
|
||||
ExtraCodecs.PLAYER_NAME.fieldOf("name").forGetter(GameProfile::getName)
|
||||
)
|
||||
.apply(instance, GameProfile::new));
|
||||
private static final Codec<GameProfile> GAME_PROFILE_CODEC = ExtraCodecs.STORED_GAME_PROFILE.codec();
|
||||
|
||||
private static final int ANIM_DURATION = 8;
|
||||
|
||||
@@ -121,7 +111,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
public void update() {
|
||||
var world = getLevel();
|
||||
if (!world.isClientSide) {
|
||||
if (!world.isClientSide()) {
|
||||
// Advance movement
|
||||
updateCommands();
|
||||
|
||||
@@ -221,7 +211,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
@Override
|
||||
public boolean teleportTo(Level world, BlockPos pos) {
|
||||
if (world.isClientSide || getLevel().isClientSide) {
|
||||
if (world.isClientSide() || getLevel().isClientSide()) {
|
||||
throw new UnsupportedOperationException("Cannot teleport on the client");
|
||||
}
|
||||
|
||||
@@ -335,7 +325,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
@Override
|
||||
public void setSelectedSlot(int slot) {
|
||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot set the slot on the client");
|
||||
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot set the slot on the client");
|
||||
|
||||
if (slot >= 0 && slot < owner.getContainerSize()) {
|
||||
selectedSlot = slot;
|
||||
@@ -371,7 +361,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
@Override
|
||||
public boolean consumeFuel(int fuel) {
|
||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot consume fuel on the client");
|
||||
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot consume fuel on the client");
|
||||
|
||||
if (!isFuelNeeded()) return true;
|
||||
|
||||
@@ -385,7 +375,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
@Override
|
||||
public void addFuel(int fuel) {
|
||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot add fuel on the client");
|
||||
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot add fuel on the client");
|
||||
|
||||
var addition = Math.max(fuel, 0);
|
||||
setFuelLevel(getFuelLevel() + addition);
|
||||
@@ -393,7 +383,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
@Override
|
||||
public MethodResult executeCommand(TurtleCommand command) {
|
||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot run commands on the client");
|
||||
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot run commands on the client");
|
||||
if (commandQueue.size() > 16) return MethodResult.of(false, "Too many ongoing turtle commands");
|
||||
|
||||
commandQueue.offer(new TurtleCommandQueueEntry(++commandsIssued, command));
|
||||
@@ -403,7 +393,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
|
||||
@Override
|
||||
public void playAnimation(TurtleAnimation animation) {
|
||||
if (getLevel().isClientSide) throw new UnsupportedOperationException("Cannot play animations on the client");
|
||||
if (getLevel().isClientSide()) throw new UnsupportedOperationException("Cannot play animations on the client");
|
||||
|
||||
this.animation = animation;
|
||||
if (this.animation == TurtleAnimation.SHORT_WAIT) {
|
||||
@@ -489,7 +479,9 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
instance.setUpgrade(upgrade);
|
||||
|
||||
// Create peripherals
|
||||
if (owner.getLevel() != null && !owner.getLevel().isClientSide) updatePeripherals(owner.createServerComputer());
|
||||
if (owner.getLevel() != null && !owner.getLevel().isClientSide()) {
|
||||
updatePeripherals(owner.createServerComputer());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -681,7 +673,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
}
|
||||
|
||||
// Advance valentines day easter egg
|
||||
if (world.isClientSide && animation == TurtleAnimation.MOVE_FORWARD && animationProgress == 4) {
|
||||
if (world.isClientSide() && animation == TurtleAnimation.MOVE_FORWARD && animationProgress == 4) {
|
||||
// Spawn love pfx if valentines day
|
||||
var currentHoliday = Holiday.getCurrent();
|
||||
if (currentHoliday == Holiday.VALENTINES) {
|
||||
|
@@ -57,7 +57,7 @@ public class TurtleItem extends BlockItem {
|
||||
|
||||
public static final CauldronInteraction CAULDRON_INTERACTION = (blockState, level, pos, player, hand, stack) -> {
|
||||
if (!stack.has(DataComponents.DYED_COLOR)) return InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||
if (!level.isClientSide) {
|
||||
if (!level.isClientSide()) {
|
||||
stack.remove(DataComponents.DYED_COLOR);
|
||||
LayeredCauldronBlock.lowerFillLevel(blockState, level, pos);
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ public class TurtleModem extends AbstractTurtleUpgrade {
|
||||
@Override
|
||||
public void update(ITurtleAccess turtle, TurtleSide side) {
|
||||
// Advance the modem
|
||||
if (!turtle.getLevel().isClientSide) {
|
||||
if (!turtle.getLevel().isClientSide()) {
|
||||
var peripheral = turtle.getPeripheral(side);
|
||||
if (peripheral instanceof Peripheral modem) {
|
||||
var state = modem.getModemState();
|
||||
|
@@ -32,7 +32,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpeakerPosition getPosition() {
|
||||
protected SpeakerPosition getPosition() {
|
||||
return SpeakerPosition.of(turtle.getLevel(), Vec3.atCenterOf(turtle.getPosition()));
|
||||
}
|
||||
|
||||
|
@@ -29,6 +29,7 @@ import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityReference;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||
@@ -218,7 +219,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
||||
|
||||
// If this is a projectile, attempt to deflect it instead.
|
||||
if (entity.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && entity instanceof Projectile projectile &&
|
||||
projectile.deflect(ProjectileDeflection.AIM_DEFLECT, player, player, true)
|
||||
projectile.deflect(ProjectileDeflection.AIM_DEFLECT, player, EntityReference.of(player), true)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
@@ -56,7 +56,7 @@ public final class TickScheduler {
|
||||
*/
|
||||
public static void schedule(Token token) {
|
||||
var world = token.owner.getLevel();
|
||||
if (world != null && !world.isClientSide && Token.STATE.compareAndSet(token, State.IDLE, State.SCHEDULED)) {
|
||||
if (world != null && !world.isClientSide() && Token.STATE.compareAndSet(token, State.IDLE, State.SCHEDULED)) {
|
||||
toTick.add(token);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,224 @@
|
||||
{
|
||||
"argument.computercraft.argument_expected": "Argumentum szükséges",
|
||||
"argument.computercraft.computer.distance": "Távolság az entitástól",
|
||||
"argument.computercraft.computer.family": "Számítógép típus",
|
||||
"argument.computercraft.computer.id": "Számítógép ID",
|
||||
"argument.computercraft.computer.instance": "Egyedi példányazonosító",
|
||||
"argument.computercraft.computer.label": "Számítógép címke",
|
||||
"argument.computercraft.computer.many_matching": "Több számítógép egyezik '%s' (példányok %s)",
|
||||
"argument.computercraft.computer.no_matching": "Nincs egyező számítógép '%s'",
|
||||
"argument.computercraft.tracking_field.no_field": "Ismeretlen mező '%s'",
|
||||
"argument.computercraft.unknown_computer_family": "Ismeretlen számítógéptípus '%s'",
|
||||
"block.computercraft.cable": "Hálózati kábel",
|
||||
"block.computercraft.computer_advanced": "Fejlett számítógép",
|
||||
"block.computercraft.computer_command": "Parancsszámítógép",
|
||||
"block.computercraft.computer_normal": "Számítógép",
|
||||
"block.computercraft.disk_drive": "Lemezmeghajtó",
|
||||
"block.computercraft.monitor_advanced": "Fejlett monitor",
|
||||
"block.computercraft.printer": "Nyomtató",
|
||||
"block.computercraft.redstone_relay": "Redstone jelfogó",
|
||||
"block.computercraft.speaker": "Hangszóró",
|
||||
"block.computercraft.turtle_advanced": "Fejlett teknős",
|
||||
"block.computercraft.turtle_advanced.upgraded": "Fejlett %s teknős",
|
||||
"block.computercraft.turtle_advanced.upgraded_twice": "Fejlett %s %s teknős",
|
||||
"block.computercraft.turtle_normal": "Teknős",
|
||||
"block.computercraft.turtle_normal.upgraded": "%s teknős",
|
||||
"block.computercraft.turtle_normal.upgraded_twice": "%s %s teknős",
|
||||
"block.computercraft.wired_modem": "Vezetékes modem",
|
||||
"block.computercraft.wired_modem_full": "Vezetékes modem",
|
||||
"block.computercraft.wireless_modem_advanced": "Ender modem",
|
||||
"block.computercraft.wireless_modem_normal": "Vezeték nélküli modem",
|
||||
"chat.computercraft.wired_modem.peripheral_connected": "Periféria \"%s\" csatlakoztatva a hálózathoz",
|
||||
"chat.computercraft.wired_modem.peripheral_disconnected": "Periféria \"%s\" lecsatlakoztatva a hálózatról",
|
||||
"commands.computercraft.desc": "A /computercraft parancs különböző hibakereső és adminisztrációs eszközöket biztosít a számítógépek vezérléséhez és kezeléséhez.",
|
||||
"commands.computercraft.dump.action": "További információ a számítógépről",
|
||||
"commands.computercraft.dump.desc": "Az összes számítógép állapotát, vagy egy konkrét számítógépről szóló információkat jeleníti meg. Megadhatod a számítógép példányazonosítóját (pl. 123), számítógép azonosítóját (pl. #123) vagy címkéjét (pl. \"@Saját Számítógép\").",
|
||||
"commands.computercraft.dump.open_path": "Nézd meg ennek a számítógépnek a fájljait",
|
||||
"commands.computercraft.dump.synopsis": "Számítógépek állapotának megjelenítése.",
|
||||
"commands.computercraft.generic.additional_rows": "%d további sor…",
|
||||
"commands.computercraft.generic.exception": "Kezelhetetlen kivétel (%s)",
|
||||
"commands.computercraft.generic.yes": "I",
|
||||
"commands.computercraft.help.desc": "Megjeleníti ezt a súgóüzenetet",
|
||||
"commands.computercraft.help.no_children": "%s nem rendelkezik alparancsokkal",
|
||||
"commands.computercraft.help.no_command": "Nincs ilyen parancs '%s'",
|
||||
"commands.computercraft.help.synopsis": "Súgó biztosítása egy adott parancshoz",
|
||||
"commands.computercraft.queue.desc": "Számítógép_parancs eseményt küld egy parancsszámítógépnek, további argumentumok továbbításával. Ez főleg térképkészítők számára készült, mint egy számítógépbarátabb változata a /trigger parancsnak. Bármelyik játékos futtathatja a parancsot, amit valószínűleg egy szövegelem kattintási eseményén keresztül végeznek.",
|
||||
"commands.computercraft.queue.synopsis": "Számítógép_parancs esemény küldése egy parancsszámítógépnek",
|
||||
"commands.computercraft.shutdown.desc": "Leállítja a megadott számítógépeket, vagy mindet, ha nincs megadva. Megadhatod a számítógép példányazonosítóját (pl. 123), számítógép azonosítóját (pl. #123) vagy címkéjét (pl. \"@Saját Számítógép\").",
|
||||
"commands.computercraft.shutdown.done": "%s/%s számítógép leállítva",
|
||||
"commands.computercraft.shutdown.synopsis": "Számítógépek távoli leállítása.",
|
||||
"commands.computercraft.synopsis": "Különféle parancsok számítógépek vezérlésére.",
|
||||
"commands.computercraft.tp.action": "Teleportálj ehhez a számítógéphez",
|
||||
"commands.computercraft.tp.desc": "Teleportálj egy számítógép helyére. Megadhatod a számítógép példányazonosítóját (pl. 123) vagy számítógép azonosítóját (pl. #123).",
|
||||
"commands.computercraft.tp.synopsis": "Teleportálás egy adott számítógéphez.",
|
||||
"commands.computercraft.track.desc": "Követi, mennyi ideig futnak a számítógépek, valamint hány eseményt kezelnek. Ez hasonló információkat nyújt, mint a /forge track, és hasznos lehet a késés diagnosztizálásában.",
|
||||
"commands.computercraft.track.dump.computer": "Számítógép",
|
||||
"commands.computercraft.track.dump.desc": "A számítógépes követés legfrissebb eredményeinek megjelenítése.",
|
||||
"commands.computercraft.track.dump.no_timings": "Nincsenek elérhető időzítések",
|
||||
"commands.computercraft.track.dump.synopsis": "A legfrissebb követési eredmények megjelenítése",
|
||||
"commands.computercraft.track.start.desc": "Minden számítógép végrehajtási idejének és eseményszámának követését indítja. Ezzel az előző futások eredményei elvesznek.",
|
||||
"commands.computercraft.track.start.stop": "Futtasd a %s parancsot a követés leállításához és az eredmények megtekintéséhez",
|
||||
"commands.computercraft.track.start.synopsis": "Minden számítógép követésének indítása",
|
||||
"commands.computercraft.track.stop.action": "Kattints a követés leállításához",
|
||||
"commands.computercraft.track.stop.desc": "Minden számítógépes esemény és végrehajtási idő követésének leállítása",
|
||||
"commands.computercraft.track.stop.not_enabled": "A számítógépek jelenleg nem követhetők",
|
||||
"commands.computercraft.track.stop.synopsis": "Minden számítógép követésének leállítása",
|
||||
"commands.computercraft.track.synopsis": "Számítógépek végrehajtási idejének követése.",
|
||||
"commands.computercraft.turn_on.desc": "Kapcsold be a megadott számítógépeket. Megadhatod a számítógép példányazonosítóját (pl. 123), számítógép azonosítóját (pl. #123) vagy címkéjét (pl. \"@Saját Számítógép\").",
|
||||
"commands.computercraft.turn_on.done": "%s/%s számítógép bekapcsolva",
|
||||
"commands.computercraft.turn_on.synopsis": "Számítógépek távoli bekapcsolása.",
|
||||
"commands.computercraft.view.action": "Nézd meg ezt a számítógépet",
|
||||
"commands.computercraft.view.desc": "Nyisd meg egy számítógép terminálját, amely lehetővé teszi a távoli vezérlést. Ez nem biztosít hozzáférést a teknősök leltárához. Megadhatod a számítógép példányazonosítóját (pl. 123) vagy számítógép azonosítóját (pl. #123).",
|
||||
"commands.computercraft.view.not_player": "Nem lehet terminált nyitni nem-játékos entitáshoz",
|
||||
"commands.computercraft.view.synopsis": "Számítógép termináljának megtekintése.",
|
||||
"gui.computercraft.config.command_require_creative": "Parancsszámítógépekhez kreatív mód szükséges",
|
||||
"gui.computercraft.config.command_require_creative.tooltip": "Szükséges, hogy a játékosok kreatív módban legyenek és rendelkezzenek adminisztrátori jogosultsággal a parancsszámítógépek használatához. Ez az alapértelmezett viselkedés a Minecraft parancsblokkjaihoz.",
|
||||
"gui.computercraft.config.computer_space_limit": "Számítógép tárhelykorlát (byte-ban)",
|
||||
"gui.computercraft.config.computer_space_limit.tooltip": "A számítógépek és teknősök lemezterületének korlátja, byte-ban.",
|
||||
"gui.computercraft.config.default_computer_settings": "Alapértelmezett számítógép-beállítások",
|
||||
"gui.computercraft.config.default_computer_settings.tooltip": "Alapértelmezett rendszerbeállítások vesszővel elválasztott listája, amelyek az új számítógépekre vonatkoznak.\nPélda: \"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\" letiltja az automatikus kiegészítést.",
|
||||
"gui.computercraft.config.disabled_generic_methods": "Letiltott általános metódusok",
|
||||
"gui.computercraft.config.disabled_generic_methods.tooltip": "Általános metódusok vagy metódusforrások listája, amelyek le vannak tiltva. Az általános metódusokat akkor adják hozzá egy blokkhoz vagy blokk entitáshoz, ha nincs kifejezetten hozzárendelt periféria-szolgáltató. Ez magában foglalja a leltár metódusokat (pl. inventory.getItemDetail, inventory.pushItems), valamint (Forge esetén) a fluid_storage és energy_storage metódusokat is.\nA listában lévő metódus lehet egy teljes metóduscsoport (computercraft:inventory), vagy egyetlen metódus (computercraft:inventory#pushItems).",
|
||||
"gui.computercraft.config.execution": "Végrehajtás",
|
||||
"gui.computercraft.config.execution.computer_threads": "Számítógép szálak",
|
||||
"gui.computercraft.config.execution.computer_threads.tooltip": "Az egyidejűleg futó számítógépek számát szabályozza. A magasabb szám több számítógép egyidejű futását teszi lehetővé, de lassulást okozhat. Vegye figyelembe, hogy néhány mod nem működik, ha a szálak száma meghaladja az 1-et. Óvatosan használja.\nTartomány: > 1",
|
||||
"gui.computercraft.config.execution.max_main_computer_time": "Szerver tick számítógépidő-korlát",
|
||||
"gui.computercraft.config.execution.max_main_computer_time.tooltip": "Az ideális maximális idő, ameddig egy számítógép egy tick-ben futtathat, milliszekundumban. Megjegyzés: Lehetséges, hogy túllépjük ezt a határt, mivel nincs mód az idő pontos előrejelzésére - ez az átlagos felső határ.",
|
||||
"gui.computercraft.config.execution.max_main_global_time": "Szerver tick globális időkorlát",
|
||||
"gui.computercraft.config.execution.max_main_global_time.tooltip": "Az egy tick-ben feladatok végrehajtására fordított maximális idő, milliszekundumban.",
|
||||
"gui.computercraft.config.execution.tooltip": "A számítógépek végrehajtási viselkedését szabályozza. Ez elsősorban szerverek finomhangolására szolgál, és általában nem szükséges megváltoztatni.",
|
||||
"gui.computercraft.config.floppy_space_limit": "Floppy lemez tárhelykorlát (byte-ban)",
|
||||
"gui.computercraft.config.floppy_space_limit.tooltip": "A floppy lemezek lemezterületének korlátja, byte-ban.",
|
||||
"gui.computercraft.config.http.bandwidth": "Sávszélesség",
|
||||
"gui.computercraft.config.http.bandwidth.global_download": "Globális letöltési korlát",
|
||||
"gui.computercraft.config.http.bandwidth.global_download.tooltip": "Az egy másodperc alatt letölthető byte-ok száma, amelyet minden számítógép oszt meg. (byte/s).\nTartomány: > 1",
|
||||
"gui.computercraft.config.http.bandwidth.global_upload": "Globális feltöltési korlát",
|
||||
"gui.computercraft.config.http.bandwidth.global_upload.tooltip": "Az egy másodperc alatt feltölthető byte-ok száma, amelyet minden számítógép oszt meg. (byte/s).\nTartomány: > 1",
|
||||
"gui.computercraft.config.http.bandwidth.tooltip": "A számítógépek által használt sávszélességet korlátozza.",
|
||||
"gui.computercraft.config.http.enabled": "HTTP API engedélyezése",
|
||||
"gui.computercraft.config.http.enabled.tooltip": "Az \"http\" API engedélyezése a számítógépeken. Ha letiltjuk, akkor az \"http\", \"pastebin\" és \"wget\" programok is le lesznek tiltva, amelyeket sok felhasználó használ. Ajánlott engedélyezve hagyni, és a \"rules\" beállítás használatával finomhangolni a szabályozást.",
|
||||
"gui.computercraft.config.http.max_requests": "Maximális egyidejű kérések",
|
||||
"gui.computercraft.config.http.max_requests.tooltip": "Az egyszerre elküldhető http kérések száma egy számítógépen. A további kérések sorba állnak, és akkor kerülnek elküldésre, amikor a futó kérések befejeződtek. 0-ra állítva nincs korlátozás.\nTartomány: > 0",
|
||||
"gui.computercraft.config.http.max_websockets": "Maximális egyidejű websockets",
|
||||
"gui.computercraft.config.http.max_websockets.tooltip": "Az egyszerre megnyitható websockets száma egy számítógépen.\nTartomány: > 1",
|
||||
"gui.computercraft.config.http.proxy.host": "Hosztnév",
|
||||
"gui.computercraft.config.http.proxy.host.tooltip": "A proxy szerver hosztneve vagy IP-címe.",
|
||||
"gui.computercraft.config.http.proxy.port.tooltip": "A proxy szerver portja.\nTartomány: 1 ~ 65536",
|
||||
"gui.computercraft.config.http.proxy.tooltip": "Az HTTP és websocket kérések proxy szerveren keresztüli alagútba helyezése. Csak az \"use_proxy\" igazra állított HTTP szabályok esetén hatékony (alapértelmezésben kikapcsolva).",
|
||||
"gui.computercraft.config.http.proxy.type": "Proxy típus",
|
||||
"gui.computercraft.config.http.proxy.type.tooltip": "A használni kívánt proxy típus.\nMegengedett értékek: HTTP, HTTPS, SOCKS4, SOCKS5",
|
||||
"gui.computercraft.config.http.rules": "Engedélyezés/tiltás szabályok",
|
||||
"gui.computercraft.config.http.rules.tooltip": "Szabályok listája, amelyek szabályozzák az \"http\" API viselkedését adott domainek vagy IP-k számára. Minden szabály egy hosztnévre és egy opcionális portra vonatkozik, majd több tulajdonságot állít be a kéréshez. A szabályok sorrendben kerülnek értékelésre, így az előbbi szabályok felülírják a későbbieket.\n\nÉrvényes tulajdonságok:\n - \"host\" (kötelező): Az a domain vagy IP-cím, amelyre ez a szabály vonatkozik. Ez lehet domain név (\"pastebin.com\"), helyettesítő karakter (\"*.pastebin.com\") vagy CIDR jelölés (\"127.0.0.0/8\").\n - \"port\" (opcionális): Csak adott porttal rendelkező kérésekre vonatkozik, mint például 80 vagy 443.\n\n - \"action\" (opcionális): Azt határozza meg, hogy engedélyezett vagy tiltott legyen-e a kérés.\n - \"max_download\" (opcionális): A maximális méret (byte-ban), amit egy számítógép letölthet ezen a kérésen keresztül.\n - \"max_upload\" (opcionális): A maximális méret (byte-ban), amit egy számítógép feltölthet ezen a kérésen keresztül.\n - \"max_websocket_message\" (opcionális): A maximális méret (byte-ban), amit egy számítógép egy websocket csomagon keresztül küldhet vagy fogadhat.\n - \"use_proxy\" (opcionális): Proxy vagy HTTP/SOCKS proxy használata, ha be van állítva.",
|
||||
"gui.computercraft.config.http.tooltip": "A HTTP API szabályozása",
|
||||
"gui.computercraft.config.http.websocket_enabled": "Websockets engedélyezése",
|
||||
"gui.computercraft.config.http.websocket_enabled.tooltip": "A websockets használatának engedélyezése az http segítségével. Ehhez az \"http_enable\" opciónak is igaznak kell lennie.",
|
||||
"gui.computercraft.config.log_computer_errors": "Számítógép hibáinak naplózása",
|
||||
"gui.computercraft.config.log_computer_errors.tooltip": "A perifériák és más Lua objektumok által kiváltott kivételek naplózása. Ez segíthet a mod készítőknek a hibák megoldásában, de túl sok naplózott hiba esetén log-túltelítettséget eredményezhet.",
|
||||
"gui.computercraft.config.maximum_open_files": "Maximálisan megnyitható fájlok száma számítógépenként",
|
||||
"gui.computercraft.config.maximum_open_files.tooltip": "Beállítja, hogy egy számítógép hány fájlt nyithat meg egyszerre. 0-ra állítva nincs korlátozás.\nTartomány: > 0",
|
||||
"gui.computercraft.config.monitor_distance": "Monitor távolság",
|
||||
"gui.computercraft.config.monitor_distance.tooltip": "A monitorok maximális megjelenítési távolsága. Alapértelmezés szerint a szabványos blokk entitás korlátot használja, de ha nagyobb monitorokat szeretne építeni, akkor ezt növelheti.\nTartomány: 16 ~ 1024",
|
||||
"gui.computercraft.config.monitor_renderer": "Monitor renderelő",
|
||||
"gui.computercraft.config.monitor_renderer.tooltip": "A monitorok renderelőjének beállítása. Általában érdemes \"legjobb\" értéken hagyni - ha a monitorok teljesítményproblémákat okoznak, kipróbálhat más renderelő opciókat.\nMegengedett értékek: BEST, TBO, VBO",
|
||||
"gui.computercraft.config.peripheral": "Perifériák",
|
||||
"gui.computercraft.config.peripheral.command_block_enabled": "Parancsblokk periféria engedélyezése",
|
||||
"gui.computercraft.config.peripheral.command_block_enabled.tooltip": "Parancsblokk periféria támogatásának engedélyezése",
|
||||
"gui.computercraft.config.peripheral.max_notes_per_tick": "Egy tick alatt játszható maximális hangjegyek száma",
|
||||
"gui.computercraft.config.peripheral.max_notes_per_tick.tooltip": "A hangszóró által egy tick alatt lejátszható maximális hangjegyek száma.\nTartomány: > 1",
|
||||
"gui.computercraft.config.peripheral.modem_high_altitude_range": "Modem hatótávolság (magas magasság)",
|
||||
"gui.computercraft.config.peripheral.modem_high_altitude_range.tooltip": "A vezeték nélküli modemek hatótávolsága maximális magasságban, tiszta időben, méterben.\nTartomány: 0 ~ 100000",
|
||||
"gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Modem hatótávolság (magas magasság, viharos idő)",
|
||||
"gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm.tooltip": "A vezeték nélküli modemek hatótávolsága maximális magasságban viharos időben, méterben.\nTartomány: 0 ~ 100000",
|
||||
"gui.computercraft.config.peripheral.modem_range": "Modem hatótávolság (alapértelmezett)",
|
||||
"gui.computercraft.config.peripheral.modem_range.tooltip": "A vezeték nélküli modemek hatótávolsága alacsony magasságban, tiszta időben, méterben.\nTartomány: 0 ~ 100000",
|
||||
"gui.computercraft.config.peripheral.modem_range_during_storm": "Modem hatótávolság (viharos idő)",
|
||||
"gui.computercraft.config.peripheral.modem_range_during_storm.tooltip": "A vezeték nélküli modemek hatótávolsága alacsony magasságban, viharos időben, méterben.\nTartomány: 0 ~ 100000",
|
||||
"gui.computercraft.config.peripheral.monitor_bandwidth": "Monitor sávszélesség",
|
||||
"gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "A monitoronként elküldhető adatkorlát *tick-enként*. Megjegyzés:\n - A sávszélességet a tömörítés előtt mérjük, így az ügyfélhez elküldött adat kisebb.\n - Nem veszi figyelembe a játékosok számát, akiknek egy csomagot küldünk. Egy monitor frissítése egy játékos számára ugyanolyan sávszélesség-korlátot fogyaszt, mint 20 játékosnak küldve.\n - Egy teljes méretű monitor ~25kb adatot küld. Az alapértelmezett érték (1MB) ~40 monitor frissítését teszi lehetővé egyetlen tick-ben.\n0-ra állítva letiltja.\nTartomány: > 0",
|
||||
"gui.computercraft.config.peripheral.tooltip": "Különböző beállítások a perifériákhoz.",
|
||||
"gui.computercraft.config.term_sizes": "Terminál méretek",
|
||||
"gui.computercraft.config.term_sizes.computer": "Számítógép",
|
||||
"gui.computercraft.config.term_sizes.computer.height": "Terminál magasság",
|
||||
"gui.computercraft.config.term_sizes.computer.height.tooltip": "Tartomány: 1 ~ 255",
|
||||
"gui.computercraft.config.term_sizes.computer.tooltip": "Számítógépek terminálmérete.",
|
||||
"gui.computercraft.config.term_sizes.computer.width": "Terminál szélesség",
|
||||
"gui.computercraft.config.term_sizes.computer.width.tooltip": "Tartomány: 1 ~ 255",
|
||||
"gui.computercraft.config.term_sizes.monitor.height": "Maximális monitor magasság",
|
||||
"gui.computercraft.config.term_sizes.monitor.height.tooltip": "Tartomány: 1 ~ 32",
|
||||
"gui.computercraft.config.term_sizes.monitor.tooltip": "A monitorok maximális mérete (blokkokban).",
|
||||
"gui.computercraft.config.term_sizes.monitor.width": "Maximális monitor szélesség",
|
||||
"gui.computercraft.config.term_sizes.monitor.width.tooltip": "Tartomány: 1 ~ 32",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer": "Zseb számítógép",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height": "Terminál magasság",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "Tartomány: 1 ~ 255",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.tooltip": "Zseb számítógépek terminálmérete.",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width": "Terminál szélesség",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "Tartomány: 1 ~ 255",
|
||||
"gui.computercraft.config.term_sizes.tooltip": "Különböző számítógépek terminálméretének konfigurálása.\nA nagyobb terminálok több sávszélességet igényelnek, ezért óvatosan használjuk.",
|
||||
"gui.computercraft.config.turtle": "Teknősök",
|
||||
"gui.computercraft.config.turtle.advanced_fuel_limit": "Fejlett teknős üzemanyag korlát",
|
||||
"gui.computercraft.config.turtle.advanced_fuel_limit.tooltip": "A fejlett teknősök üzemanyag korlátja.\nTartomány: > 0",
|
||||
"gui.computercraft.config.turtle.can_push": "A teknősök tolják az entitásokat",
|
||||
"gui.computercraft.config.turtle.can_push.tooltip": "Ha be van állítva igazra, a teknősök eltolják az entitásokat az útból, ha van elég hely, ahelyett, hogy megállnának.",
|
||||
"gui.computercraft.config.turtle.need_fuel": "Üzemanyag szükséges",
|
||||
"gui.computercraft.config.turtle.need_fuel.tooltip": "Beállítja, hogy a teknősöknek szükségük van-e üzemanyagra a mozgáshoz.",
|
||||
"gui.computercraft.config.turtle.normal_fuel_limit": "Teknős üzemanyag korlát",
|
||||
"gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "A teknősök üzemanyag korlátja.\nTartomány: > 0",
|
||||
"gui.computercraft.config.turtle.tooltip": "Különböző beállítások a teknősökhöz.",
|
||||
"gui.computercraft.config.upload_max_size": "Feltöltési fájlméret korlát (byte-ban)",
|
||||
"gui.computercraft.config.upload_max_size.tooltip": "A feltöltési fájlméret korlátja, byte-ban. A tartománynak 1 KiB és 16 MiB között kell lennie.\nVegye figyelembe, hogy a feltöltések egyetlen tick alatt kerülnek feldolgozásra - a nagy fájlok vagy a gyenge hálózati teljesítmény leállíthatják a hálózati szálat. És figyeljünk a lemezterületre!\nTartomány: 1024 ~ 16777216",
|
||||
"gui.computercraft.config.upload_nag_delay": "Feltöltési figyelmeztetési késleltetés",
|
||||
"gui.computercraft.config.upload_nag_delay.tooltip": "Az a késleltetés másodpercben, ami után figyelmeztetést kapunk a feldolgozatlan importokról. 0-ra állítva letiltja.\nTartomány: 0 ~ 60",
|
||||
"gui.computercraft.pocket_computer_overlay": "Zseb számítógép megnyitva. Nyomd meg az ESC-t a bezáráshoz.",
|
||||
"gui.computercraft.terminal": "Számítógép terminál",
|
||||
"gui.computercraft.tooltip.computer_id": "Számítógép ID: %s",
|
||||
"gui.computercraft.tooltip.copy": "Másolás vágólapra",
|
||||
"gui.computercraft.tooltip.disk_id": "Lemez ID: %s",
|
||||
"gui.computercraft.tooltip.terminate": "A futó kód leállítása",
|
||||
"gui.computercraft.tooltip.terminate.key": "Tartsd lenyomva a Ctrl+T billentyűket",
|
||||
"gui.computercraft.tooltip.turn_off": "Kapcsold ki ezt a számítógépet",
|
||||
"gui.computercraft.tooltip.turn_off.key": "Tartsd lenyomva a Ctrl+S billentyűket",
|
||||
"gui.computercraft.tooltip.turn_on": "Kapcsold be ezt a számítógépet",
|
||||
"gui.computercraft.upload.failed": "Feltöltés sikertelen",
|
||||
"gui.computercraft.upload.failed.computer_off": "Be kell kapcsolnod a számítógépet a fájlok feltöltéséhez.",
|
||||
"gui.computercraft.upload.failed.corrupted": "Fájlok megsérültek a feltöltés során. Kérlek próbáld újra.",
|
||||
"gui.computercraft.upload.failed.generic": "Feltöltés sikertelen (%s)",
|
||||
"gui.computercraft.upload.failed.name_too_long": "A fájlnevek túl hosszúak a feltöltéshez.",
|
||||
"gui.computercraft.upload.failed.too_many_files": "Nem lehet ilyen sok fájlt feltölteni.",
|
||||
"gui.computercraft.upload.failed.too_much": "A fájlok túl nagyok a feltöltéshez.",
|
||||
"gui.computercraft.upload.no_response": "Fájlok átvitele",
|
||||
"gui.computercraft.upload.no_response.msg": "A számítógéped nem használta a továbbított fájlokat. Lehet, hogy futtatnod kell a %s programot, majd újra próbálkozni.",
|
||||
"item.computercraft.disk": "Floppy lemez",
|
||||
"item.computercraft.pocket_computer_advanced": "Fejlett zseb számítógép",
|
||||
"item.computercraft.pocket_computer_advanced.upgraded": "Fejlett %s zseb számítógép",
|
||||
"item.computercraft.pocket_computer_normal": "Zseb számítógép",
|
||||
"item.computercraft.pocket_computer_normal.upgraded": "%s zseb számítógép",
|
||||
"item.computercraft.printed_book": "Nyomtatott könyv",
|
||||
"item.computercraft.printed_page": "Nyomtatott oldal",
|
||||
"item.computercraft.printed_pages": "Nyomtatott oldalak",
|
||||
"item.computercraft.treasure_disk": "Floppy lemez",
|
||||
"tag.item.computercraft.computer": "Számítógépek",
|
||||
"tag.item.computercraft.monitor": "Monitorok",
|
||||
"tag.item.computercraft.turtle": "Teknősök",
|
||||
"tag.item.computercraft.wired_modem": "Vezetékes modemek",
|
||||
"tracking_field.computercraft.avg": "%s (átlag)",
|
||||
"tracking_field.computercraft.computer_tasks.name": "Feladatok",
|
||||
"tracking_field.computercraft.count": "%s (szám)",
|
||||
"tracking_field.computercraft.fs.name": "Fájlrendszer műveletek",
|
||||
"tracking_field.computercraft.http_download.name": "HTTP letöltés",
|
||||
"tracking_field.computercraft.http_requests.name": "HTTP kérések",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP feltöltés",
|
||||
"tracking_field.computercraft.peripheral.name": "Periféria hívások",
|
||||
"tracking_field.computercraft.server_tasks.name": "Szerver feladatok",
|
||||
"tracking_field.computercraft.turtle_ops.name": "Teknős műveletek",
|
||||
"tracking_field.computercraft.websocket_incoming.name": "Websocket bejövő",
|
||||
"tracking_field.computercraft.websocket_outgoing.name": "Websocket kimenő",
|
||||
"upgrade.computercraft.speaker.adjective": "Hangos",
|
||||
"upgrade.computercraft.wireless_modem_normal.adjective": "Vezeték nélküli",
|
||||
"upgrade.minecraft.crafting_table.adjective": "Kézműves",
|
||||
"upgrade.minecraft.diamond_axe.adjective": "Fanyeső",
|
||||
"upgrade.minecraft.diamond_hoe.adjective": "Gazdálkodó",
|
||||
"upgrade.minecraft.diamond_pickaxe.adjective": "Bányász",
|
||||
"upgrade.minecraft.diamond_shovel.adjective": "Ásó",
|
||||
"upgrade.minecraft.diamond_sword.adjective": "Közelharci"
|
||||
}
|
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"argument.computercraft.argument_expected": "预期自变量",
|
||||
"argument.computercraft.computer.distance": "实体距离",
|
||||
"argument.computercraft.computer.family": "电脑类别",
|
||||
"argument.computercraft.computer.id": "电脑ID",
|
||||
"argument.computercraft.computer.family": "计算机类别",
|
||||
"argument.computercraft.computer.id": "计算机ID",
|
||||
"argument.computercraft.computer.instance": "唯一实例ID",
|
||||
"argument.computercraft.computer.label": "电脑标签",
|
||||
"argument.computercraft.computer.label": "计算机标签",
|
||||
"argument.computercraft.computer.many_matching": "多台计算机匹配'%s' (实例%s)",
|
||||
"argument.computercraft.computer.no_matching": "没有计算机匹配'%s'",
|
||||
"argument.computercraft.tracking_field.no_field": "未知字段'%s'",
|
||||
"argument.computercraft.unknown_computer_family": "未知电脑类别 '%s'",
|
||||
"block.computercraft.cable": "网络电缆",
|
||||
"argument.computercraft.unknown_computer_family": "未知计算机类别“%s”",
|
||||
"block.computercraft.cable": "网络线缆",
|
||||
"block.computercraft.computer_advanced": "高级计算机",
|
||||
"block.computercraft.computer_command": "命令电脑",
|
||||
"block.computercraft.computer_command": "命令计算机",
|
||||
"block.computercraft.computer_normal": "计算机",
|
||||
"block.computercraft.disk_drive": "磁盘驱动器",
|
||||
"block.computercraft.disk_drive": "软盘驱动器",
|
||||
"block.computercraft.monitor_advanced": "高级显示器",
|
||||
"block.computercraft.monitor_normal": "显示器",
|
||||
"block.computercraft.printer": "打印机",
|
||||
@@ -29,36 +29,36 @@
|
||||
"block.computercraft.wired_modem_full": "有线调制解调器",
|
||||
"block.computercraft.wireless_modem_advanced": "末影调制解调器",
|
||||
"block.computercraft.wireless_modem_normal": "无线调制解调器",
|
||||
"chat.computercraft.wired_modem.peripheral_connected": "外部设备\"%s\"连接到网络",
|
||||
"chat.computercraft.wired_modem.peripheral_disconnected": "外部设备\"%s\"与网络断开连接",
|
||||
"chat.computercraft.wired_modem.peripheral_connected": "外部设备\"%s\"已连接到网络",
|
||||
"chat.computercraft.wired_modem.peripheral_disconnected": "外部设备\"%s\"已与网络断开连接",
|
||||
"commands.computercraft.desc": "/computercraft命令提供各种调试和管理工具,用于控制和与计算机交互.",
|
||||
"commands.computercraft.dump.action": "查看有关此计算机的更多信息",
|
||||
"commands.computercraft.dump.desc": "显示所有计算机的状态或某台计算机的特定信息. 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. \"@My Computer\").",
|
||||
"commands.computercraft.dump.open_path": "查看该电脑的文件",
|
||||
"commands.computercraft.dump.synopsis": "显示计算机的状态.",
|
||||
"commands.computercraft.generic.additional_rows": "%d额外的行…",
|
||||
"commands.computercraft.generic.exception": "未处理的异常(%s)",
|
||||
"commands.computercraft.generic.no": "N",
|
||||
"commands.computercraft.generic.yes": "Y",
|
||||
"commands.computercraft.dump.open_path": "查看此计算机的文件",
|
||||
"commands.computercraft.dump.synopsis": "显示计算机的状态。",
|
||||
"commands.computercraft.generic.additional_rows": "%d额外的行……",
|
||||
"commands.computercraft.generic.exception": "未处理的异常(%s)",
|
||||
"commands.computercraft.generic.no": "否",
|
||||
"commands.computercraft.generic.yes": "是",
|
||||
"commands.computercraft.help.desc": "显示该帮助信息",
|
||||
"commands.computercraft.help.no_children": "%s没有子命令",
|
||||
"commands.computercraft.help.no_command": "没有这样的命令'%s'",
|
||||
"commands.computercraft.help.no_command": "没有这样的命令“%s”",
|
||||
"commands.computercraft.help.synopsis": "为特定的命令提供帮助",
|
||||
"commands.computercraft.queue.desc": "发送computer_command事件到命令计算机,并传递其他参数. 这主要是为地图制作者设计的, 作为/trigger更加计算机友好的版本. 任何玩家都可以运行命令, 这很可能是通过文本组件的点击事件完成的.",
|
||||
"commands.computercraft.queue.synopsis": "将computer_command事件发送到命令计算机",
|
||||
"commands.computercraft.shutdown.desc": "关闭列出的计算机或全部计算机(如果未指定). 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. \"@My Computer\").",
|
||||
"commands.computercraft.shutdown.desc": "关闭列出的计算机或全部计算机(如果未指定)。你可以指定计算机的实例id(例如 123),计算机id(例如 #123)或标签(例如 \"@My Computer\")。",
|
||||
"commands.computercraft.shutdown.done": "关闭%s/%s计算机",
|
||||
"commands.computercraft.shutdown.synopsis": "远程关闭计算机.",
|
||||
"commands.computercraft.synopsis": "各种控制计算机的命令.",
|
||||
"commands.computercraft.tp.action": "传送到这台电脑",
|
||||
"commands.computercraft.tp.desc": "传送到计算机的位置. 你可以指定计算机的实例id (例如. 123)或计算机id (例如. #123).",
|
||||
"commands.computercraft.tp.synopsis": "传送到特定的计算机.",
|
||||
"commands.computercraft.track.desc": "跟踪计算机执行的时间以及它们处理的事件数. 这以/forge track类似的方式呈现信息,可用于诊断滞后.",
|
||||
"commands.computercraft.shutdown.synopsis": "远程关闭计算机。",
|
||||
"commands.computercraft.synopsis": "各种控制计算机的命令。",
|
||||
"commands.computercraft.tp.action": "传送到这台计算机",
|
||||
"commands.computercraft.tp.desc": "传送到计算机的位置。你可以指定计算机的实例id(例如 123)或计算机id(例如 #123)。",
|
||||
"commands.computercraft.tp.synopsis": "传送到特定的计算机。",
|
||||
"commands.computercraft.track.desc": "跟踪计算机执行的时间以及它们处理的事件数。这以/forge track类似的方式呈现信息,可能有助于诊断卡顿与滞后。",
|
||||
"commands.computercraft.track.dump.computer": "计算机",
|
||||
"commands.computercraft.track.dump.desc": "输出计算机跟踪的最新结果.",
|
||||
"commands.computercraft.track.dump.desc": "输出计算机跟踪的最新结果。",
|
||||
"commands.computercraft.track.dump.no_timings": "没有时序可用",
|
||||
"commands.computercraft.track.dump.synopsis": "输出最新的跟踪结果",
|
||||
"commands.computercraft.track.start.desc": "开始跟踪所有计算机的执行时间和事件计数. 这将放弃先前运行的结果.",
|
||||
"commands.computercraft.track.start.desc": "开始跟踪所有计算机的执行时间和事件计数。这将放弃先前运行的结果。",
|
||||
"commands.computercraft.track.start.stop": "运行%s以停止跟踪并查看结果",
|
||||
"commands.computercraft.track.start.synopsis": "开始跟踪所有计算机",
|
||||
"commands.computercraft.track.stop.action": "点击停止跟踪",
|
||||
@@ -67,16 +67,16 @@
|
||||
"commands.computercraft.track.stop.synopsis": "停止跟踪所有计算机",
|
||||
"commands.computercraft.track.synopsis": "跟踪计算机的执行时间.",
|
||||
"commands.computercraft.turn_on.desc": "打开列出的计算机. 你可以指定计算机的实例id (例如. 123), 计算机id (例如. #123)或标签(例如. \"@My Computer\").",
|
||||
"commands.computercraft.turn_on.done": "打开%s/%s计算机",
|
||||
"commands.computercraft.turn_on.done": "已打开%s/%s台计算机",
|
||||
"commands.computercraft.turn_on.synopsis": "远程打开计算机.",
|
||||
"commands.computercraft.view.action": "查看此计算机",
|
||||
"commands.computercraft.view.desc": "打开计算机的终端,允许远程控制计算机. 这不提供对海龟库存的访问. 你可以指定计算机的实例id (例如. 123)或计算机id (例如. #123).",
|
||||
"commands.computercraft.view.not_player": "无法为非玩家打开终端",
|
||||
"commands.computercraft.view.synopsis": "查看计算机的终端.",
|
||||
"gui.computercraft.config.command_require_creative": "命令电脑需要创造模式",
|
||||
"gui.computercraft.config.command_require_creative": "命令计算机需要创造模式",
|
||||
"gui.computercraft.config.command_require_creative.tooltip": "玩家需要处于创造模式并为管理员才能与命令计算机交互。\n这是原版命令方块的默认行为。",
|
||||
"gui.computercraft.config.computer_space_limit": "计算机空间限制(字节)",
|
||||
"gui.computercraft.config.computer_space_limit.tooltip": "计算机和海龟的磁盘空间限制,以字节为单位。",
|
||||
"gui.computercraft.config.computer_space_limit.tooltip": "计算机和海龟的软盘空间限制,以字节为单位。",
|
||||
"gui.computercraft.config.default_computer_settings": "默认计算机设置",
|
||||
"gui.computercraft.config.default_computer_settings.tooltip": "以逗号分隔的默认系统设置列表,用于在新计算机上设置。\n示例:“shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false”\n将禁用所有自动补全功能。",
|
||||
"gui.computercraft.config.disabled_generic_methods": "禁用的通用方法",
|
||||
@@ -89,15 +89,15 @@
|
||||
"gui.computercraft.config.execution.max_main_global_time": "服务器全局tick时间限制",
|
||||
"gui.computercraft.config.execution.max_main_global_time.tooltip": "在1刻内执行任务所花费的最大时间,以毫秒为单位。\n请注意,我们很可能会超出此限制,因为无法确定需要多长时间——这旨在成为平均时间的上限。",
|
||||
"gui.computercraft.config.execution.tooltip": "控制计算机的执行行为。这主要用于微调服务器,一般不需要触碰。",
|
||||
"gui.computercraft.config.floppy_space_limit": "软盘空间限制(字节)",
|
||||
"gui.computercraft.config.floppy_space_limit.tooltip": "软盘的磁盘空间限制,以字节为单位。",
|
||||
"gui.computercraft.config.floppy_space_limit": "软盘空间限制(字节)",
|
||||
"gui.computercraft.config.floppy_space_limit.tooltip": "软盘的存储空间限制,以字节为单位。",
|
||||
"gui.computercraft.config.http": "HTTP",
|
||||
"gui.computercraft.config.http.bandwidth": "带宽",
|
||||
"gui.computercraft.config.http.bandwidth.global_download": "全局下载限速",
|
||||
"gui.computercraft.config.http.bandwidth.global_download.tooltip": "每秒钟可以下载的字节数. 所有电脑共享该设置 (bytes/s).",
|
||||
"gui.computercraft.config.http.bandwidth.global_download.tooltip": "每秒钟内可下载的字节数。此值在所有计算机之间共享。(字节/秒)",
|
||||
"gui.computercraft.config.http.bandwidth.global_upload": "全局上传限速",
|
||||
"gui.computercraft.config.http.bandwidth.global_upload.tooltip": "每秒钟可以上传的字节数. 所有电脑共享该设置 (bytes/s).",
|
||||
"gui.computercraft.config.http.bandwidth.tooltip": "限制电脑可以使用的带宽.",
|
||||
"gui.computercraft.config.http.bandwidth.global_upload.tooltip": "每秒钟内可上传的字节数。此值在所有计算机之间共享。(字节/秒)",
|
||||
"gui.computercraft.config.http.bandwidth.tooltip": "限制计算机可以使用的带宽。",
|
||||
"gui.computercraft.config.http.enabled": "启用HTTP API",
|
||||
"gui.computercraft.config.http.enabled.tooltip": "在计算机上启用“http”API。禁用此功能还会禁用许多用户依赖的“pastebin”和“wget”程序。建议保持此功能开启并使用“规则”配置选项来实施更精细的控制。",
|
||||
"gui.computercraft.config.http.max_requests": "最大并发请求数",
|
||||
@@ -112,7 +112,7 @@
|
||||
"gui.computercraft.config.http.proxy.tooltip": "通过代理服务器传输HTTP和WebSocket请求。仅影响将“use_proxy”设为true(默认关闭)的HTTP规则。\n如果代理需要认证,请在与“computercraft-server.toml”相同的目录中创建一个“computercraft-proxy.pw”文件,其中包含以冒号分隔的用户名和密码,例如“myuser:mypassword”。对于SOCKS4代理,只需要用户名。",
|
||||
"gui.computercraft.config.http.proxy.type": "代理类型",
|
||||
"gui.computercraft.config.http.proxy.type.tooltip": "代理使用的协议.",
|
||||
"gui.computercraft.config.http.rules": "允许/阻止规则",
|
||||
"gui.computercraft.config.http.rules": "允许/拒绝规则",
|
||||
"gui.computercraft.config.http.rules.tooltip": "控制特定域或IP的“http”API行为的规则列表。每条规则匹配一个主机名和一个可选端口,然后为请求设置多个属性。规则按顺序进行评估,这意味着较早的规则将覆盖较晚的规则。\n\n有效属性:\n —“host”(必需):此规则匹配的域或 IP 地址。这可能是域名(“pastebin.com”)、通配符(“*.pastebin.com”)或 CIDR 表示法(“127.0.0.0/8”)。\n —“port”(可选):仅匹配特定端口的请求,例如80或443。\n\n —“action”(可选):允许还是拒绝此请求。\n —“max_download”(可选):计算机在此请求中可以下载的最大大小(以字节为单位)。\n —“max_upload”(可选):计算机在此请求中可以上传的最大大小(以字节为单位)。\n —“max_websocket_message”(可选):计算机在一个WebSocket数据包中可以发送或接收的最大大小(以字节为单位)。\n —“use_proxy”(可选):如果已配置,则启用HTTP/SOCKS代理。",
|
||||
"gui.computercraft.config.http.tooltip": "控制HTTP API",
|
||||
"gui.computercraft.config.http.websocket_enabled": "启用websockets",
|
||||
@@ -121,11 +121,11 @@
|
||||
"gui.computercraft.config.log_computer_errors.tooltip": "记录外设和其他Lua对象抛出的异常。这可让Mod作者更轻松地调试问题,但如果人们使用有缺陷的方法,则可能导致日志垃圾。",
|
||||
"gui.computercraft.config.maximum_open_files": "每台计算机打开的最大文件数",
|
||||
"gui.computercraft.config.maximum_open_files.tooltip": "设置计算机可同时打开的文件数。设为0表示无限制。",
|
||||
"gui.computercraft.config.monitor_distance": "监视器距离",
|
||||
"gui.computercraft.config.monitor_distance.tooltip": "监视器渲染的最大距离。默认为标准图块实体限制,但如果你希望建造更大的监视器,则可以扩展。",
|
||||
"gui.computercraft.config.monitor_renderer": "监视器渲染器",
|
||||
"gui.computercraft.config.monitor_renderer.tooltip": "用于监视器的渲染器。通常,应将其保持在“最佳”状态——如果监视器存在性能问题,你可以尝试其他渲染器。",
|
||||
"gui.computercraft.config.peripheral": "外围设备",
|
||||
"gui.computercraft.config.monitor_distance": "显示器距离",
|
||||
"gui.computercraft.config.monitor_distance.tooltip": "显示器渲染的最大距离。默认为标准图块实体限制,但如果你希望建造更大的显示器,则可以调高此值。",
|
||||
"gui.computercraft.config.monitor_renderer": "显示器渲染器",
|
||||
"gui.computercraft.config.monitor_renderer.tooltip": "用于显示器的渲染器。通常,应将其保持在“最佳”状态——如果显示器存在性能问题,你可以尝试其他渲染器。",
|
||||
"gui.computercraft.config.peripheral": "外部设备",
|
||||
"gui.computercraft.config.peripheral.command_block_enabled": "启用命令方块外设",
|
||||
"gui.computercraft.config.peripheral.command_block_enabled.tooltip": "启用命令方块外设支持",
|
||||
"gui.computercraft.config.peripheral.max_notes_per_tick": "计算机一次可以播放的最大音符数量",
|
||||
@@ -138,8 +138,8 @@
|
||||
"gui.computercraft.config.peripheral.modem_range.tooltip": "晴朗天气下低海拔无线调制解调器的范围,以米为单位。",
|
||||
"gui.computercraft.config.peripheral.modem_range_during_storm": "调制解调器范围(恶劣天气)",
|
||||
"gui.computercraft.config.peripheral.modem_range_during_storm.tooltip": "暴风雨天气下低海拔无线调制解调器的范围,以米为单位。",
|
||||
"gui.computercraft.config.peripheral.monitor_bandwidth": "监视器带宽",
|
||||
"gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "*每刻*可以发送多少监视器数据的限制。请注意:\n —带宽是在压缩之前测量的,因此发送到客户端的数据较少。\n —这忽略了数据包发送到的玩家数量。为一个玩家更新监视器所消耗的带宽限制与发送到20个玩家的带宽限制相同。\n —全尺寸监视器发送约25kb的数据。因此默认值(1MB)允许在1刻内更新约40个监视器。\n设为0以禁用。",
|
||||
"gui.computercraft.config.peripheral.monitor_bandwidth": "显示器带宽",
|
||||
"gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "*每刻*可以发送多少显示器数据的限制。请注意:\n - 带宽是在压缩之前测量的,因此发送到客户端的数据较少。\n - 这忽略了数据包发送到的玩家数量。为一个玩家更新显示器所消耗的带宽限制与发送到20个玩家的带宽限制相同。\n - 全尺寸显示器发送约25kb的数据。因此默认值(1MB)允许在1刻内更新约40个显示器。\n设为0以禁用。",
|
||||
"gui.computercraft.config.peripheral.tooltip": "与外设相关的各种选项。",
|
||||
"gui.computercraft.config.term_sizes": "终端尺寸",
|
||||
"gui.computercraft.config.term_sizes.computer": "计算机",
|
||||
@@ -148,18 +148,18 @@
|
||||
"gui.computercraft.config.term_sizes.computer.tooltip": "计算机的终端尺寸。",
|
||||
"gui.computercraft.config.term_sizes.computer.width": "终端宽度",
|
||||
"gui.computercraft.config.term_sizes.computer.width.tooltip": "计算机终端宽度",
|
||||
"gui.computercraft.config.term_sizes.monitor": "监视器",
|
||||
"gui.computercraft.config.term_sizes.monitor.height": "最大监视器高度",
|
||||
"gui.computercraft.config.term_sizes.monitor.height.tooltip": "监视器的最大高度",
|
||||
"gui.computercraft.config.term_sizes.monitor.tooltip": "监视器的最大尺寸(以方块为单位)。",
|
||||
"gui.computercraft.config.term_sizes.monitor.width": "最大监视器宽度",
|
||||
"gui.computercraft.config.term_sizes.monitor.width.tooltip": "监视器的最大宽度",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer": "手提计算机",
|
||||
"gui.computercraft.config.term_sizes.monitor": "显示器",
|
||||
"gui.computercraft.config.term_sizes.monitor.height": "最大显示器高度",
|
||||
"gui.computercraft.config.term_sizes.monitor.height.tooltip": "显示器的最大高度",
|
||||
"gui.computercraft.config.term_sizes.monitor.tooltip": "显示器的最大尺寸(以方块为单位)。",
|
||||
"gui.computercraft.config.term_sizes.monitor.width": "最大显示器宽度",
|
||||
"gui.computercraft.config.term_sizes.monitor.width.tooltip": "显示器的最大宽度",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer": "便携式计算机",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height": "终端高度",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "手提计算机终端高度",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.tooltip": "手提计算机的终端尺寸。",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "便携式计算机终端高度",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.tooltip": "便携式计算机终端尺寸",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width": "终端宽度",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "手提计算机终端宽度",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "便携式计算机终端宽度",
|
||||
"gui.computercraft.config.term_sizes.tooltip": "配置各种计算机终端的尺寸。\n终端越大,需要的带宽越多,请谨慎使用。",
|
||||
"gui.computercraft.config.turtle": "海龟",
|
||||
"gui.computercraft.config.turtle.advanced_fuel_limit": "高级海龟燃料限制",
|
||||
@@ -172,14 +172,14 @@
|
||||
"gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "海龟的燃料限制。",
|
||||
"gui.computercraft.config.turtle.tooltip": "与海龟相关的各种选项。",
|
||||
"gui.computercraft.config.upload_max_size": "文件上传大小限制(字节)",
|
||||
"gui.computercraft.config.upload_max_size.tooltip": "文件上传大小限制(以字节为单位)。必须在1KiB到16MiB之间。\n请记住,上传在1刻内处理——大文件或不佳的网络性能可能会使网络线程停滞。并且注意磁盘空间!",
|
||||
"gui.computercraft.config.upload_max_size.tooltip": "文件上传大小限制(以字节为单位)。必须在1KiB到16MiB之间。\n请记住,上传在1刻内处理——大文件或不佳的网络性能可能会使网络线程停滞。记得注意软盘空间!",
|
||||
"gui.computercraft.config.upload_nag_delay": "上传延迟",
|
||||
"gui.computercraft.config.upload_nag_delay.tooltip": "通知未处理的导入之前延迟的秒数。设为0以禁用。",
|
||||
"gui.computercraft.pocket_computer_overlay": "手提计算机已打开。按ESC键关闭。",
|
||||
"gui.computercraft.pocket_computer_overlay": "便携式计算机已打开。按ESC键可关闭。",
|
||||
"gui.computercraft.terminal": "计算机终端",
|
||||
"gui.computercraft.tooltip.computer_id": "计算机ID: %s",
|
||||
"gui.computercraft.tooltip.copy": "复制到剪贴板",
|
||||
"gui.computercraft.tooltip.disk_id": "磁盘ID: %s",
|
||||
"gui.computercraft.tooltip.disk_id": "软盘ID:%s",
|
||||
"gui.computercraft.tooltip.terminate": "停止当前运行的代码",
|
||||
"gui.computercraft.tooltip.terminate.key": "按住Ctrl+T",
|
||||
"gui.computercraft.tooltip.turn_off": "关闭这台计算机",
|
||||
@@ -195,19 +195,19 @@
|
||||
"gui.computercraft.upload.no_response": "传输文件",
|
||||
"gui.computercraft.upload.no_response.msg": "你的计算机尚未使用你传输的文件。你可能需要运行%s程序并重试。",
|
||||
"item.computercraft.disk": "软盘",
|
||||
"item.computercraft.pocket_computer_advanced": "高级手提计算机",
|
||||
"item.computercraft.pocket_computer_advanced.upgraded": "高级%s手提计算机",
|
||||
"item.computercraft.pocket_computer_normal": "手提计算机",
|
||||
"item.computercraft.pocket_computer_normal.upgraded": "%s手提计算机",
|
||||
"item.computercraft.pocket_computer_advanced": "高级便携式计算机",
|
||||
"item.computercraft.pocket_computer_advanced.upgraded": "高级便携式计算机(%s)",
|
||||
"item.computercraft.pocket_computer_normal": "便携式计算机",
|
||||
"item.computercraft.pocket_computer_normal.upgraded": "便携式计算机(%s)",
|
||||
"item.computercraft.printed_book": "打印书",
|
||||
"item.computercraft.printed_page": "打印纸",
|
||||
"item.computercraft.printed_pages": "打印纸簇",
|
||||
"item.computercraft.printed_pages": "一摞打印纸",
|
||||
"item.computercraft.treasure_disk": "软盘",
|
||||
"itemGroup.computercraft": "ComputerCraft",
|
||||
"tag.item.computercraft.computer": "计算机",
|
||||
"tag.item.computercraft.disks": "磁盘",
|
||||
"tag.item.computercraft.disks": "软盘",
|
||||
"tag.item.computercraft.dyeable": "可染色物品",
|
||||
"tag.item.computercraft.monitor": "监视器",
|
||||
"tag.item.computercraft.monitor": "显示器",
|
||||
"tag.item.computercraft.pocket_computers": "便携式计算机",
|
||||
"tag.item.computercraft.turtle": "海龟",
|
||||
"tag.item.computercraft.turtle_can_place": "可放置海龟物品",
|
||||
@@ -220,12 +220,12 @@
|
||||
"tracking_field.computercraft.http_requests.name": "HTTP请求",
|
||||
"tracking_field.computercraft.http_upload.name": "HTTP上传",
|
||||
"tracking_field.computercraft.max": "%s (最大)",
|
||||
"tracking_field.computercraft.peripheral.name": "外部设备呼叫",
|
||||
"tracking_field.computercraft.peripheral.name": "外部设备调用",
|
||||
"tracking_field.computercraft.server_tasks.name": "服务器任务",
|
||||
"tracking_field.computercraft.turtle_ops.name": "海龟行动",
|
||||
"tracking_field.computercraft.turtle_ops.name": "海龟操作",
|
||||
"tracking_field.computercraft.websocket_incoming.name": "Websocket传入",
|
||||
"tracking_field.computercraft.websocket_outgoing.name": "Websocket传出",
|
||||
"upgrade.computercraft.speaker.adjective": "喧闹",
|
||||
"upgrade.computercraft.speaker.adjective": "嘈杂",
|
||||
"upgrade.computercraft.wireless_modem_advanced.adjective": "末影",
|
||||
"upgrade.computercraft.wireless_modem_normal.adjective": "无线",
|
||||
"upgrade.minecraft.crafting_table.adjective": "合成",
|
||||
|
@@ -17,8 +17,8 @@ accessible field net/minecraft/client/gui/components/ChatComponent allMessages L
|
||||
|
||||
# ItemPocketRenderer/ItemPrintoutRenderer
|
||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer calculateMapTilt (F)F
|
||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderMapHand (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;ILnet/minecraft/world/entity/HumanoidArm;)V
|
||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderPlayerArm (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;IFFLnet/minecraft/world/entity/HumanoidArm;)V
|
||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderMapHand (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/world/entity/HumanoidArm;)V
|
||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderPlayerArm (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;IFFLnet/minecraft/world/entity/HumanoidArm;)V
|
||||
|
||||
# SpeakerInstance/SpeakerManager
|
||||
accessible method com/mojang/blaze3d/audio/Channel pumpBuffers (I)V
|
||||
|
@@ -31,8 +31,8 @@ public @interface WithMinecraft {
|
||||
}
|
||||
|
||||
public static void bootstrap() {
|
||||
SharedConstants.tryDetectVersion();
|
||||
ServiceLoader.load(SetupHook.class, SetupHook.class.getClassLoader()).forEach(SetupHook::run);
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import net.minecraft.gametest.framework.GameTestServer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.Services;
|
||||
import net.minecraft.server.WorldStem;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
|
||||
import net.minecraft.server.level.progress.LevelLoadListener;
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -22,7 +22,10 @@ import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
@Mixin(GameTestServer.class)
|
||||
abstract class GameTestServerMixin extends MinecraftServer {
|
||||
GameTestServerMixin(Thread serverThread, LevelStorageSource.LevelStorageAccess storageSource, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer fixerUpper, Services services, ChunkProgressListenerFactory progressListenerFactory) {
|
||||
GameTestServerMixin(
|
||||
Thread serverThread, LevelStorageSource.LevelStorageAccess storageSource, PackRepository packRepository,
|
||||
WorldStem worldStem, Proxy proxy, DataFixer fixerUpper, Services services, LevelLoadListener progressListenerFactory
|
||||
) {
|
||||
super(serverThread, storageSource, packRepository, worldStem, proxy, fixerUpper, services, progressListenerFactory);
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,7 @@ import dan200.computercraft.gametest.api.*
|
||||
import dan200.computercraft.shared.ModRegistry
|
||||
import dan200.computercraft.test.core.assertArrayEquals
|
||||
import dan200.computercraft.test.core.computer.getApi
|
||||
import net.minecraft.client.input.KeyEvent
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.gametest.framework.GameTestHelper
|
||||
@@ -155,8 +156,8 @@ class Computer_Test {
|
||||
// Press a key on the client
|
||||
thenOnClient {
|
||||
val screen = minecraft.screen as AbstractComputerScreen<*>
|
||||
screen.keyPressed(GLFW.GLFW_KEY_A, 0, 0)
|
||||
screen.keyReleased(GLFW.GLFW_KEY_A, 0, 0)
|
||||
screen.keyPressed(KeyEvent(GLFW.GLFW_KEY_A, 0, 0))
|
||||
screen.keyReleased(KeyEvent(GLFW.GLFW_KEY_A, 0, 0))
|
||||
}
|
||||
// And assert it is handled and sent back to the client
|
||||
thenIdle(2)
|
||||
|
@@ -122,7 +122,7 @@ class Disk_Drive_Test {
|
||||
thenWaitUntil {
|
||||
val drive = helper.getBlockEntity(drivePos, DiskDriveBlockEntity::class.java)
|
||||
if (!drive.getItem(0).has(ModRegistry.DataComponents.DISK_ID.get())) {
|
||||
helper.fail("Disk has no item", drivePos)
|
||||
helper.abort("Disk has no item", drivePos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -45,7 +45,7 @@ class Monitor_Test {
|
||||
val tile = context.getBlockEntity(pos, MonitorBlockEntity::class.java)
|
||||
|
||||
if (tile.width != 1 || tile.height != 1) {
|
||||
context.fail("Tile has width and height of ${tile.width}x${tile.height}, but should be 1x1", pos)
|
||||
context.abort("Tile has width and height of ${tile.width}x${tile.height}, but should be 1x1", pos)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -35,7 +35,9 @@ class Recipe_Test {
|
||||
|
||||
val profile = GameProfile(UUID.fromString("f3c8d69b-0776-4512-8434-d1b2165909eb"), "dan200")
|
||||
|
||||
val tag = DataComponentPatch.builder().set(DataComponents.PROFILE, ResolvableProfile(profile)).build()
|
||||
val tag =
|
||||
DataComponentPatch.builder().set(DataComponents.PROFILE, ResolvableProfile.createResolved(profile))
|
||||
.build()
|
||||
assertEquals(tag, result.componentsPatch, "Expected NBT tags to be the same")
|
||||
}
|
||||
}
|
||||
|
@@ -680,7 +680,7 @@ class Turtle_Test {
|
||||
|
||||
val villager = helper.getEntity(EntityType.VILLAGER)
|
||||
val expectedY = helper.absolutePos(pos).y - 0.125
|
||||
if (villager.y < expectedY) helper.fail("Expected villager at y>=$expectedY, but at ${villager.y}", pos)
|
||||
if (villager.y < expectedY) helper.abort("Expected villager at y>=$expectedY, but at ${villager.y}", pos)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,7 +697,7 @@ class Turtle_Test {
|
||||
helper.assertEntityNotPresent(EntityType.SHEEP)
|
||||
val count = helper.getBlockEntity(turtlePos, TurtleBlockEntity::class.java)
|
||||
.countItem(Items.WHITE_WOOL)
|
||||
if (count == 0) helper.fail("Expected turtle to have white wool", turtlePos)
|
||||
if (count == 0) helper.abort("Expected turtle to have white wool", turtlePos)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@ fun Minecraft.isRenderingStable(): Boolean = (this as MinecraftExtensions).`comp
|
||||
fun GameTestSequence.thenOnClient(task: ClientTestHelper.() -> Unit): GameTestSequence {
|
||||
var future: CompletableFuture<Void>? = null
|
||||
thenExecute { future = Minecraft.getInstance().submit { task(ClientTestHelper()) } }
|
||||
thenWaitUntil { if (!future!!.isDone) fail("Not done task yet") }
|
||||
thenWaitUntil { if (!future!!.isDone) abort("Not done task yet") }
|
||||
thenExecute {
|
||||
try {
|
||||
future!!.get()
|
||||
@@ -59,10 +59,10 @@ fun GameTestSequence.thenScreenshot(name: String? = null, showGui: Boolean = fal
|
||||
thenWaitUntil {
|
||||
if (Minecraft.getInstance().isRenderingStable()) {
|
||||
val idleFor = ++counter
|
||||
if (idleFor <= 20) fail("Only idle for $idleFor ticks")
|
||||
if (idleFor <= 20) abort("Only idle for $idleFor ticks")
|
||||
} else {
|
||||
counter = 0
|
||||
fail("Waiting for client to finish rendering")
|
||||
abort("Waiting for client to finish rendering")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ fun GameTestSequence.thenScreenshot(name: String? = null, showGui: Boolean = fal
|
||||
// Take a screenshot and wait for it to have finished.
|
||||
val hasScreenshot = AtomicBoolean()
|
||||
thenOnClient { screenshot("$fullName.png") { hasScreenshot.set(true) } }
|
||||
thenWaitUntil { if (!hasScreenshot.get()) fail("Screenshot does not exist") }
|
||||
thenWaitUntil { if (!hasScreenshot.get()) abort("Screenshot does not exist") }
|
||||
thenOnClient { minecraft.options.hideGui = false }
|
||||
|
||||
return this
|
||||
@@ -92,7 +92,7 @@ fun ServerPlayer.setupForTest() {
|
||||
*/
|
||||
fun GameTestHelper.positionAtArmorStand() {
|
||||
val stand = getEntity(EntityType.ARMOR_STAND)
|
||||
val player = level.randomPlayer ?: fail("Player does not exist")
|
||||
val player = level.randomPlayer ?: abort("Player does not exist")
|
||||
|
||||
player.setupForTest()
|
||||
player.connection.teleport(stand.x, stand.y, stand.z, stand.yRot, stand.xRot)
|
||||
@@ -103,7 +103,7 @@ fun GameTestHelper.positionAtArmorStand() {
|
||||
*/
|
||||
fun GameTestHelper.positionAt(pos: BlockPos, yRot: Float = 0.0f, xRot: Float = 0.0f) {
|
||||
val absolutePos = absolutePos(pos)
|
||||
val player = level.randomPlayer ?: fail("Player does not exist")
|
||||
val player = level.randomPlayer ?: abort("Player does not exist")
|
||||
|
||||
player.setupForTest()
|
||||
player.connection.teleport(absolutePos.x + 0.5, absolutePos.y + 0.5, absolutePos.z + 0.5, yRot, xRot)
|
||||
|
@@ -97,11 +97,11 @@ fun GameTestSequence.thenComputerOk(name: String? = null, marker: String = Compu
|
||||
|
||||
thenWaitUntil {
|
||||
val computer = ComputerState.get(label)
|
||||
if (computer == null || !computer.isDone(marker)) fail("Computer '$label' has not reached $marker yet.")
|
||||
if (computer == null || !computer.isDone(marker)) abort("Computer '$label' has not reached $marker yet.")
|
||||
}
|
||||
thenExecuteFailFast {
|
||||
val error = ComputerState.get(label)!!.check(marker)
|
||||
if (error != null) fail(error)
|
||||
if (error != null) abort(error)
|
||||
}
|
||||
return this
|
||||
}
|
||||
@@ -128,7 +128,7 @@ fun GameTestSequence.thenOnComputer(name: String? = null, action: suspend LuaTas
|
||||
thenWaitUntil {
|
||||
if (!monitor!!.isFinished) {
|
||||
val runningFor = (test as GameTestInfoAccessor).`computercraft$getTick`() - self.lastTick
|
||||
fail("Computer '$label' has not finished yet (running for $runningFor ticks).")
|
||||
abort("Computer '$label' has not finished yet (running for $runningFor ticks).")
|
||||
}
|
||||
}
|
||||
thenExecuteFailFast { monitor!!.check() }
|
||||
@@ -155,25 +155,25 @@ fun GameTestHelper.immediate(run: () -> Unit) {
|
||||
// Helper functions for failing tests
|
||||
|
||||
/** Raise a [GameTestAssertException]. */
|
||||
fun GameTestHelper.fail(message: String): Nothing = throw assertionException(Component.literal(message))
|
||||
fun GameTestHelper.abort(message: String): Nothing = throw assertionException(Component.literal(message))
|
||||
|
||||
/** Raise a [GameTestAssertException] at a position. */
|
||||
fun GameTestHelper.fail(message: String, pos: BlockPos): Nothing =
|
||||
fun GameTestHelper.abort(message: String, pos: BlockPos): Nothing =
|
||||
throw assertionException(pos, Component.literal(message))
|
||||
|
||||
/** Assert a condition is true, or raise a [GameTestAssertException] if not. */
|
||||
fun GameTestHelper.assertTrue(condition: Boolean, message: String) = assertTrue(condition, Component.literal(message))
|
||||
|
||||
/** Raise a [GameTestAssertException]. */
|
||||
fun GameTestSequence.fail(message: String): Nothing =
|
||||
fun GameTestSequence.abort(message: String): Nothing =
|
||||
throw GameTestAssertException(
|
||||
Component.literal(message),
|
||||
((this as GameTestSequenceAccessor).parent as GameTestInfoAccessor).`computercraft$getTick`(),
|
||||
)
|
||||
|
||||
/** Fail with an optional context message. */
|
||||
private fun GameTestHelper.fail(message: String?, detail: String, pos: BlockPos): Nothing {
|
||||
fail(if (message.isNullOrEmpty()) detail else "$message: $detail", pos)
|
||||
private fun GameTestHelper.abort(message: String?, detail: String, pos: BlockPos): Nothing {
|
||||
abort(if (message.isNullOrEmpty()) detail else "$message: $detail", pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -186,7 +186,7 @@ fun GameTestHelper.assertBlockIs(pos: BlockPos, predicate: (BlockState) -> Boole
|
||||
*/
|
||||
fun GameTestHelper.assertBlockIs(pos: BlockPos, predicate: (BlockState) -> Boolean, message: String) {
|
||||
val state = getBlockState(pos)
|
||||
if (!predicate(state)) fail(message, state.toString(), pos)
|
||||
if (!predicate(state)) abort(message, state.toString(), pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,9 +196,9 @@ fun <T : Comparable<T>> GameTestHelper.assertBlockHas(pos: BlockPos, property: P
|
||||
val state = getBlockState(pos)
|
||||
if (!state.hasProperty(property)) {
|
||||
val id = RegistryHelper.getKeyOrThrow(BuiltInRegistries.BLOCK, state.block)
|
||||
fail(message, "block $id does not have property ${property.name}", pos)
|
||||
abort(message, "block $id does not have property ${property.name}", pos)
|
||||
} else if (state.getValue(property) != value) {
|
||||
fail(message, "${property.name} is ${state.getValue(property)}, expected $value", pos)
|
||||
abort(message, "${property.name} is ${state.getValue(property)}, expected $value", pos)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,8 +208,8 @@ fun <T : Comparable<T>> GameTestHelper.assertBlockHas(pos: BlockPos, property: P
|
||||
fun GameTestHelper.getContainerAt(pos: BlockPos): Container =
|
||||
when (val container: BlockEntity? = level.getBlockEntity(absolutePos(pos))) {
|
||||
is Container -> container
|
||||
null -> fail("Expected a container at $pos, found nothing", pos)
|
||||
else -> fail("Expected a container at $pos, found ${getName(container.type)}", pos)
|
||||
null -> abort("Expected a container at $pos, found nothing", pos)
|
||||
else -> abort("Expected a container at $pos, found ${getName(container.type)}", pos)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,7 +254,7 @@ private fun GameTestHelper.assertContainerExactlyImpl(pos: BlockPos, container:
|
||||
|
||||
if (slot >= 0) {
|
||||
val invItems = (0 until container.containerSize).map { container.getItem(it) }.dropLastWhile { it.isEmpty }
|
||||
fail(
|
||||
abort(
|
||||
"""
|
||||
Items do not match (first mismatch at slot $slot).
|
||||
Expected: ${formatItems(items)}
|
||||
@@ -278,15 +278,15 @@ fun GameTestHelper.assertPeripheral(pos: BlockPos, direction: Direction = Direct
|
||||
val peripheral = getPeripheralAt(pos, direction)
|
||||
val block = getBlockState(pos).block.name.string
|
||||
when {
|
||||
peripheral == null -> fail("No peripheral for '$block'", pos)
|
||||
peripheral.type != type -> fail("Peripheral for '$block' is of type ${peripheral.type}, expected $type", pos)
|
||||
peripheral == null -> abort("No peripheral for '$block'", pos)
|
||||
peripheral.type != type -> abort("Peripheral for '$block' is of type ${peripheral.type}, expected $type", pos)
|
||||
}
|
||||
}
|
||||
|
||||
fun GameTestHelper.assertNoPeripheral(pos: BlockPos, direction: Direction = Direction.UP) {
|
||||
val peripheral = getPeripheralAt(pos, direction)
|
||||
val block = getBlockState(pos).block.name
|
||||
if (peripheral != null) fail("Expected no peripheral for '$block', got a ${peripheral.type}", pos)
|
||||
if (peripheral != null) abort("Expected no peripheral for '$block', got a ${peripheral.type}", pos)
|
||||
}
|
||||
|
||||
fun GameTestHelper.assertExactlyItems(vararg expected: ItemStack, message: String? = null) {
|
||||
@@ -295,7 +295,7 @@ fun GameTestHelper.assertExactlyItems(vararg expected: ItemStack, message: Strin
|
||||
if (!matcher.matches(actual)) {
|
||||
val description = StringDescription()
|
||||
matcher.describeMismatch(actual, description)
|
||||
fail(if (message.isNullOrEmpty()) description.toString() else "$message: $description")
|
||||
abort(if (message.isNullOrEmpty()) description.toString() else "$message: $description")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ fun GameTestHelper.assertExactlyItems(vararg expected: ItemStack, message: Strin
|
||||
fun GameTestHelper.assertItemEntityCountIs(expected: Item, count: Int) {
|
||||
val actualCount = getEntities(EntityType.ITEM).sumOf { if (it.item.`is`(expected)) it.item.count else 0 }
|
||||
if (actualCount != count) {
|
||||
fail("Expected $count ${ItemStack(expected).itemName.string} items to exist (found $actualCount)")
|
||||
abort("Expected $count ${ItemStack(expected).itemName.string} items to exist (found $actualCount)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,9 +318,9 @@ private fun getName(type: BlockEntityType<*>): ResourceLocation =
|
||||
fun <T : Entity> GameTestHelper.getEntity(type: EntityType<T>): T {
|
||||
val entities = getEntities(type)
|
||||
when (entities.size) {
|
||||
0 -> fail("No $type entities")
|
||||
0 -> abort("No $type entities")
|
||||
1 -> return entities[0]
|
||||
else -> fail("Multiple $type entities (${entities.size} in bounding box)")
|
||||
else -> abort("Multiple $type entities (${entities.size} in bounding box)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ fun GameTestHelper.assertNotCraftable(vararg items: ItemStack) {
|
||||
|
||||
val recipe = level.server.recipeManager.getRecipeFor(RecipeType.CRAFTING, input, level)
|
||||
|
||||
if (recipe.isPresent) fail("Expected no recipe to match $items")
|
||||
if (recipe.isPresent) abort("Expected no recipe to match $items")
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,7 +381,7 @@ fun GameTestHelper.craftItem(vararg items: ItemStack): ItemStack {
|
||||
val input = CraftingInput.of(3, 3, container)
|
||||
|
||||
val recipe = level.server.recipeManager.getRecipeFor(RecipeType.CRAFTING, input, level).getOrNull()
|
||||
?: fail("No recipe matches $items")
|
||||
?: throw assertionException("No recipe matches $items")
|
||||
return recipe.value.assemble(input, level.registryAccess())
|
||||
}
|
||||
|
||||
|
@@ -75,7 +75,7 @@ object TestHooks {
|
||||
}
|
||||
|
||||
fun getTestOrigin(server: MinecraftServer): BlockPos {
|
||||
val spawn = server.overworld().sharedSpawnPos
|
||||
val spawn = server.respawnData.pos()
|
||||
return BlockPos(spawn.x, -59, spawn.y)
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ object TestHooks {
|
||||
LOG.info("Cleaning up after last run")
|
||||
|
||||
val level = server.overworld()
|
||||
StructureUtils.findTestBlocks(getTestOrigin(server), 200, level).forEach { pos ->
|
||||
StructureUtils.findTestBlocks(getTestOrigin(server), 200, level).toList().forEach { pos ->
|
||||
val test = level.getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK).getOrNull() ?: return@forEach
|
||||
StructureUtils.clearSpaceForStructure(test.structureBoundingBox, level)
|
||||
}
|
||||
|
@@ -1,3 +1,11 @@
|
||||
# New features in CC: Tweaked 1.116.1
|
||||
|
||||
* Update translations.
|
||||
|
||||
Several bug fixes:
|
||||
* Fix NPE when mcfunction files contain CC commands.
|
||||
* Fix crash in `speaker.playAudio` on noisy pocket computers.
|
||||
|
||||
# New features in CC: Tweaked 1.116.0
|
||||
|
||||
* Add `turtle.getEquippedLeft()` and `turtle.getEquippedRight()`.
|
||||
@@ -5,6 +13,7 @@
|
||||
* Support multi-line strings and comments in `edit`.
|
||||
* Computer and pocket computer terminal sizes can be set with the `computercraft:terminal_size` component.
|
||||
* Border and sidebar textures now use vanilla's nine-sliced format.
|
||||
* Allow equipping upgrades on the bottom of a pocket computer.
|
||||
|
||||
Several bug fixes:
|
||||
* Ignore shader compilation errors when running with Pojav.
|
||||
|
@@ -1,21 +1,9 @@
|
||||
New features in CC: Tweaked 1.116.0
|
||||
New features in CC: Tweaked 1.116.1
|
||||
|
||||
* Add `turtle.getEquippedLeft()` and `turtle.getEquippedRight()`.
|
||||
* Add item tags for floppy disks and pocket computers.
|
||||
* Support multi-line strings and comments in `edit`.
|
||||
* Computer and pocket computer terminal sizes can be set with the `computercraft:terminal_size` component.
|
||||
* Border and sidebar textures now use vanilla's nine-sliced format.
|
||||
* Update translations.
|
||||
|
||||
Several bug fixes:
|
||||
* Ignore shader compilation errors when running with Pojav.
|
||||
* Fix several issues with character input.
|
||||
* Fix pocket computer dyes being lost when equipping/unequipping upgrades.
|
||||
* Fix superflous warnings from allocation tracking.
|
||||
* Fix `__lt`/`__le` not working on heterogeneous types.
|
||||
* Many documentation fixes (Lemmmy, matematikaadit, McJack12).
|
||||
* Fix `0` being treated as a valid colour in `window` and `colour.toBlit`.
|
||||
* Fix out-of-bounds when pasting too lon text.
|
||||
* Fix syntax highlighting of string escapes (LorneHyde).
|
||||
* Fix sidebar texture of advanced computers being offset.
|
||||
* Fix NPE when mcfunction files contain CC commands.
|
||||
* Fix crash in `speaker.playAudio` on noisy pocket computers.
|
||||
|
||||
Type "help changelog" to see the full version history.
|
||||
|
@@ -74,7 +74,6 @@ configurations {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
clientCompileOnly(variantOf(libs.emi) { classifier("api") })
|
||||
modCompileOnly(libs.bundles.externalMods.fabric.compile) {
|
||||
exclude("net.fabricmc", "fabric-loader")
|
||||
exclude("net.fabricmc.fabric-api")
|
||||
|
@@ -12,7 +12,6 @@ import dan200.computercraft.api.client.FabricComputerCraftAPIClient;
|
||||
import dan200.computercraft.client.platform.ClientNetworkContextImpl;
|
||||
import dan200.computercraft.client.platform.FabricModelKey;
|
||||
import dan200.computercraft.client.platform.ModelKey;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.ComputerCraft;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.config.ConfigSpec;
|
||||
@@ -25,12 +24,13 @@ import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlu
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.UnbakedExtraModel;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.BlockRenderLayerMap;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.SpecialGuiElementRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.item.ItemTintSources;
|
||||
import net.minecraft.client.gui.components.debug.DebugScreenEntries;
|
||||
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
|
||||
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
@@ -41,7 +41,6 @@ import net.minecraft.client.renderer.item.properties.conditional.ConditionalItem
|
||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperties;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ResolvableModel;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -49,8 +48,6 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
public class ComputerCraftClient {
|
||||
public static void init() {
|
||||
var clientNetwork = new ClientNetworkContextImpl();
|
||||
@@ -67,9 +64,10 @@ public class ComputerCraftClient {
|
||||
ClientRegistry.registerItemColours(ItemTintSources.ID_MAPPER::put);
|
||||
ClientRegistry.registerSelectItemProperties(SelectItemModelProperties.ID_MAPPER::put);
|
||||
ClientRegistry.registerConditionalItemProperties(ConditionalItemModelProperties.ID_MAPPER::put);
|
||||
ClientRegistry.registerLayerDefinitions((id, factory) -> EntityModelLayerRegistry.registerModelLayer(id, factory::get));
|
||||
|
||||
PreparableModelLoadingPlugin.register(
|
||||
ClientRegistry::gatherExtraModels,
|
||||
(state, executor) -> ClientRegistry.gatherExtraModels(state.resourceManager(), executor),
|
||||
(state, context) -> ClientRegistry.registerExtraModels(new ClientRegistry.RegisterExtraModels() {
|
||||
@Override
|
||||
public <U, T> void register(ModelKey<T> key, U unbaked, BiConsumer<U, ResolvableModel.Resolver> resolve, BiFunction<U, ModelBaker, T> bake) {
|
||||
@@ -93,6 +91,7 @@ public class ComputerCraftClient {
|
||||
|
||||
ClientTickEvents.START_CLIENT_TICK.register(client -> ClientHooks.onTick());
|
||||
// This isn't 100% consistent with Forge, but not worth a mixin.
|
||||
/*
|
||||
WorldRenderEvents.START.register(context -> ClientHooks.onRenderTick());
|
||||
WorldRenderEvents.BLOCK_OUTLINE.register((context, hitResult) -> {
|
||||
var hit = Minecraft.getInstance().hitResult;
|
||||
@@ -102,6 +101,9 @@ public class ComputerCraftClient {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
ClientRegistry.registerDebugScreenEntries(DebugScreenEntries::register);
|
||||
|
||||
// Register our open folder command
|
||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
|
||||
|
@@ -1,23 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import dan200.computercraft.client.ClientHooks;
|
||||
import net.minecraft.client.gui.components.DebugScreenOverlay;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(DebugScreenOverlay.class)
|
||||
class DebugScreenOverlayMixin {
|
||||
@Inject(method = "getSystemInformation", at = @At("RETURN"))
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
private void appendBlockDebugInfo(CallbackInfoReturnable<List<String>> cir) {
|
||||
ClientHooks.addBlockDebugInfo(cir.getReturnValue()::add);
|
||||
}
|
||||
}
|
@@ -7,9 +7,10 @@ package dan200.computercraft.mixin.client;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.ClientHooks;
|
||||
import dan200.computercraft.client.ExtendedItemFrameRenderStateHolder;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.ItemFrameRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||
import net.minecraft.client.renderer.state.CameraRenderState;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -21,14 +22,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@SuppressWarnings("UnusedMethod")
|
||||
class ItemFrameRendererMixin {
|
||||
@Inject(
|
||||
method = "render(Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V",
|
||||
method = "submit(Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;Lnet/minecraft/client/renderer/state/CameraRenderState;)V",
|
||||
at = @At(value = "FIELD", target = "Lnet/minecraft/client/renderer/entity/state/ItemFrameRenderState;mapId:Lnet/minecraft/world/level/saveddata/maps/MapId;", opcode = Opcodes.GETFIELD, ordinal = 1),
|
||||
cancellable = true
|
||||
)
|
||||
@SuppressWarnings("unused")
|
||||
private void render(ItemFrameRenderState frame, PoseStack pose, MultiBufferSource buffers, int light, CallbackInfo ci) {
|
||||
private void submit(ItemFrameRenderState frame, PoseStack pose, SubmitNodeCollector buffers, CameraRenderState camera, CallbackInfo ci) {
|
||||
var state = ((ExtendedItemFrameRenderStateHolder) frame).computercraft$state();
|
||||
if (ClientHooks.onRenderItemFrame(pose, buffers, frame, state, light)) {
|
||||
if (ClientHooks.onRenderItemFrame(pose, buffers, frame, state)) {
|
||||
ci.cancel();
|
||||
pose.popPose();
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.ClientHooks;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
@@ -22,9 +22,9 @@ class ItemInHandRendererMixin {
|
||||
@SuppressWarnings("unused")
|
||||
private void onRenderItem(
|
||||
AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float swingProgress, ItemStack stack,
|
||||
float equippedProgress, PoseStack transform, MultiBufferSource buffer, int combinedLight, CallbackInfo ci
|
||||
float equippedProgress, PoseStack transform, SubmitNodeCollector collector, int combinedLight, CallbackInfo ci
|
||||
) {
|
||||
if (ClientHooks.onRenderHeldItem(transform, buffer, combinedLight, hand, pitch, equippedProgress, swingProgress, stack)) {
|
||||
if (ClientHooks.onRenderHeldItem(transform, collector, combinedLight, hand, pitch, equippedProgress, swingProgress, stack)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
@@ -7,7 +7,6 @@
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"client": [
|
||||
"DebugScreenOverlayMixin",
|
||||
"ItemFrameRendererMixin",
|
||||
"ItemFrameRenderStateMixin",
|
||||
"ItemInHandRendererMixin",
|
||||
|
@@ -40,18 +40,14 @@ import net.fabricmc.fabric.api.lookup.v1.item.ItemApiLookup;
|
||||
import net.fabricmc.fabric.api.loot.v3.LootTableEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
|
||||
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
|
||||
import net.fabricmc.fabric.api.resource.v1.ResourceLoader;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ChunkLevel;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
@@ -59,8 +55,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class ComputerCraft {
|
||||
@@ -137,33 +131,19 @@ public class ComputerCraft {
|
||||
entries.getContext(), entries
|
||||
));
|
||||
|
||||
CommonHooks.onDatapackReload((name, listener) -> ResourceManagerHelper.get(PackType.SERVER_DATA).registerReloadListener(new ReloadListener(name, listener)));
|
||||
CommonHooks.onDatapackReload(ResourceLoader.get(PackType.SERVER_DATA)::registerReloader);
|
||||
|
||||
FabricDetailRegistries.FLUID_VARIANT.addProvider(FluidDetails::fill);
|
||||
|
||||
ComputerCraftAPI.registerGenericSource(new InventoryMethods());
|
||||
|
||||
Peripherals.addGenericLookup(InventoryMethods::extractContainer);
|
||||
}
|
||||
|
||||
private static <B extends FriendlyByteBuf, T extends CustomPacketPayload> void registerPayloadType(PayloadTypeRegistry<B> registry, CustomPacketPayload.TypeAndCodec<B, T> type) {
|
||||
registry.register(type.type(), type.codec());
|
||||
|
||||
if (FabricLoader.getInstance().isModLoaded(CreateIntegration.ID)) CreateIntegration.setup();
|
||||
}
|
||||
|
||||
private record ReloadListener(ResourceLocation name, PreparableReloadListener listener)
|
||||
implements IdentifiableResourceReloadListener {
|
||||
|
||||
@Override
|
||||
public ResourceLocation getFabricId() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> reload(PreparationBarrier preparationBarrier, ResourceManager resourceManager, Executor backgroundExecutor, Executor gameExecutor) {
|
||||
return listener.reload(preparationBarrier, resourceManager, backgroundExecutor, gameExecutor);
|
||||
}
|
||||
private static <B extends FriendlyByteBuf, T extends CustomPacketPayload> void registerPayloadType(PayloadTypeRegistry<B> registry, CustomPacketPayload.TypeAndCodec<B, T> type) {
|
||||
registry.register(type.type(), type.codec());
|
||||
}
|
||||
|
||||
private record BlockComponentImpl<T, C extends @Nullable Object>(
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user