mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-11-04 07:32:59 +00:00 
			
		
		
		
	Compare commits
	
		
			59 Commits
		
	
	
		
			v1.21.4-1.
			...
			v1.20.1-1.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					18f3426f1d | ||
| 
						 | 
					0ec46fe38e | ||
| 
						 | 
					569de7fafb | ||
| 
						 | 
					157ce4fa55 | ||
| 
						 | 
					b9ed66983d | ||
| 
						 | 
					d0fbec6c6b | ||
| 
						 | 
					a683697e8c | ||
| 
						 | 
					9e233a916f | ||
| 
						 | 
					5a9e21ccc3 | ||
| 
						 | 
					5f16909d4b | ||
| 
						 | 
					00475b9bb0 | ||
| 
						 | 
					018ce7c8a5 | ||
| 
						 | 
					44726827b4 | ||
| 
						 | 
					3cf914cb4c | ||
| 
						 | 
					180156ff1c | ||
| 
						 | 
					c6ba753568 | ||
| 
						 | 
					9f45c91925 | ||
| 
						 | 
					8344c0a5c2 | ||
| 
						 | 
					a292d33830 | ||
| 
						 | 
					341d1c7bc2 | ||
| 
						 | 
					531eacfac7 | ||
| 
						 | 
					1f3da5205c | ||
| 
						 | 
					798ceefafe | ||
| 
						 | 
					7c0f79fc3c | ||
| 
						 | 
					b35cefc5dd | ||
| 
						 | 
					69353a4fcf | ||
| 
						 | 
					ff363dca5a | ||
| 
						 | 
					1c51282426 | ||
| 
						 | 
					4a3a1c9275 | ||
| 
						 | 
					2557dd0af9 | ||
| 
						 | 
					b5c0c6e104 | ||
| 
						 | 
					876fd8ddb8 | ||
| 
						 | 
					ee3b1343b5 | ||
| 
						 | 
					b440b964b7 | ||
| 
						 | 
					5dfc401b45 | ||
| 
						 | 
					4344c3072f | ||
| 
						 | 
					947001104d | ||
| 
						 | 
					8711512769 | ||
| 
						 | 
					9c0ce27ce6 | ||
| 
						 | 
					c458360b18 | ||
| 
						 | 
					09ad6c1905 | ||
| 
						 | 
					0e1e8a72d3 | ||
| 
						 | 
					7c1e8e1951 | ||
| 
						 | 
					b03546a158 | ||
| 
						 | 
					582713467f | ||
| 
						 | 
					b6f41a0df5 | ||
| 
						 | 
					594738a022 | ||
| 
						 | 
					27f2ab364c | ||
| 
						 | 
					5a43273757 | ||
| 
						 | 
					97e28516fb | ||
| 
						 | 
					676fb5fb53 | ||
| 
						 | 
					63ba3fe274 | ||
| 
						 | 
					749b3df227 | ||
| 
						 | 
					b97634b717 | ||
| 
						 | 
					1b8344d0a3 | ||
| 
						 | 
					b42bc0a01a | ||
| 
						 | 
					0cff73e2fc | ||
| 
						 | 
					a892739f8e | ||
| 
						 | 
					f8785a092f | 
@@ -27,7 +27,7 @@ indent_size = 2
 | 
			
		||||
[*.yml]
 | 
			
		||||
indent_size = 2
 | 
			
		||||
 | 
			
		||||
[{*.kt,*.kts}]
 | 
			
		||||
[*.{kt,kts}]
 | 
			
		||||
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
 | 
			
		||||
ij_kotlin_continuation_indent_size = 4
 | 
			
		||||
ij_kotlin_spaces_around_equality_operators = true
 | 
			
		||||
@@ -39,3 +39,14 @@ ij_kotlin_allow_trailing_comma_on_call_site = true
 | 
			
		||||
ij_kotlin_method_parameters_wrap = off
 | 
			
		||||
ij_kotlin_call_parameters_wrap = off
 | 
			
		||||
ij_kotlin_extends_list_wrap = off
 | 
			
		||||
 | 
			
		||||
ktlint_code_style = intellij_idea
 | 
			
		||||
ktlint_standard_class-naming = disabled
 | 
			
		||||
ktlint_standard_class-signature = disabled
 | 
			
		||||
ktlint_standard_function-naming = disabled
 | 
			
		||||
ktlint_standard_no-wildcard-imports = disabled
 | 
			
		||||
 | 
			
		||||
# FIXME: These two are disable right now as they're over-eager in putting things
 | 
			
		||||
#  on the same line. We should set max_line_length and handle this properly.
 | 
			
		||||
ktlint_standard_function-signature = disabled
 | 
			
		||||
ktlint_standard_function-expression-body = disabled
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								.github/workflows/main-ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/main-ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -14,7 +14,7 @@ jobs:
 | 
			
		||||
    - name: 📥 Set up Java
 | 
			
		||||
      uses: actions/setup-java@v4
 | 
			
		||||
      with:
 | 
			
		||||
        java-version: 17
 | 
			
		||||
        java-version: 21
 | 
			
		||||
        distribution: 'temurin'
 | 
			
		||||
 | 
			
		||||
    - name: 📥 Setup Gradle
 | 
			
		||||
@@ -87,7 +87,7 @@ jobs:
 | 
			
		||||
    - name: 📥 Set up Java
 | 
			
		||||
      uses: actions/setup-java@v4
 | 
			
		||||
      with:
 | 
			
		||||
        java-version: 17
 | 
			
		||||
        java-version: 21
 | 
			
		||||
        distribution: 'temurin'
 | 
			
		||||
 | 
			
		||||
    - name: 📥 Setup Gradle
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/make-doc.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/make-doc.yml
									
									
									
									
										vendored
									
									
								
							@@ -17,7 +17,7 @@ jobs:
 | 
			
		||||
    - name: 📥 Set up Java
 | 
			
		||||
      uses: actions/setup-java@v4
 | 
			
		||||
      with:
 | 
			
		||||
        java-version: 17
 | 
			
		||||
        java-version: 21
 | 
			
		||||
        distribution: 'temurin'
 | 
			
		||||
 | 
			
		||||
    - name: 📥 Setup Gradle
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@ Translations are managed through [CrowdIn], an online interface for managing lan
 | 
			
		||||
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
 | 
			
		||||
 | 
			
		||||
 - Make sure you've got the following software installed:
 | 
			
		||||
   - Java Development Kit 17 (JDK). This can be downloaded from [Adoptium].
 | 
			
		||||
   - Java Development Kit 21 (JDK). This can be downloaded from [Adoptium].
 | 
			
		||||
   - [Git](https://git-scm.com/).
 | 
			
		||||
   - [NodeJS 20 or later][node].
 | 
			
		||||
 | 
			
		||||
@@ -88,8 +88,8 @@ You'll first need to [set up a development environment as above](#setting-up-a-d
 | 
			
		||||
 | 
			
		||||
Once this is set up, you can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code,
 | 
			
		||||
writing the resulting HTML into `./projects/web/build/site`, which can then be opened in a browser. When iterating on
 | 
			
		||||
documentation, you can instead run `./gradlew docWebsite -t`, which will rebuild documentation every time you change a
 | 
			
		||||
file.
 | 
			
		||||
documentation, you can instead run `./gradlew :web:assemble -x :web:compileTeaVM -t`, which will rebuild documentation
 | 
			
		||||
every time you change a file.
 | 
			
		||||
 | 
			
		||||
Documentation is built using [illuaminate] which, while not currently documented (somewhat ironic), is largely the same
 | 
			
		||||
as [ldoc][ldoc]. Documentation comments are written in Markdown, though note that we do not support many GitHub-specific
 | 
			
		||||
@@ -101,7 +101,7 @@ about how you can build on that until you've covered everything!
 | 
			
		||||
 | 
			
		||||
[new-issue]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose "Create a new issue"
 | 
			
		||||
[community]: README.md#community "Get in touch with the community."
 | 
			
		||||
[Adoptium]: https://adoptium.net/temurin/releases?version=17 "Download OpenJDK 17"
 | 
			
		||||
[Adoptium]: https://adoptium.net/temurin/releases?version=21 "Download OpenJDK 21"
 | 
			
		||||
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
 | 
			
		||||
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
 | 
			
		||||
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,11 @@
 | 
			
		||||
 | 
			
		||||
import cc.tweaked.gradle.JUnitExt
 | 
			
		||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI
 | 
			
		||||
import net.fabricmc.loom.util.gradle.SourceSetHelper
 | 
			
		||||
import org.jetbrains.gradle.ext.*
 | 
			
		||||
import org.jetbrains.gradle.ext.Application
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    publishing
 | 
			
		||||
    alias(libs.plugins.taskTree)
 | 
			
		||||
    alias(libs.plugins.githubRelease)
 | 
			
		||||
    alias(libs.plugins.gradleVersions)
 | 
			
		||||
    alias(libs.plugins.versionCatalogUpdate)
 | 
			
		||||
@@ -70,7 +68,7 @@ idea.project.settings.runConfigurations {
 | 
			
		||||
        val fabricProject = evaluationDependsOn(":fabric")
 | 
			
		||||
        val classPathGroup = fabricProject.extensions.getByType<LoomGradleExtensionAPI>().mods
 | 
			
		||||
            .joinToString(File.pathSeparator + File.pathSeparator) { modSettings ->
 | 
			
		||||
                SourceSetHelper.getClasspath(modSettings, project).joinToString(File.pathSeparator) { it.absolutePath }
 | 
			
		||||
                modSettings.modFiles.joinToString(File.pathSeparator) { it.absolutePath }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        vmParameters = "-ea -Dfabric.classPathGroups=$classPathGroup"
 | 
			
		||||
@@ -115,8 +113,12 @@ idea.project.settings.compiler.javac {
 | 
			
		||||
        .toMap()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
repositories() {
 | 
			
		||||
    mavenCentral()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
versionCatalogUpdate {
 | 
			
		||||
    sortByKey = false
 | 
			
		||||
    pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
 | 
			
		||||
    keep { keepUnusedLibraries = true }
 | 
			
		||||
    keep { keepUnusedVersions = true }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ repositories {
 | 
			
		||||
        name = "Fabric"
 | 
			
		||||
        content {
 | 
			
		||||
            includeGroup("net.fabricmc")
 | 
			
		||||
            includeGroup("net.fabricmc.unpick")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -69,6 +70,6 @@ gradlePlugin {
 | 
			
		||||
 | 
			
		||||
versionCatalogUpdate {
 | 
			
		||||
    sortByKey = false
 | 
			
		||||
    keep { keepUnusedLibraries = true }
 | 
			
		||||
    keep { keepUnusedVersions = true }
 | 
			
		||||
    catalogFile = file("../gradle/libs.versions.toml")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,7 @@
 | 
			
		||||
 | 
			
		||||
/** Default configuration for Fabric projects. */
 | 
			
		||||
 | 
			
		||||
import cc.tweaked.gradle.CCTweakedExtension
 | 
			
		||||
import cc.tweaked.gradle.CCTweakedPlugin
 | 
			
		||||
import cc.tweaked.gradle.IdeaRunConfigurations
 | 
			
		||||
import cc.tweaked.gradle.MinecraftConfigurations
 | 
			
		||||
import cc.tweaked.gradle.*
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
    `java-library`
 | 
			
		||||
@@ -67,3 +64,19 @@ dependencies {
 | 
			
		||||
tasks.ideaSyncTask {
 | 
			
		||||
    doLast { IdeaRunConfigurations(project).patch() }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tasks.named("checkDependencyConsistency", DependencyCheck::class.java) {
 | 
			
		||||
    val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
 | 
			
		||||
    // Minecraft depends on lwjgl, but Fabric forces it to a more recent version
 | 
			
		||||
    for (lwjgl in listOf(
 | 
			
		||||
        "lwjgl",
 | 
			
		||||
        "lwjgl-glfw",
 | 
			
		||||
        "lwjgl-jemalloc",
 | 
			
		||||
        "lwjgl-openal",
 | 
			
		||||
        "lwjgl-opengl",
 | 
			
		||||
        "lwjgl-stb",
 | 
			
		||||
        "lwjgl-tinyfd",
 | 
			
		||||
    )) {
 | 
			
		||||
        override("org.lwjgl", lwjgl, "3.3.2")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,6 @@
 | 
			
		||||
 | 
			
		||||
import cc.tweaked.gradle.CCTweakedExtension
 | 
			
		||||
import cc.tweaked.gradle.CCTweakedPlugin
 | 
			
		||||
import cc.tweaked.gradle.IdeaRunConfigurations
 | 
			
		||||
import cc.tweaked.gradle.MinecraftConfigurations
 | 
			
		||||
 | 
			
		||||
plugins {
 | 
			
		||||
@@ -20,7 +19,7 @@ val mcVersion: String by extra
 | 
			
		||||
 | 
			
		||||
legacyForge {
 | 
			
		||||
    val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
 | 
			
		||||
    version = "${mcVersion}-${libs.findVersion("forge").get()}"
 | 
			
		||||
    version = "$mcVersion-${libs.findVersion("forge").get()}"
 | 
			
		||||
 | 
			
		||||
    parchment {
 | 
			
		||||
        minecraftVersion = libs.findVersion("parchmentMc").get().toString()
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,8 @@ plugins {
 | 
			
		||||
    checkstyle
 | 
			
		||||
    id("com.diffplug.spotless")
 | 
			
		||||
    id("net.ltgt.errorprone")
 | 
			
		||||
    // Required for cross-project dependencies in Fabric
 | 
			
		||||
    id("net.fabricmc.fabric-loom-companion")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val modVersion: String by extra
 | 
			
		||||
@@ -28,9 +30,9 @@ version = modVersion
 | 
			
		||||
base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
 | 
			
		||||
 | 
			
		||||
java {
 | 
			
		||||
    toolchain {
 | 
			
		||||
        languageVersion= CCTweakedPlugin.JAVA_VERSION
 | 
			
		||||
    }
 | 
			
		||||
    toolchain { languageVersion = CCTweakedPlugin.JDK_VERSION }
 | 
			
		||||
    sourceCompatibility = CCTweakedPlugin.JAVA_VERSION
 | 
			
		||||
    targetCompatibility = CCTweakedPlugin.JAVA_VERSION
 | 
			
		||||
 | 
			
		||||
    withSourcesJar()
 | 
			
		||||
}
 | 
			
		||||
@@ -79,19 +81,31 @@ dependencies {
 | 
			
		||||
// Configure default JavaCompile tasks with our arguments.
 | 
			
		||||
sourceSets.all {
 | 
			
		||||
    tasks.named(compileJavaTaskName, JavaCompile::class.java) {
 | 
			
		||||
        // Processing just gives us "No processor claimed any of these annotations", so skip that!
 | 
			
		||||
        options.compilerArgs.addAll(listOf("-Xlint", "-Xlint:-processing"))
 | 
			
		||||
        // Explicitly set release, as that limits the APIs we can use to the right version of Java.
 | 
			
		||||
        options.release = CCTweakedPlugin.JAVA_TARGET.asInt()
 | 
			
		||||
 | 
			
		||||
        options.compilerArgs.addAll(
 | 
			
		||||
            listOf(
 | 
			
		||||
                "-Xlint",
 | 
			
		||||
                // Processing just gives us "No processor claimed any of these annotations", so skip that!
 | 
			
		||||
                "-Xlint:-processing",
 | 
			
		||||
                // We violate this pattern too often for it to be a helpful warning. Something to improve one day!
 | 
			
		||||
                "-Xlint:-this-escape",
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        options.errorprone {
 | 
			
		||||
            check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
 | 
			
		||||
            check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
 | 
			
		||||
            // Too many false positives right now. Maybe we need an indirection for it later on.
 | 
			
		||||
            check("AssignmentExpression", CheckSeverity.OFF) // I'm a bad person.
 | 
			
		||||
            check("ReferenceEquality", CheckSeverity.OFF)
 | 
			
		||||
            check("EnumOrdinal", CheckSeverity.OFF) // For now. We could replace most of these with EnumMap.
 | 
			
		||||
            check("OperatorPrecedence", CheckSeverity.OFF) // For now.
 | 
			
		||||
            check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
 | 
			
		||||
            check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
 | 
			
		||||
            check("InvalidInlineTag", CheckSeverity.OFF) // Triggered by @snippet. Can be removed on Java 21.
 | 
			
		||||
            option("UnusedMethod:ExemptingMethodAnnotations", "dan200.computercraft.api.lua.LuaFunction")
 | 
			
		||||
 | 
			
		||||
            check("NullAway", CheckSeverity.ERROR)
 | 
			
		||||
            option(
 | 
			
		||||
@@ -114,7 +128,6 @@ tasks.compileTestJava {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
tasks.withType(JavaCompile::class.java).configureEach {
 | 
			
		||||
    options.encoding = "UTF-8"
 | 
			
		||||
}
 | 
			
		||||
@@ -148,7 +161,7 @@ tasks.javadoc {
 | 
			
		||||
    options {
 | 
			
		||||
        val stdOptions = this as StandardJavadocDocletOptions
 | 
			
		||||
        stdOptions.addBooleanOption("Xdoclint:all,-missing", true)
 | 
			
		||||
        stdOptions.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
 | 
			
		||||
        stdOptions.links("https://docs.oracle.com/en/java/javase/21/docs/api/")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -163,7 +176,7 @@ tasks.test {
 | 
			
		||||
 | 
			
		||||
tasks.withType(JacocoReport::class.java).configureEach {
 | 
			
		||||
    reports.xml.required = true
 | 
			
		||||
    reports.html.required =true
 | 
			
		||||
    reports.html.required = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
project.plugins.withType(CCTweakedPlugin::class.java) {
 | 
			
		||||
@@ -187,30 +200,23 @@ spotless {
 | 
			
		||||
    fun FormatExtension.defaults() {
 | 
			
		||||
        endWithNewline()
 | 
			
		||||
        trimTrailingWhitespace()
 | 
			
		||||
        indentWithSpaces(4)
 | 
			
		||||
        leadingTabsToSpaces(4)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    java {
 | 
			
		||||
        defaults()
 | 
			
		||||
        importOrder("", "javax|java", "\\#")
 | 
			
		||||
        removeUnusedImports()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val ktlintConfig = mapOf(
 | 
			
		||||
        "ktlint_standard_no-wildcard-imports" to "disabled",
 | 
			
		||||
        "ktlint_standard_class-naming" to "disabled",
 | 
			
		||||
        "ktlint_standard_function-naming" to "disabled",
 | 
			
		||||
        "ij_kotlin_allow_trailing_comma" to "true",
 | 
			
		||||
        "ij_kotlin_allow_trailing_comma_on_call_site" to "true",
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    kotlinGradle {
 | 
			
		||||
        defaults()
 | 
			
		||||
        ktlint().editorConfigOverride(ktlintConfig)
 | 
			
		||||
        ktlint()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    kotlin {
 | 
			
		||||
        defaults()
 | 
			
		||||
        ktlint().editorConfigOverride(ktlintConfig)
 | 
			
		||||
        ktlint()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
 * See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import cc.tweaked.gradle.CCTweakedPlugin
 | 
			
		||||
import cc.tweaked.gradle.MinecraftConfigurations
 | 
			
		||||
import cc.tweaked.gradle.clientClasses
 | 
			
		||||
import cc.tweaked.gradle.commonClasses
 | 
			
		||||
@@ -52,3 +53,5 @@ dependencies {
 | 
			
		||||
 | 
			
		||||
    testImplementation(testFixtures(project))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
kotlin.compilerOptions.jvmTarget = CCTweakedPlugin.KOTLIN_TARGET
 | 
			
		||||
 
 | 
			
		||||
@@ -223,7 +223,7 @@ abstract class CCTweakedExtension(private val project: Project) {
 | 
			
		||||
        ).resolve().single()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun <T> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
 | 
			
		||||
    private fun <T: Any> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
 | 
			
		||||
        val baseResult = project.providers.exec {
 | 
			
		||||
            commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@
 | 
			
		||||
 | 
			
		||||
package cc.tweaked.gradle
 | 
			
		||||
 | 
			
		||||
import org.gradle.api.JavaVersion
 | 
			
		||||
import org.gradle.api.Plugin
 | 
			
		||||
import org.gradle.api.Project
 | 
			
		||||
import org.gradle.api.plugins.JavaPlugin
 | 
			
		||||
@@ -13,6 +14,7 @@ import org.gradle.plugins.ide.idea.model.IdeaModel
 | 
			
		||||
import org.jetbrains.gradle.ext.IdeaExtPlugin
 | 
			
		||||
import org.jetbrains.gradle.ext.runConfigurations
 | 
			
		||||
import org.jetbrains.gradle.ext.settings
 | 
			
		||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configures projects to match a shared configuration.
 | 
			
		||||
@@ -42,6 +44,17 @@ class CCTweakedPlugin : Plugin<Project> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        val JAVA_VERSION = JavaLanguageVersion.of(17)
 | 
			
		||||
        /**
 | 
			
		||||
         * The version we run with. We use Java 21 here, as our Gradle build requires that.
 | 
			
		||||
         */
 | 
			
		||||
        val JDK_VERSION = JavaLanguageVersion.of(21)
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * The Java version we target. Should be the same as what Minecraft uses.
 | 
			
		||||
         */
 | 
			
		||||
        val JAVA_TARGET = JavaLanguageVersion.of(17)
 | 
			
		||||
 | 
			
		||||
        val JAVA_VERSION = JavaVersion.toVersion(JAVA_TARGET.asInt())
 | 
			
		||||
        val KOTLIN_TARGET = JvmTarget.fromTarget(JAVA_TARGET.toString())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,10 @@ abstract class DependencyCheck : DefaultTask() {
 | 
			
		||||
        overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun override(group: String, module: String, version: String) {
 | 
			
		||||
        overrides.put("$group:$module", version)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Add a configuration to check.
 | 
			
		||||
     */
 | 
			
		||||
 
 | 
			
		||||
@@ -5,10 +5,8 @@
 | 
			
		||||
package cc.tweaked.gradle
 | 
			
		||||
 | 
			
		||||
import org.gradle.api.file.DirectoryProperty
 | 
			
		||||
import org.gradle.api.provider.Property
 | 
			
		||||
import org.gradle.api.tasks.AbstractExecTask
 | 
			
		||||
import org.gradle.api.tasks.OutputDirectory
 | 
			
		||||
import java.io.File
 | 
			
		||||
 | 
			
		||||
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
 | 
			
		||||
    @get:OutputDirectory
 | 
			
		||||
 
 | 
			
		||||
@@ -124,7 +124,7 @@ class CloseScope : AutoCloseable {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Proxy method to avoid overload ambiguity. */
 | 
			
		||||
fun <T> Property<T>.setProvider(provider: Provider<out T>) = set(provider)
 | 
			
		||||
fun <T: Any> Property<T >.setProvider(provider: Provider<out T>) = set(provider)
 | 
			
		||||
 | 
			
		||||
/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */
 | 
			
		||||
fun Provider<out FileSystemLocation>.getAbsolutePath(): String = get().asFile.absolutePath
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,6 @@ import javax.xml.xpath.XPathFactory
 | 
			
		||||
 * Would be good to PR some (or all) of these changes upstream at some point.
 | 
			
		||||
 *
 | 
			
		||||
 * @see net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask
 | 
			
		||||
 * @see net.minecraftforge.gradle.common.util.runs.IntellijRunGenerator
 | 
			
		||||
 */
 | 
			
		||||
internal class IdeaRunConfigurations(project: Project) {
 | 
			
		||||
    private val rootProject = project.rootProject
 | 
			
		||||
@@ -35,22 +34,6 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
			
		||||
    private val writer = TransformerFactory.newInstance().newTransformer()
 | 
			
		||||
 | 
			
		||||
    private val ideaDir = rootProject.file(".idea/")
 | 
			
		||||
    private val buildDir: Lazy<String?> = lazy {
 | 
			
		||||
        val ideaMisc = ideaDir.resolve("misc.xml")
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            val doc = Files.newBufferedReader(ideaMisc.toPath()).use {
 | 
			
		||||
                documentBuilder.parse(InputSource(it))
 | 
			
		||||
            }
 | 
			
		||||
            val node =
 | 
			
		||||
                xpath.evaluate("//component[@name=\"ProjectRootManager\"]/output", doc, XPathConstants.NODE) as Node
 | 
			
		||||
            val attr = node.attributes.getNamedItem("url") as Attr
 | 
			
		||||
            attr.value.removePrefix("file://")
 | 
			
		||||
        } catch (e: Exception) {
 | 
			
		||||
            LOGGER.error("Failed to find root directory", e)
 | 
			
		||||
            null
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun patch() = synchronized(LOCK) {
 | 
			
		||||
        val runConfigDir = ideaDir.resolve("runConfigurations")
 | 
			
		||||
@@ -58,10 +41,9 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
			
		||||
 | 
			
		||||
        Files.list(runConfigDir.toPath()).use {
 | 
			
		||||
            for (configuration in it) {
 | 
			
		||||
                val filename = configuration.fileName.toString();
 | 
			
		||||
                val filename = configuration.fileName.toString()
 | 
			
		||||
                when {
 | 
			
		||||
                    filename.endsWith("_fabric.xml") -> patchFabric(configuration)
 | 
			
		||||
                    filename.startsWith("forge_") && filename.endsWith(".xml") -> patchForge(configuration)
 | 
			
		||||
                    else -> {}
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -72,65 +54,6 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
			
		||||
        setXml("//configuration", "folderName") { "Fabric" }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun patchForge(path: Path) = withXml(path) {
 | 
			
		||||
        val configId = path.fileName.toString().removePrefix("forge_").removeSuffix(".xml")
 | 
			
		||||
        val sourceSet = forgeConfigs[configId]
 | 
			
		||||
        if (sourceSet == null) {
 | 
			
		||||
            LOGGER.error("[{}] Cannot map run configuration to a known source set", path)
 | 
			
		||||
            return@withXml
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setXml("//configuration", "folderName") { "Forge" }
 | 
			
		||||
        setXml("//configuration/module", "name") { "${rootProject.name}.forge.$sourceSet" }
 | 
			
		||||
 | 
			
		||||
        if (buildDir.value == null) return@withXml
 | 
			
		||||
        setXml("//configuration/envs/env[@name=\"MOD_CLASSES\"]", "value") { classpath ->
 | 
			
		||||
            val classes = classpath!!.split(':')
 | 
			
		||||
            val newClasses = mutableListOf<String>()
 | 
			
		||||
            fun appendUnique(x: String) {
 | 
			
		||||
                if (!newClasses.contains(x)) newClasses.add(x)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            for (entry in classes) {
 | 
			
		||||
                if (!entry.contains("/out/")) {
 | 
			
		||||
                    appendUnique(entry)
 | 
			
		||||
                    continue
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                val match = CLASSPATH_ENTRY.matchEntire(entry)
 | 
			
		||||
                if (match != null) {
 | 
			
		||||
                    val modId = match.groups["modId"]!!.value
 | 
			
		||||
                    val proj = match.groups["proj"]!!.value
 | 
			
		||||
                    var component = match.groups["component"]!!.value
 | 
			
		||||
                    if (component == "production") component = "main"
 | 
			
		||||
 | 
			
		||||
                    appendUnique(forgeModEntry(modId, proj, component))
 | 
			
		||||
                } else {
 | 
			
		||||
                    LOGGER.warn("[{}] Unknown classpath entry {}", path, entry)
 | 
			
		||||
                    appendUnique(entry)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Ensure common code is on the classpath
 | 
			
		||||
            for (proj in listOf("common", "common-api")) {
 | 
			
		||||
                for (component in listOf("main", "client")) {
 | 
			
		||||
                    appendUnique(forgeModEntry("computercraft", proj, component))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (newClasses.any { it.startsWith("cctest%%") }) {
 | 
			
		||||
                appendUnique(forgeModEntry("cctest", "core", "testFixtures"))
 | 
			
		||||
                appendUnique(forgeModEntry("cctest", "common", "testFixtures"))
 | 
			
		||||
                appendUnique(forgeModEntry("cctest", "common", "testMod"))
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            newClasses.joinToString(":")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun forgeModEntry(mod: String, project: String, component: String) =
 | 
			
		||||
        "$mod%%${buildDir.value}/production/${rootProject.name}.$project.$component"
 | 
			
		||||
 | 
			
		||||
    private fun LocatedDocument.setXml(xpath: String, attribute: String, value: (String?) -> String) {
 | 
			
		||||
        val node = this@IdeaRunConfigurations.xpath.evaluate(xpath, document, XPathConstants.NODE) as Node?
 | 
			
		||||
        if (node == null) {
 | 
			
		||||
@@ -159,16 +82,5 @@ internal class IdeaRunConfigurations(project: Project) {
 | 
			
		||||
    companion object {
 | 
			
		||||
        private val LOGGER = Logging.getLogger(IdeaRunConfigurations::class.java)
 | 
			
		||||
        private val LOCK = Any()
 | 
			
		||||
 | 
			
		||||
        private val CLASSPATH_ENTRY =
 | 
			
		||||
            Regex("(?<modId>[a-z]+)%%\\\$PROJECT_DIR\\\$/projects/(?<proj>[a-z-]+)/out/(?<component>\\w+)/(?<type>[a-z]+)\$")
 | 
			
		||||
 | 
			
		||||
        private val forgeConfigs = mapOf(
 | 
			
		||||
            "runClient" to "client",
 | 
			
		||||
            "runData" to "main",
 | 
			
		||||
            "runGameTestServer" to "testMod",
 | 
			
		||||
            "runServer" to "main",
 | 
			
		||||
            "runTestClient" to "testMod",
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,6 @@ class MinecraftConfigurations private constructor(private val project: Project)
 | 
			
		||||
 | 
			
		||||
        // Set up an API configuration for clients (to ensure it's consistent with the main source set).
 | 
			
		||||
        val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
 | 
			
		||||
            isVisible = false
 | 
			
		||||
            isCanBeConsumed = false
 | 
			
		||||
            isCanBeResolved = false
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,16 +0,0 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package cc.tweaked.gradle
 | 
			
		||||
 | 
			
		||||
import groovy.util.Node
 | 
			
		||||
import groovy.util.NodeList
 | 
			
		||||
 | 
			
		||||
object XmlUtil {
 | 
			
		||||
    fun findChild(node: Node, name: String): Node? = when (val child = node.get(name)) {
 | 
			
		||||
        is Node -> child
 | 
			
		||||
        is NodeList -> child.singleOrNull() as Node?
 | 
			
		||||
        else -> null
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
 | 
			
		||||
 | 
			
		||||
# Mod properties
 | 
			
		||||
isUnstable=false
 | 
			
		||||
modVersion=1.115.1
 | 
			
		||||
modVersion=1.116.2
 | 
			
		||||
 | 
			
		||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
 | 
			
		||||
mcVersion=1.20.1
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +1,2 @@
 | 
			
		||||
#This file is generated by updateDaemonJvm
 | 
			
		||||
toolchainVersion=17
 | 
			
		||||
toolchainVersion=21
 | 
			
		||||
 
 | 
			
		||||
@@ -23,17 +23,17 @@ netty = "4.1.82.Final"
 | 
			
		||||
slf4j = "2.0.1"
 | 
			
		||||
 | 
			
		||||
# Core dependencies (independent of Minecraft)
 | 
			
		||||
asm = "9.6"
 | 
			
		||||
asm = "9.9"
 | 
			
		||||
autoService = "1.1.1"
 | 
			
		||||
checkerFramework = "3.42.0"
 | 
			
		||||
cobalt = { strictly = "0.9.5" }
 | 
			
		||||
commonsCli = "1.6.0"
 | 
			
		||||
jetbrainsAnnotations = "24.1.0"
 | 
			
		||||
checkerFramework = "3.51.1"
 | 
			
		||||
cobalt = { strictly = "0.9.7" }
 | 
			
		||||
commonsCli = "1.10.0"
 | 
			
		||||
jetbrainsAnnotations = "26.0.2-1"
 | 
			
		||||
jspecify = "1.0.0"
 | 
			
		||||
jzlib = "1.1.3"
 | 
			
		||||
kotlin = "2.1.10"
 | 
			
		||||
kotlin-coroutines = "1.10.1"
 | 
			
		||||
nightConfig = "3.8.1"
 | 
			
		||||
kotlin = "2.2.21"
 | 
			
		||||
kotlin-coroutines = "1.10.2"
 | 
			
		||||
nightConfig = "3.8.3"
 | 
			
		||||
 | 
			
		||||
# Minecraft mods
 | 
			
		||||
emi = "1.0.8+1.20.1"
 | 
			
		||||
@@ -47,35 +47,34 @@ rei = "12.0.626"
 | 
			
		||||
rubidium = "0.6.1"
 | 
			
		||||
sodium = "mc1.20-0.4.10"
 | 
			
		||||
create-forge = "6.0.0-9"
 | 
			
		||||
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
 | 
			
		||||
create-fabric = "6.0.7.0+mc1.20.1-build.1716"
 | 
			
		||||
 | 
			
		||||
# Testing
 | 
			
		||||
hamcrest = "2.2"
 | 
			
		||||
jqwik = "1.8.2"
 | 
			
		||||
junit = "5.11.4"
 | 
			
		||||
junitPlatform = "1.11.4"
 | 
			
		||||
hamcrest = "3.0"
 | 
			
		||||
jqwik = "1.9.3"
 | 
			
		||||
junit = "6.0.1"
 | 
			
		||||
junitPlatform = "6.0.1"
 | 
			
		||||
jmh = "1.37"
 | 
			
		||||
 | 
			
		||||
# Build tools
 | 
			
		||||
cctJavadoc = "1.8.3"
 | 
			
		||||
checkstyle = "10.21.2"
 | 
			
		||||
errorProne-core = "2.36.0"
 | 
			
		||||
errorProne-plugin = "4.1.0"
 | 
			
		||||
fabric-loom = "1.9.2"
 | 
			
		||||
cctJavadoc = "1.8.4"
 | 
			
		||||
checkstyle = "12.1.1"
 | 
			
		||||
errorProne-core = "2.43.0"
 | 
			
		||||
errorProne-plugin = "4.3.0"
 | 
			
		||||
fabric-loom = "1.12.3"
 | 
			
		||||
githubRelease = "2.5.2"
 | 
			
		||||
gradleVersions = "0.50.0"
 | 
			
		||||
ideaExt = "1.1.7"
 | 
			
		||||
illuaminate = "0.1.0-74-gf1551d5"
 | 
			
		||||
lwjgl = "3.3.3"
 | 
			
		||||
gradleVersions = "0.53.0"
 | 
			
		||||
ideaExt = "1.3"
 | 
			
		||||
illuaminate = "0.1.0-83-g1131f68"
 | 
			
		||||
lwjgl = "3.3.6"
 | 
			
		||||
minotaur = "2.8.7"
 | 
			
		||||
modDevGradle = "2.0.74"
 | 
			
		||||
nullAway = "0.12.3"
 | 
			
		||||
shadow = "8.3.1"
 | 
			
		||||
spotless = "6.23.3"
 | 
			
		||||
taskTree = "2.1.1"
 | 
			
		||||
teavm = "0.11.0-SQUID.1"
 | 
			
		||||
vanillaExtract = "0.2.0"
 | 
			
		||||
versionCatalogUpdate = "0.8.1"
 | 
			
		||||
modDevGradle = "2.0.116"
 | 
			
		||||
nullAway = "0.12.11"
 | 
			
		||||
shadow = "9.2.2"
 | 
			
		||||
spotless = "8.0.0"
 | 
			
		||||
teavm = "0.13.0-SQUID.2"
 | 
			
		||||
vanillaExtract = "0.2.1"
 | 
			
		||||
versionCatalogUpdate = "1.0.1"
 | 
			
		||||
 | 
			
		||||
[libraries]
 | 
			
		||||
# Normal dependencies
 | 
			
		||||
@@ -174,7 +173,6 @@ githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "g
 | 
			
		||||
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
 | 
			
		||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
 | 
			
		||||
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
 | 
			
		||||
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
 | 
			
		||||
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
 | 
			
		||||
 | 
			
		||||
[bundles]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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-9.2.0-bin.zip
 | 
			
		||||
networkTimeout=10000
 | 
			
		||||
validateDistributionUrl=true
 | 
			
		||||
zipStoreBase=GRADLE_USER_HOME
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1064
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1064
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -12,11 +12,11 @@
 | 
			
		||||
    "tslib": "^2.0.3"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@rollup/plugin-node-resolve": "^15.2.1",
 | 
			
		||||
    "@rollup/plugin-node-resolve": "^16.0.0",
 | 
			
		||||
    "@rollup/plugin-typescript": "^12.0.0",
 | 
			
		||||
    "@rollup/plugin-url": "^8.0.1",
 | 
			
		||||
    "@swc/core": "^1.3.92",
 | 
			
		||||
    "@types/node": "^22.0.0",
 | 
			
		||||
    "@types/node": "^24.0.0",
 | 
			
		||||
    "lightningcss": "^1.22.0",
 | 
			
		||||
    "preact-render-to-string": "^6.2.1",
 | 
			
		||||
    "rehype": "^13.0.0",
 | 
			
		||||
 
 | 
			
		||||
@@ -63,16 +63,25 @@ tasks.javadoc {
 | 
			
		||||
            """.trimIndent(),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        taglets("cc.tweaked.javadoc.SnippetTaglet")
 | 
			
		||||
        tagletPath(configurations.detachedConfiguration(dependencies.project(":lints")).toList())
 | 
			
		||||
 | 
			
		||||
        val snippetSources = listOf(":common", ":fabric", ":forge").flatMap {
 | 
			
		||||
            project(it).sourceSets["examples"].allSource.sourceDirectories
 | 
			
		||||
        }
 | 
			
		||||
        inputs.files(snippetSources)
 | 
			
		||||
        jFlags("-Dcc.snippet-path=" + snippetSources.joinToString(File.pathSeparator) { it.absolutePath })
 | 
			
		||||
        addPathOption("-snippet-path").value = snippetSources
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump.
 | 
			
		||||
    source(project(":core-api").sourceSets.main.map { it.allJava })
 | 
			
		||||
 | 
			
		||||
    options {
 | 
			
		||||
        this as StandardJavadocDocletOptions
 | 
			
		||||
        addBooleanOption("-allow-script-in-comments", true)
 | 
			
		||||
        bottom(
 | 
			
		||||
            """
 | 
			
		||||
            <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script>
 | 
			
		||||
            <script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
 | 
			
		||||
            <link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet">
 | 
			
		||||
            """.trimIndent(),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,20 @@ public class ComputerCraftTags {
 | 
			
		||||
        public static final TagKey<Item> WIRED_MODEM = make("wired_modem");
 | 
			
		||||
        public static final TagKey<Item> MONITOR = make("monitor");
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Floppy disks. Both the read/write version, and treasure disks.
 | 
			
		||||
         *
 | 
			
		||||
         * @since 1.116.0
 | 
			
		||||
         */
 | 
			
		||||
        public static final TagKey<Item> DISKS = make("disks");
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * All pocket computers.
 | 
			
		||||
         *
 | 
			
		||||
         * @since 1.116.0
 | 
			
		||||
         */
 | 
			
		||||
        public static final TagKey<Item> POCKET_COMPUTERS = make("pocket_computers");
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Items which can be {@linkplain Item#use(Level, Player, InteractionHand) used} when calling
 | 
			
		||||
         * {@code turtle.place()}.
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@ import java.util.function.BiFunction;
 | 
			
		||||
 * <h3>Registering the upgrade serialiser</h3>
 | 
			
		||||
 * First, let's create a new class that implements {@link ITurtleUpgrade}. It is recommended to subclass
 | 
			
		||||
 * {@link AbstractTurtleUpgrade}, as that provides a default implementation of most methods.
 | 
			
		||||
 * <p>
 | 
			
		||||
 *
 | 
			
		||||
 * {@snippet class=com.example.examplemod.ExampleTurtleUpgrade region=body}
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Now we must construct a new upgrade serialiser. In most cases, you can use one of the helper methods
 | 
			
		||||
 
 | 
			
		||||
@@ -81,7 +81,7 @@ val luaJavadoc by tasks.registering(Javadoc::class) {
 | 
			
		||||
    options.addStringOption("project-root", rootProject.file(".").absolutePath)
 | 
			
		||||
    options.noTimestamp(false)
 | 
			
		||||
 | 
			
		||||
    javadocTool = javaToolchains.javadocToolFor { languageVersion = CCTweakedPlugin.JAVA_VERSION }
 | 
			
		||||
    javadocTool = javaToolchains.javadocToolFor { languageVersion = CCTweakedPlugin.JDK_VERSION }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
val lintLua by tasks.registering(IlluaminateExec::class) {
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,8 @@ import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.ItemLike;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
@@ -63,6 +65,8 @@ import java.util.function.Supplier;
 | 
			
		||||
 * @see ModRegistry The common registry for actual game objects.
 | 
			
		||||
 */
 | 
			
		||||
public final class ClientRegistry {
 | 
			
		||||
    private static final Logger LOG = LoggerFactory.getLogger(ClientRegistry.class);
 | 
			
		||||
 | 
			
		||||
    private ClientRegistry() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -182,7 +186,18 @@ public final class ClientRegistry {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
 | 
			
		||||
        RenderTypes.registerShaders(resources, load);
 | 
			
		||||
        RenderTypes.registerShaders(resources, (name, create, onLoaded) -> {
 | 
			
		||||
            ShaderInstance shader;
 | 
			
		||||
            try {
 | 
			
		||||
                shader = create.get();
 | 
			
		||||
            } catch (Exception e) {
 | 
			
		||||
                LOG.error("Failed to load {}", name, e);
 | 
			
		||||
                onLoaded.accept(null);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            load.accept(shader, onLoaded);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private record UnclampedPropertyFunction(
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,40 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.client.gui;
 | 
			
		||||
 | 
			
		||||
import org.lwjgl.glfw.GLFW;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Supports for converting/translating key codes.
 | 
			
		||||
 */
 | 
			
		||||
public class KeyConverter {
 | 
			
		||||
    /**
 | 
			
		||||
     * GLFW's key events refer to the physical key code, rather than the "actual" key code (with keyboard layout
 | 
			
		||||
     * applied).
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This makes sense for WASD-style input, but is a right pain for keyboard shortcuts — this function attempts to
 | 
			
		||||
     * translate those keys back to their "actual" key code. See also
 | 
			
		||||
     * <a href="https://github.com/glfw/glfw/issues/1502"> this discussion on GLFW's GitHub.</a>
 | 
			
		||||
     *
 | 
			
		||||
     * @param key      The current key code.
 | 
			
		||||
     * @param scanCode The current scan code.
 | 
			
		||||
     * @return The translated key code.
 | 
			
		||||
     */
 | 
			
		||||
    public static int physicalToActual(int key, int scanCode) {
 | 
			
		||||
        var name = GLFW.glfwGetKeyName(key, scanCode);
 | 
			
		||||
        if (name == null || name.length() != 1) return key;
 | 
			
		||||
 | 
			
		||||
        // If we've got a single character as the key name, treat that as the ASCII value of the key,
 | 
			
		||||
        // and map that back to a key code.
 | 
			
		||||
        var character = name.charAt(0);
 | 
			
		||||
 | 
			
		||||
        // 0-9 and A-Z map directly to their GLFW key (they're the same ASCII code).
 | 
			
		||||
        if ((character >= '0' && character <= '9') || (character >= 'A' && character <= 'Z')) return character;
 | 
			
		||||
        // a-z map to GLFW_KEY_{A,Z}
 | 
			
		||||
        if (character >= 'a' && character <= 'z') return GLFW.GLFW_KEY_A + (character - 'a');
 | 
			
		||||
 | 
			
		||||
        return key;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
package dan200.computercraft.client.gui.widgets;
 | 
			
		||||
 | 
			
		||||
import com.mojang.blaze3d.vertex.Tesselator;
 | 
			
		||||
import dan200.computercraft.client.gui.KeyConverter;
 | 
			
		||||
import dan200.computercraft.client.render.RenderTypes;
 | 
			
		||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
 | 
			
		||||
import dan200.computercraft.core.terminal.Terminal;
 | 
			
		||||
@@ -85,7 +86,7 @@ public class TerminalWidget extends AbstractWidget {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) {
 | 
			
		||||
            switch (key) {
 | 
			
		||||
            switch (KeyConverter.physicalToActual(key, scancode)) {
 | 
			
		||||
                case GLFW.GLFW_KEY_T -> {
 | 
			
		||||
                    if (terminateTimer < 0) terminateTimer = 0;
 | 
			
		||||
                }
 | 
			
		||||
@@ -121,7 +122,7 @@ public class TerminalWidget extends AbstractWidget {
 | 
			
		||||
            computer.keyUp(key);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (key) {
 | 
			
		||||
        switch (KeyConverter.physicalToActual(key, scancode)) {
 | 
			
		||||
            case GLFW.GLFW_KEY_T -> terminateTimer = -1;
 | 
			
		||||
            case GLFW.GLFW_KEY_R -> rebootTimer = -1;
 | 
			
		||||
            case GLFW.GLFW_KEY_S -> shutdownTimer = -1;
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ 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.lectern.CustomLecternBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.media.items.PrintoutItem;
 | 
			
		||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
 | 
			
		||||
@@ -57,9 +58,9 @@ public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternB
 | 
			
		||||
        poseStack.translate(0, -0.125f, 0);
 | 
			
		||||
 | 
			
		||||
        var item = lectern.getItem();
 | 
			
		||||
        if (item.getItem() instanceof PrintoutItem printout) {
 | 
			
		||||
        if (item.getItem() instanceof PrintoutItem) {
 | 
			
		||||
            var vertexConsumer = LecternPrintoutModel.MATERIAL.buffer(buffer, RenderType::entitySolid);
 | 
			
		||||
            if (printout.getType() == PrintoutItem.Type.BOOK) {
 | 
			
		||||
            if (item.is(ModRegistry.Items.PRINTED_BOOK.get())) {
 | 
			
		||||
                printoutModel.renderBook(poseStack, vertexConsumer, packedLight, packedOverlay);
 | 
			
		||||
            } else {
 | 
			
		||||
                printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutItem.getPageCount(item));
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ package dan200.computercraft.client.render;
 | 
			
		||||
 | 
			
		||||
import com.mojang.blaze3d.vertex.PoseStack;
 | 
			
		||||
import com.mojang.math.Axis;
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry;
 | 
			
		||||
import dan200.computercraft.shared.media.items.PrintoutItem;
 | 
			
		||||
import net.minecraft.client.renderer.MultiBufferSource;
 | 
			
		||||
import net.minecraft.world.entity.EntityType;
 | 
			
		||||
@@ -51,7 +52,7 @@ public final class PrintoutItemRenderer extends ItemMapLikeRenderer {
 | 
			
		||||
 | 
			
		||||
    private static void drawPrintout(PoseStack transform, MultiBufferSource render, ItemStack stack, int light) {
 | 
			
		||||
        var pages = PrintoutItem.getPageCount(stack);
 | 
			
		||||
        var book = ((PrintoutItem) stack.getItem()).getType() == PrintoutItem.Type.BOOK;
 | 
			
		||||
        var book = stack.is(ModRegistry.Items.PRINTED_BOOK.get());
 | 
			
		||||
 | 
			
		||||
        double width = LINE_MAX_LENGTH * FONT_WIDTH + X_TEXT_MARGIN * 2;
 | 
			
		||||
        double height = LINES_PER_PAGE * FONT_HEIGHT + Y_TEXT_MARGIN * 2;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,11 +16,11 @@ import net.minecraft.client.renderer.RenderType;
 | 
			
		||||
import net.minecraft.client.renderer.ShaderInstance;
 | 
			
		||||
import net.minecraft.resources.ResourceLocation;
 | 
			
		||||
import net.minecraft.server.packs.resources.ResourceProvider;
 | 
			
		||||
import org.apache.commons.io.function.IOSupplier;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.function.BiConsumer;
 | 
			
		||||
import java.util.function.Consumer;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -68,9 +68,12 @@ public class RenderTypes {
 | 
			
		||||
        return Objects.requireNonNull(GameRenderer.getRendertypeTextShader(), "Text shader has not been registered");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
 | 
			
		||||
        load.accept(
 | 
			
		||||
            new MonitorTextureBufferShader(
 | 
			
		||||
    public interface ShaderLoader {
 | 
			
		||||
        void tryLoad(String name, IOSupplier<ShaderInstance> create, Consumer<@Nullable ShaderInstance> accept) throws IOException;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void registerShaders(ResourceProvider resources, ShaderLoader load) throws IOException {
 | 
			
		||||
        load.tryLoad("monitor shader", () -> new MonitorTextureBufferShader(
 | 
			
		||||
                resources,
 | 
			
		||||
                ComputerCraftAPI.MOD_ID + "/monitor_tbo",
 | 
			
		||||
                MONITOR_TBO.format()
 | 
			
		||||
 
 | 
			
		||||
@@ -66,8 +66,8 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
 | 
			
		||||
            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, (float) 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
 | 
			
		||||
            font.drawInBatch(label, width, (float) 0, 0xffffffff, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
 | 
			
		||||
            font.drawInBatch(label, width, 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
 | 
			
		||||
            font.drawInBatch(label, width, 0, 0xffffffff, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
 | 
			
		||||
 | 
			
		||||
            transform.popPose();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -106,6 +106,8 @@ public final class LanguageProvider implements DataProvider {
 | 
			
		||||
        add(ComputerCraftTags.Items.TURTLE, "Turtles");
 | 
			
		||||
        add(ComputerCraftTags.Items.WIRED_MODEM, "Wired modems");
 | 
			
		||||
        add(ComputerCraftTags.Items.MONITOR, "Monitors");
 | 
			
		||||
        add(ComputerCraftTags.Items.DISKS, "Disks");
 | 
			
		||||
        add(ComputerCraftTags.Items.POCKET_COMPUTERS, "Pocket Computers");
 | 
			
		||||
 | 
			
		||||
        // Turtle/pocket upgrades
 | 
			
		||||
        add("upgrade.minecraft.diamond_sword.adjective", "Melee");
 | 
			
		||||
@@ -183,7 +185,6 @@ public final class LanguageProvider implements DataProvider {
 | 
			
		||||
        // Metrics
 | 
			
		||||
        add(Metrics.COMPUTER_TASKS, "Tasks");
 | 
			
		||||
        add(Metrics.SERVER_TASKS, "Server tasks");
 | 
			
		||||
        add(Metrics.JAVA_ALLOCATION, "Java Allocations");
 | 
			
		||||
        add(Metrics.PERIPHERAL_OPS, "Peripheral calls");
 | 
			
		||||
        add(Metrics.FS_OPS, "Filesystem operations");
 | 
			
		||||
        add(Metrics.HTTP_REQUESTS, "HTTP requests");
 | 
			
		||||
 
 | 
			
		||||
@@ -98,6 +98,8 @@ class TagProvider {
 | 
			
		||||
        tags.copy(ComputerCraftTags.Blocks.TURTLE, ComputerCraftTags.Items.TURTLE);
 | 
			
		||||
        tags.tag(ComputerCraftTags.Items.WIRED_MODEM).add(ModRegistry.Items.WIRED_MODEM.get(), ModRegistry.Items.WIRED_MODEM_FULL.get());
 | 
			
		||||
        tags.copy(ComputerCraftTags.Blocks.MONITOR, ComputerCraftTags.Items.MONITOR);
 | 
			
		||||
        tags.tag(ComputerCraftTags.Items.DISKS).add(ModRegistry.Items.DISK.get(), ModRegistry.Items.TREASURE_DISK.get());
 | 
			
		||||
        tags.tag(ComputerCraftTags.Items.POCKET_COMPUTERS).add(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
 | 
			
		||||
 | 
			
		||||
        tags.tag(ItemTags.PIGLIN_LOVED).add(
 | 
			
		||||
            ModRegistry.Items.COMPUTER_ADVANCED.get(), ModRegistry.Items.TURTLE_ADVANCED.get(),
 | 
			
		||||
 
 | 
			
		||||
@@ -205,7 +205,9 @@
 | 
			
		||||
  "item.computercraft.treasure_disk": "Floppy Disk",
 | 
			
		||||
  "itemGroup.computercraft": "ComputerCraft",
 | 
			
		||||
  "tag.item.computercraft.computer": "Computers",
 | 
			
		||||
  "tag.item.computercraft.disks": "Disks",
 | 
			
		||||
  "tag.item.computercraft.monitor": "Monitors",
 | 
			
		||||
  "tag.item.computercraft.pocket_computers": "Pocket Computers",
 | 
			
		||||
  "tag.item.computercraft.turtle": "Turtles",
 | 
			
		||||
  "tag.item.computercraft.wired_modem": "Wired modems",
 | 
			
		||||
  "tracking_field.computercraft.avg": "%s (avg)",
 | 
			
		||||
@@ -215,7 +217,6 @@
 | 
			
		||||
  "tracking_field.computercraft.http_download.name": "HTTP download",
 | 
			
		||||
  "tracking_field.computercraft.http_requests.name": "HTTP requests",
 | 
			
		||||
  "tracking_field.computercraft.http_upload.name": "HTTP upload",
 | 
			
		||||
  "tracking_field.computercraft.java_allocation.name": "Java Allocations",
 | 
			
		||||
  "tracking_field.computercraft.max": "%s (max)",
 | 
			
		||||
  "tracking_field.computercraft.peripheral.name": "Peripheral calls",
 | 
			
		||||
  "tracking_field.computercraft.server_tasks.name": "Server tasks",
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.impl.network.wired;
 | 
			
		||||
 | 
			
		||||
import org.jetbrains.annotations.Contract;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
import org.slf4j.Logger;
 | 
			
		||||
import org.slf4j.LoggerFactory;
 | 
			
		||||
@@ -61,7 +60,6 @@ final class InvariantChecker {
 | 
			
		||||
        return okay;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Contract("")
 | 
			
		||||
    private static <T> @Nullable T makeNullable(T object) {
 | 
			
		||||
        return object;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -437,8 +437,8 @@ final class WiredNetworkImpl implements WiredNetwork {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static WiredNodeImpl checkNode(WiredNode node) {
 | 
			
		||||
        if (node instanceof WiredNodeImpl) {
 | 
			
		||||
            return (WiredNodeImpl) node;
 | 
			
		||||
        if (node instanceof WiredNodeImpl n) {
 | 
			
		||||
            return n;
 | 
			
		||||
        } else {
 | 
			
		||||
            throw new IllegalArgumentException("Unknown implementation of IWiredNode: " + node);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -123,7 +123,7 @@ import java.util.function.Predicate;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Registers ComputerCraft's registry entries and additional objects, such as {@link CauldronInteraction}s and
 | 
			
		||||
 * {@link DetailProvider}s
 | 
			
		||||
 * {@link DetailProvider}s.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * The functions in this class should be called from a loader-specific class.
 | 
			
		||||
 */
 | 
			
		||||
@@ -264,11 +264,11 @@ public final class ModRegistry {
 | 
			
		||||
            REGISTRY.register("treasure_disk", () -> new TreasureDiskItem(properties().stacksTo(1)));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<PrintoutItem> PRINTED_PAGE = REGISTRY.register("printed_page",
 | 
			
		||||
            () -> new PrintoutItem(properties().stacksTo(1), PrintoutItem.Type.PAGE));
 | 
			
		||||
            () -> new PrintoutItem(properties().stacksTo(1)));
 | 
			
		||||
        public static final RegistryEntry<PrintoutItem> PRINTED_PAGES = REGISTRY.register("printed_pages",
 | 
			
		||||
            () -> new PrintoutItem(properties().stacksTo(1), PrintoutItem.Type.PAGES));
 | 
			
		||||
            () -> new PrintoutItem(properties().stacksTo(1)));
 | 
			
		||||
        public static final RegistryEntry<PrintoutItem> PRINTED_BOOK = REGISTRY.register("printed_book",
 | 
			
		||||
            () -> new PrintoutItem(properties().stacksTo(1), PrintoutItem.Type.BOOK));
 | 
			
		||||
            () -> new PrintoutItem(properties().stacksTo(1)));
 | 
			
		||||
 | 
			
		||||
        public static final RegistryEntry<BlockItem> SPEAKER = ofBlock(Blocks.SPEAKER, BlockItem::new);
 | 
			
		||||
        public static final RegistryEntry<BlockItem> DISK_DRIVE = ofBlock(Blocks.DISK_DRIVE, BlockItem::new);
 | 
			
		||||
 
 | 
			
		||||
@@ -50,6 +50,12 @@ 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")
 | 
			
		||||
 
 | 
			
		||||
@@ -66,8 +66,8 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
 | 
			
		||||
    public LiteralArgumentBuilder<CommandSourceStack> then(final ArgumentBuilder<CommandSourceStack, ?> argument) {
 | 
			
		||||
        if (getRedirect() != null) throw new IllegalStateException("Cannot add children to a redirected node");
 | 
			
		||||
 | 
			
		||||
        if (argument instanceof HelpingArgumentBuilder) {
 | 
			
		||||
            children.add((HelpingArgumentBuilder) argument);
 | 
			
		||||
        if (argument instanceof HelpingArgumentBuilder child) {
 | 
			
		||||
            children.add(child);
 | 
			
		||||
        } else if (argument instanceof LiteralArgumentBuilder) {
 | 
			
		||||
            super.then(argument);
 | 
			
		||||
        } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.computer.blocks;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.annotations.ForgeOverride;
 | 
			
		||||
import dan200.computercraft.api.ComputerCraftAPI;
 | 
			
		||||
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
 | 
			
		||||
import dan200.computercraft.shared.computer.items.IComputerItem;
 | 
			
		||||
@@ -25,7 +24,6 @@ import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.level.BlockGetter;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.level.LevelAccessor;
 | 
			
		||||
import net.minecraft.world.level.LevelReader;
 | 
			
		||||
import net.minecraft.world.level.block.Block;
 | 
			
		||||
import net.minecraft.world.level.block.EntityBlock;
 | 
			
		||||
import net.minecraft.world.level.block.HorizontalDirectionalBlock;
 | 
			
		||||
@@ -177,12 +175,6 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
 | 
			
		||||
        if (be instanceof AbstractComputerBlockEntity computer) computer.neighborChanged(neighbourPos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ForgeOverride
 | 
			
		||||
    public final void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbour) {
 | 
			
		||||
        var be = world.getBlockEntity(pos);
 | 
			
		||||
        if (be instanceof AbstractComputerBlockEntity computer) computer.neighborChanged(neighbour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    public BlockState updateShape(BlockState state, Direction direction, BlockState neighborState, LevelAccessor level, BlockPos pos, BlockPos neighborPos) {
 | 
			
		||||
 
 | 
			
		||||
@@ -74,7 +74,7 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static boolean isValidClipboard(ByteBuffer buffer) {
 | 
			
		||||
        for (int i = buffer.remaining(), max = buffer.limit(); i < max; i++) {
 | 
			
		||||
        for (int i = buffer.position(), max = buffer.limit(); i < max; i++) {
 | 
			
		||||
            if (!StringUtil.isTypableChar(buffer.get(i))) return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,8 @@ import dan200.computercraft.shared.media.items.DiskItem;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.util.function.Supplier;
 | 
			
		||||
import java.util.function.ToIntFunction;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,19 +4,18 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.media.items;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.annotations.ForgeOverride;
 | 
			
		||||
import dan200.computercraft.core.util.Colour;
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry;
 | 
			
		||||
import dan200.computercraft.shared.common.IColouredItem;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlock;
 | 
			
		||||
import net.minecraft.ChatFormatting;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.InteractionResult;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.TooltipFlag;
 | 
			
		||||
import net.minecraft.world.item.context.UseOnContext;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.level.LevelReader;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -47,9 +46,9 @@ public class DiskItem extends Item implements IColouredItem {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ForgeOverride
 | 
			
		||||
    public boolean doesSneakBypassUse(ItemStack stack, LevelReader world, BlockPos pos, Player player) {
 | 
			
		||||
        return true;
 | 
			
		||||
    @Override
 | 
			
		||||
    public InteractionResult useOn(UseOnContext context) {
 | 
			
		||||
        return DiskDriveBlock.defaultUseItemOn(context);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static int getDiskID(ItemStack stack) {
 | 
			
		||||
 
 | 
			
		||||
@@ -33,17 +33,8 @@ public class PrintoutItem extends Item {
 | 
			
		||||
    public static final int LINE_MAX_LENGTH = 25;
 | 
			
		||||
    public static final int MAX_PAGES = 16;
 | 
			
		||||
 | 
			
		||||
    public enum Type {
 | 
			
		||||
        PAGE,
 | 
			
		||||
        PAGES,
 | 
			
		||||
        BOOK
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private final Type type;
 | 
			
		||||
 | 
			
		||||
    public PrintoutItem(Properties settings, Type type) {
 | 
			
		||||
    public PrintoutItem(Properties settings) {
 | 
			
		||||
        super(settings);
 | 
			
		||||
        this.type = type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@@ -103,10 +94,6 @@ public class PrintoutItem extends Item {
 | 
			
		||||
        return ModRegistry.Items.PRINTED_BOOK.get().createFromTitleAndText(title, text, colours);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Type getType() {
 | 
			
		||||
        return type;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String getTitle(ItemStack stack) {
 | 
			
		||||
        var nbt = stack.getTag();
 | 
			
		||||
        return nbt != null && nbt.contains(NBT_TITLE) ? nbt.getString(NBT_TITLE) : "";
 | 
			
		||||
 
 | 
			
		||||
@@ -4,17 +4,16 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.media.items;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.annotations.ForgeOverride;
 | 
			
		||||
import dan200.computercraft.core.util.Colour;
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlock;
 | 
			
		||||
import net.minecraft.network.chat.Component;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.InteractionResult;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import net.minecraft.world.item.TooltipFlag;
 | 
			
		||||
import net.minecraft.world.item.context.UseOnContext;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.level.LevelReader;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
@@ -34,9 +33,9 @@ public class TreasureDiskItem extends Item {
 | 
			
		||||
        if (!label.isEmpty()) list.add(Component.literal(label));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ForgeOverride
 | 
			
		||||
    public boolean doesSneakBypassUse(ItemStack stack, LevelReader world, BlockPos pos, Player player) {
 | 
			
		||||
        return true;
 | 
			
		||||
    @Override
 | 
			
		||||
    public InteractionResult useOn(UseOnContext context) {
 | 
			
		||||
        return DiskDriveBlock.defaultUseItemOn(context);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static ItemStack create(String subPath, int colourIndex) {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@ import dan200.computercraft.api.media.IMedia;
 | 
			
		||||
import dan200.computercraft.core.filesystem.SubMount;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.item.ItemStack;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ public final class PrintoutRecipe extends CustomRecipe {
 | 
			
		||||
            for (var x = 0; x < inventory.getWidth(); x++) {
 | 
			
		||||
                var stack = inventory.getItem(x + y * inventory.getWidth());
 | 
			
		||||
                if (!stack.isEmpty()) {
 | 
			
		||||
                    if (stack.getItem() instanceof PrintoutItem printout && printout.getType() != PrintoutItem.Type.BOOK) {
 | 
			
		||||
                    if (stack.is(ModRegistry.Items.PRINTED_PAGE.get()) || stack.is(ModRegistry.Items.PRINTED_PAGES.get())) {
 | 
			
		||||
                        if (printouts == null) printouts = new ItemStack[9];
 | 
			
		||||
                        printouts[numPrintouts] = stack;
 | 
			
		||||
                        numPages += PrintoutItem.getPageCount(stack);
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ import net.minecraft.network.FriendlyByteBuf;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Stops a sound on the client
 | 
			
		||||
 * Stops a sound on the client.
 | 
			
		||||
 * <p>
 | 
			
		||||
 * Called when a speaker is broken.
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -6,12 +6,11 @@ package dan200.computercraft.shared.peripheral.diskdrive;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry;
 | 
			
		||||
import dan200.computercraft.shared.common.HorizontalContainerBlock;
 | 
			
		||||
import dan200.computercraft.shared.platform.PlatformHelper;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.core.Direction;
 | 
			
		||||
import net.minecraft.world.InteractionHand;
 | 
			
		||||
import net.minecraft.world.InteractionResult;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.item.Item;
 | 
			
		||||
import net.minecraft.world.item.context.UseOnContext;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.level.block.BaseEntityBlock;
 | 
			
		||||
import net.minecraft.world.level.block.Block;
 | 
			
		||||
@@ -21,7 +20,6 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
 | 
			
		||||
import net.minecraft.world.level.block.state.BlockState;
 | 
			
		||||
import net.minecraft.world.level.block.state.StateDefinition;
 | 
			
		||||
import net.minecraft.world.level.block.state.properties.EnumProperty;
 | 
			
		||||
import net.minecraft.world.phys.BlockHitResult;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
public class DiskDriveBlock extends HorizontalContainerBlock {
 | 
			
		||||
@@ -42,21 +40,26 @@ public class DiskDriveBlock extends HorizontalContainerBlock {
 | 
			
		||||
        properties.add(FACING, STATE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
 | 
			
		||||
        if (player.isCrouching() && level.getBlockEntity(pos) instanceof DiskDriveBlockEntity drive) {
 | 
			
		||||
            // Try to put a disk into the drive
 | 
			
		||||
            var disk = player.getItemInHand(hand);
 | 
			
		||||
            if (disk.isEmpty()) return InteractionResult.PASS;
 | 
			
		||||
    /**
 | 
			
		||||
     * A default implementation of {@link Item#useOn(UseOnContext)} for items that can be placed into a drive.
 | 
			
		||||
     *
 | 
			
		||||
     * @param context The context of this item usage action.
 | 
			
		||||
     * @return Whether the item was placed or not.
 | 
			
		||||
     */
 | 
			
		||||
    public static InteractionResult defaultUseItemOn(UseOnContext context) {
 | 
			
		||||
        if (context.getPlayer() == null || !context.getPlayer().isSecondaryUseActive()) return InteractionResult.PASS;
 | 
			
		||||
 | 
			
		||||
            if (!level.isClientSide && drive.getDiskStack().isEmpty() && PlatformHelper.get().getMedia(disk) != null) {
 | 
			
		||||
                drive.setDiskStack(disk.split(1));
 | 
			
		||||
        var level = context.getLevel();
 | 
			
		||||
        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()) {
 | 
			
		||||
                drive.setDiskStack(context.getItemInHand().split(1));
 | 
			
		||||
            }
 | 
			
		||||
            return InteractionResult.sidedSuccess(level.isClientSide);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return super.use(state, level, pos, player, hand, hit);
 | 
			
		||||
        return InteractionResult.PASS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Nullable
 | 
			
		||||
 
 | 
			
		||||
@@ -41,9 +41,9 @@ public abstract class AbstractFluidMethods<T> implements GenericPeripheral {
 | 
			
		||||
     * The returned table is sparse, and so empty tanks will be `nil` - it is recommended to loop over using [`pairs`]
 | 
			
		||||
     * rather than [`ipairs`].
 | 
			
		||||
     *
 | 
			
		||||
     * @param fluids The current fluid handler.
 | 
			
		||||
     * @param fluids The current fluid storage.
 | 
			
		||||
     * @return All tanks.
 | 
			
		||||
     * @cc.treturn { (table|nil)... } All tanks in this fluid storage.
 | 
			
		||||
     * @cc.treturn { (table|nil)... } Basic information about all fluids in this fluid storage.
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction(mainThread = true)
 | 
			
		||||
    public abstract Map<Integer, Map<String, ?>> tanks(T fluids);
 | 
			
		||||
 
 | 
			
		||||
@@ -56,8 +56,8 @@ public abstract class AbstractInventoryMethods<T> implements GenericPeripheral {
 | 
			
		||||
     * rather than [`ipairs`].
 | 
			
		||||
     *
 | 
			
		||||
     * @param inventory The current inventory.
 | 
			
		||||
     * @return All items in this inventory.
 | 
			
		||||
     * @cc.treturn { (table|nil)... } All items in this inventory.
 | 
			
		||||
     * @return Basic information about all items in this inventory.
 | 
			
		||||
     * @cc.treturn { (table|nil)... } Basic information about all items in this inventory.
 | 
			
		||||
     * @cc.usage Find an adjacent chest and print all items in it.
 | 
			
		||||
     *
 | 
			
		||||
     * <pre>{@code
 | 
			
		||||
@@ -81,17 +81,15 @@ public abstract class AbstractInventoryMethods<T> implements GenericPeripheral {
 | 
			
		||||
     * recommended to print it out using [`textutils.serialize`] or in the Lua
 | 
			
		||||
     * REPL, to explore what is available.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * > [Deprecated fields][!INFO]
 | 
			
		||||
     * > Older versions of CC: Tweaked exposed an {@code itemGroups} field, listing the
 | 
			
		||||
     * > creative tabs an item was available under. This information is no longer available on
 | 
			
		||||
     * > more recent versions of the game, and so this field will always be empty. Do not use this
 | 
			
		||||
     * > field in new code!
 | 
			
		||||
     * > [Missing fields][!INFO]
 | 
			
		||||
     * > CC: Tweaked exposes an {@code itemGroups} field, listing the creative tabs an
 | 
			
		||||
     * > item is available under. This information is not available on Minecraft 1.19.3
 | 
			
		||||
     * > to 1.20.3, and so this field will be empty on those versions.
 | 
			
		||||
     *
 | 
			
		||||
     * @param inventory The current inventory.
 | 
			
		||||
     * @param slot      The slot to get information about.
 | 
			
		||||
     * @return Information about the item in this slot, or {@code nil} if not present.
 | 
			
		||||
     * @return Information about the item in this slot, or {@code nil} if it is empty.
 | 
			
		||||
     * @throws LuaException If the slot is out of range.
 | 
			
		||||
     * @cc.treturn table Information about the item in this slot, or {@code nil} if not present.
 | 
			
		||||
     * @cc.usage Print some information about the first in a chest.
 | 
			
		||||
     *
 | 
			
		||||
     * <pre>{@code
 | 
			
		||||
@@ -109,7 +107,7 @@ public abstract class AbstractInventoryMethods<T> implements GenericPeripheral {
 | 
			
		||||
     */
 | 
			
		||||
    @Nullable
 | 
			
		||||
    @LuaFunction(mainThread = true)
 | 
			
		||||
    public abstract Map<String, ?> getItemDetail(T inventory, int slot) throws LuaException;
 | 
			
		||||
    public abstract Map<?, ?> getItemDetail(T inventory, int slot) throws LuaException;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the maximum number of items which can be stored in this slot.
 | 
			
		||||
 
 | 
			
		||||
@@ -260,11 +260,6 @@ public class CableBlock extends Block implements SimpleWaterloggedBlock, EntityB
 | 
			
		||||
        if (world.getBlockEntity(pos) instanceof CableBlockEntity modem) modem.neighborChanged(neighbourPos);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ForgeOverride
 | 
			
		||||
    public final void onNeighborChange(BlockState state, LevelReader world, BlockPos pos, BlockPos neighbour) {
 | 
			
		||||
        if (world.getBlockEntity(pos) instanceof CableBlockEntity modem) modem.neighborChanged(neighbour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.shared.peripheral.modem.wired;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.annotations.ForgeOverride;
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry;
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.core.Direction;
 | 
			
		||||
@@ -15,7 +14,6 @@ import net.minecraft.world.InteractionResult;
 | 
			
		||||
import net.minecraft.world.entity.player.Player;
 | 
			
		||||
import net.minecraft.world.level.Level;
 | 
			
		||||
import net.minecraft.world.level.LevelAccessor;
 | 
			
		||||
import net.minecraft.world.level.LevelReader;
 | 
			
		||||
import net.minecraft.world.level.block.Block;
 | 
			
		||||
import net.minecraft.world.level.block.EntityBlock;
 | 
			
		||||
import net.minecraft.world.level.block.entity.BlockEntity;
 | 
			
		||||
@@ -66,13 +64,6 @@ public class WiredModemFullBlock extends Block implements EntityBlock {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ForgeOverride
 | 
			
		||||
    public final void onNeighborChange(BlockState state, LevelReader level, BlockPos pos, BlockPos neighbour) {
 | 
			
		||||
        if (state.getValue(PERIPHERAL_ON) && level.getBlockEntity(pos) instanceof WiredModemFullBlockEntity modem) {
 | 
			
		||||
            modem.neighborChanged(neighbour);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    @Deprecated
 | 
			
		||||
    public void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource rand) {
 | 
			
		||||
 
 | 
			
		||||
@@ -305,7 +305,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
 | 
			
		||||
        return wrappers == null ? null : wrappers.get(remoteName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class RemotePeripheralWrapper implements IComputerAccess, GuardedLuaContext.Guard {
 | 
			
		||||
    private static final class RemotePeripheralWrapper implements IComputerAccess, GuardedLuaContext.Guard {
 | 
			
		||||
        private final WiredModemElement element;
 | 
			
		||||
        private final IPeripheral peripheral;
 | 
			
		||||
        private final IComputerAccess computer;
 | 
			
		||||
@@ -331,13 +331,13 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
 | 
			
		||||
            methodMap = methods;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void attach() {
 | 
			
		||||
        private void attach() {
 | 
			
		||||
            attached = true;
 | 
			
		||||
            peripheral.attach(this);
 | 
			
		||||
            computer.queueEvent("peripheral", getAttachmentName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void detach() {
 | 
			
		||||
        private void detach() {
 | 
			
		||||
            peripheral.detach(this);
 | 
			
		||||
            computer.queueEvent("peripheral_detach", getAttachmentName());
 | 
			
		||||
            attached = false;
 | 
			
		||||
@@ -352,19 +352,19 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public String getType() {
 | 
			
		||||
        private String getType() {
 | 
			
		||||
            return type;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Set<String> getAdditionalTypes() {
 | 
			
		||||
        private Set<String> getAdditionalTypes() {
 | 
			
		||||
            return additionalTypes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Collection<String> getMethodNames() {
 | 
			
		||||
        private Collection<String> getMethodNames() {
 | 
			
		||||
            return methodMap.keySet();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public MethodResult callMethod(ILuaContext context, String methodName, IArguments arguments) throws LuaException {
 | 
			
		||||
        private MethodResult callMethod(ILuaContext context, String methodName, IArguments arguments) throws LuaException {
 | 
			
		||||
            var method = methodMap.get(methodName);
 | 
			
		||||
            if (method == null) throw new LuaException("No such method " + methodName);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ public class WirelessModemBlockEntity extends BlockEntity {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean equals(@Nullable IPeripheral other) {
 | 
			
		||||
            return this == other || (other instanceof Peripheral && entity == ((Peripheral) other).entity);
 | 
			
		||||
            return this == other || (other instanceof Peripheral o && entity == o.entity);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,6 @@ import org.jspecify.annotations.Nullable;
 | 
			
		||||
 * monitor.setCursorPos(1, 1)
 | 
			
		||||
 * monitor.write("Hello, world!")
 | 
			
		||||
 * }</pre>
 | 
			
		||||
 *
 | 
			
		||||
 * @cc.see monitor_resize Queued when a monitor is resized.
 | 
			
		||||
 * @cc.see monitor_touch Queued when an advanced monitor is clicked.
 | 
			
		||||
 */
 | 
			
		||||
@@ -95,7 +94,7 @@ public class MonitorPeripheral extends TermMethods implements IPeripheral {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean equals(@Nullable IPeripheral other) {
 | 
			
		||||
        return other instanceof MonitorPeripheral && monitor == ((MonitorPeripheral) other).monitor;
 | 
			
		||||
        return other instanceof MonitorPeripheral o && monitor == o.monitor;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private ServerMonitor getMonitor() throws LuaException {
 | 
			
		||||
 
 | 
			
		||||
@@ -57,11 +57,10 @@ public final class MonitorWatcher {
 | 
			
		||||
            if (monitor == null) continue;
 | 
			
		||||
 | 
			
		||||
            var pos = tile.getBlockPos();
 | 
			
		||||
            var world = tile.getLevel();
 | 
			
		||||
            if (!(world instanceof ServerLevel)) continue;
 | 
			
		||||
            if (!(tile.getLevel() instanceof ServerLevel level)) continue;
 | 
			
		||||
 | 
			
		||||
            var chunk = world.getChunkAt(pos);
 | 
			
		||||
            if (((ServerLevel) world).getChunkSource().chunkMap.getPlayers(chunk.getPos(), false).isEmpty()) {
 | 
			
		||||
            var chunk = level.getChunkAt(pos);
 | 
			
		||||
            if (level.getChunkSource().chunkMap.getPlayers(chunk.getPos(), false).isEmpty()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
package dan200.computercraft.shared.peripheral.printer;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.api.peripheral.IPeripheral;
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry;
 | 
			
		||||
import dan200.computercraft.shared.common.AbstractContainerBlockEntity;
 | 
			
		||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
 | 
			
		||||
import dan200.computercraft.shared.container.BasicWorldlyContainer;
 | 
			
		||||
@@ -159,9 +160,7 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static boolean isPaper(ItemStack stack) {
 | 
			
		||||
        var item = stack.getItem();
 | 
			
		||||
        return item == Items.PAPER
 | 
			
		||||
            || (item instanceof PrintoutItem printout && printout.getType() == PrintoutItem.Type.PAGE);
 | 
			
		||||
        return stack.is(Items.PAPER) || stack.is(ModRegistry.Items.PRINTED_PAGE.get());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private boolean canInputPage() {
 | 
			
		||||
 
 | 
			
		||||
@@ -53,7 +53,7 @@ public class SpeakerBlockEntity extends BlockEntity {
 | 
			
		||||
 | 
			
		||||
        @Override
 | 
			
		||||
        public boolean equals(@Nullable IPeripheral other) {
 | 
			
		||||
            return this == other || (other instanceof Peripheral && speaker == ((Peripheral) other).speaker);
 | 
			
		||||
            return this == other || (other instanceof Peripheral o && speaker == o.speaker);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -44,11 +44,12 @@ public final class PocketBrain implements IPocketAccess {
 | 
			
		||||
    private int colour = -1;
 | 
			
		||||
    private int lightColour = -1;
 | 
			
		||||
 | 
			
		||||
    public PocketBrain(PocketHolder holder, @Nullable UpgradeData<IPocketUpgrade> upgrade, ServerComputer.Properties properties) {
 | 
			
		||||
    public PocketBrain(PocketHolder holder, @Nullable UpgradeData<IPocketUpgrade> upgrade, int colour, ServerComputer.Properties properties) {
 | 
			
		||||
        this.computer = new PocketServerComputer(this, holder, properties);
 | 
			
		||||
        this.holder = holder;
 | 
			
		||||
        this.position = holder.pos();
 | 
			
		||||
        this.upgrade = UpgradeData.copyOf(upgrade);
 | 
			
		||||
        this.colour = colour;
 | 
			
		||||
        invalidatePeripheral();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -272,7 +272,7 @@ public class PocketComputerItem extends Item implements IComputerItem, IColoured
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var brain = new PocketBrain(
 | 
			
		||||
            holder, getUpgradeWithData(stack),
 | 
			
		||||
            holder, getUpgradeWithData(stack), getColour(stack),
 | 
			
		||||
            ServerComputer.properties(getComputerID(stack), getFamily()).label(getLabel(stack))
 | 
			
		||||
        );
 | 
			
		||||
        var computer = brain.computer();
 | 
			
		||||
@@ -314,10 +314,14 @@ public class PocketComputerItem extends Item implements IComputerItem, IColoured
 | 
			
		||||
        // item. However, if we've just crafted the computer with an upgrade, we should sync the other way, and update
 | 
			
		||||
        // the computer.
 | 
			
		||||
        var server = level.getServer();
 | 
			
		||||
        if (server != null) {
 | 
			
		||||
            var computer = getServerComputer(server, stack);
 | 
			
		||||
            if (computer != null) computer.getBrain().setUpgrade(getUpgradeWithData(stack));
 | 
			
		||||
        }
 | 
			
		||||
        if (server == null) return;
 | 
			
		||||
 | 
			
		||||
        var computer = getServerComputer(server, stack);
 | 
			
		||||
        if (computer == null) return;
 | 
			
		||||
 | 
			
		||||
        var brain = computer.getBrain();
 | 
			
		||||
        brain.setUpgrade(getUpgradeWithData(stack));
 | 
			
		||||
        brain.setColour(getColour(stack));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // IComputerItem implementation
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,6 @@ public class PocketSpeaker extends AbstractPocketUpgrade {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void update(IPocketAccess access, @Nullable IPeripheral peripheral) {
 | 
			
		||||
        if (!(peripheral instanceof PocketSpeakerPeripheral)) return;
 | 
			
		||||
        ((PocketSpeakerPeripheral) peripheral).update();
 | 
			
		||||
        if (peripheral instanceof PocketSpeakerPeripheral speaker) speaker.update();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,9 @@ import dan200.computercraft.core.metrics.Metrics;
 | 
			
		||||
import dan200.computercraft.core.metrics.MetricsObserver;
 | 
			
		||||
import dan200.computercraft.shared.peripheral.generic.methods.AbstractInventoryMethods;
 | 
			
		||||
import dan200.computercraft.shared.turtle.core.*;
 | 
			
		||||
import org.jspecify.annotations.Nullable;
 | 
			
		||||
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Optional;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -659,6 +661,7 @@ public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
     * @cc.treturn [2] string The reason equipping this item failed.
 | 
			
		||||
     * @cc.since 1.6
 | 
			
		||||
     * @see #equipRight()
 | 
			
		||||
     * @see #getEquippedLeft()
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction
 | 
			
		||||
    public final MethodResult equipLeft() {
 | 
			
		||||
@@ -678,12 +681,45 @@ public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
     * @cc.treturn [2] string The reason equipping this item failed.
 | 
			
		||||
     * @cc.since 1.6
 | 
			
		||||
     * @see #equipLeft()
 | 
			
		||||
     * @see #getEquippedRight()
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction
 | 
			
		||||
    public final MethodResult equipRight() {
 | 
			
		||||
        return trackCommand(new TurtleEquipCommand(TurtleSide.RIGHT));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the upgrade currently equipped on the left of the turtle.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This returns information about the currently equipped item, in the same form as
 | 
			
		||||
     * {@link #getItemDetail(ILuaContext, Optional, Optional)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Information about the currently equipped item, or {@code nil} if no upgrade is equipped.
 | 
			
		||||
     * @see #equipLeft()
 | 
			
		||||
     * @cc.since 1.116.0
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction(mainThread = true)
 | 
			
		||||
    public final @Nullable Map<?, ?> getEquippedLeft() {
 | 
			
		||||
        var upgrade = turtle.getUpgradeWithData(TurtleSide.LEFT);
 | 
			
		||||
        return upgrade == null ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(upgrade.getUpgradeItem());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the upgrade currently equipped on the right of the turtle.
 | 
			
		||||
     * <p>
 | 
			
		||||
     * This returns information about the currently equipped item, in the same form as
 | 
			
		||||
     * {@link #getItemDetail(ILuaContext, Optional, Optional)}.
 | 
			
		||||
     *
 | 
			
		||||
     * @return Information about the currently equipped item, or {@code nil} if no upgrade is equipped.
 | 
			
		||||
     * @see #equipRight()
 | 
			
		||||
     * @cc.since 1.116.0
 | 
			
		||||
     */
 | 
			
		||||
    @LuaFunction(mainThread = true)
 | 
			
		||||
    public final @Nullable Map<?, ?> getEquippedRight() {
 | 
			
		||||
        var upgrade = turtle.getUpgradeWithData(TurtleSide.RIGHT);
 | 
			
		||||
        return upgrade == null ? null : VanillaDetailRegistries.ITEM_STACK.getDetails(upgrade.getUpgradeItem());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get information about the block in front of the turtle.
 | 
			
		||||
     *
 | 
			
		||||
@@ -745,7 +781,7 @@ public class TurtleAPI implements ILuaAPI {
 | 
			
		||||
     *                 more information about the item at the cost of taking longer to run.
 | 
			
		||||
     * @return The command result.
 | 
			
		||||
     * @throws LuaException If the slot is out of range.
 | 
			
		||||
     * @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty.
 | 
			
		||||
     * @cc.treturn nil|table Information about the item in this slot, or {@code nil} if it is empty.
 | 
			
		||||
     * @cc.since 1.64
 | 
			
		||||
     * @cc.changed 1.90.0 Added detailed parameter.
 | 
			
		||||
     * @cc.usage Print the current slot, assuming it contains 13 dirt.
 | 
			
		||||
 
 | 
			
		||||
@@ -62,14 +62,13 @@ public class TurtleDropCommand implements TurtleCommand {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (transferred) {
 | 
			
		||||
            case ContainerTransfer.NO_SPACE:
 | 
			
		||||
                return TurtleCommandResult.failure("No space for items");
 | 
			
		||||
            case ContainerTransfer.NO_ITEMS:
 | 
			
		||||
                return TurtleCommandResult.failure("No items to drop");
 | 
			
		||||
            default:
 | 
			
		||||
        return switch (transferred) {
 | 
			
		||||
            case ContainerTransfer.NO_SPACE -> TurtleCommandResult.failure("No space for items");
 | 
			
		||||
            case ContainerTransfer.NO_ITEMS -> TurtleCommandResult.failure("No items to drop");
 | 
			
		||||
            default -> {
 | 
			
		||||
                turtle.playAnimation(TurtleAnimation.WAIT);
 | 
			
		||||
                return TurtleCommandResult.success();
 | 
			
		||||
        }
 | 
			
		||||
                yield TurtleCommandResult.success();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -50,15 +50,14 @@ public class TurtleSuckCommand implements TurtleCommand {
 | 
			
		||||
        if (inventory != null) {
 | 
			
		||||
            // Take from inventory of thing in front
 | 
			
		||||
            var transferred = inventory.moveTo(TurtleUtil.getOffsetInventory(turtle), quantity);
 | 
			
		||||
            switch (transferred) {
 | 
			
		||||
                case ContainerTransfer.NO_SPACE:
 | 
			
		||||
                    return TurtleCommandResult.failure("No space for items");
 | 
			
		||||
                case ContainerTransfer.NO_ITEMS:
 | 
			
		||||
                    return TurtleCommandResult.failure("No items to take");
 | 
			
		||||
                default:
 | 
			
		||||
            return switch (transferred) {
 | 
			
		||||
                case ContainerTransfer.NO_SPACE -> TurtleCommandResult.failure("No space for items");
 | 
			
		||||
                case ContainerTransfer.NO_ITEMS -> TurtleCommandResult.failure("No items to take");
 | 
			
		||||
                default -> {
 | 
			
		||||
                    turtle.playAnimation(TurtleAnimation.WAIT);
 | 
			
		||||
                    return TurtleCommandResult.success();
 | 
			
		||||
            }
 | 
			
		||||
                    yield TurtleCommandResult.success();
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
        } else {
 | 
			
		||||
            // Suck up loose items off the ground
 | 
			
		||||
            var aabb = new AABB(
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,9 @@ public final class TurtleUpgradeRecipe extends CustomRecipe {
 | 
			
		||||
            itemTurtle.getUpgradeWithData(turtle, TurtleSide.RIGHT),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Get the upgrades for the new items
 | 
			
		||||
        // Get the upgrades for the new items.
 | 
			
		||||
        // Note: because the turtle is facing towards us, the directions are flipped. Items placed to the left
 | 
			
		||||
        // of the turtle, are equipped on its right (and vice versa).
 | 
			
		||||
        var items = new ItemStack[]{ rightItem, leftItem };
 | 
			
		||||
        for (var i = 0; i < 2; i++) {
 | 
			
		||||
            if (!items[i].isEmpty()) {
 | 
			
		||||
 
 | 
			
		||||
@@ -70,9 +70,9 @@ public final class DropConsumer {
 | 
			
		||||
 | 
			
		||||
    public static boolean onEntitySpawn(Entity entity) {
 | 
			
		||||
        // Capture any nearby item spawns
 | 
			
		||||
        if (dropWorld == entity.level() && entity instanceof ItemEntity
 | 
			
		||||
        if (dropWorld == entity.level() && entity instanceof ItemEntity item
 | 
			
		||||
            && assertNonNull(dropBounds).contains(entity.position())) {
 | 
			
		||||
            handleDrops(((ItemEntity) entity).getItem());
 | 
			
		||||
            handleDrops(item.getItem());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ public final class InventoryUtil {
 | 
			
		||||
     */
 | 
			
		||||
    public static int getInventorySlotFromCompartment(Player player, int slot, ItemStack stack) {
 | 
			
		||||
        if (stack.isEmpty()) throw new IllegalArgumentException("Cannot search for empty stack");
 | 
			
		||||
        if (player.getInventory().getItem(slot) == stack) return slot;
 | 
			
		||||
        if (slot >= 0 && slot < Inventory.INVENTORY_SIZE && player.getInventory().getItem(slot) == stack) return slot;
 | 
			
		||||
        if (player.getInventory().getItem(Inventory.SLOT_OFFHAND) == stack) return Inventory.SLOT_OFFHAND;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -79,8 +79,8 @@ public class PrettyJsonWriter extends JsonWriter {
 | 
			
		||||
 | 
			
		||||
        // Otherwise we either need to push to our list or finish a record pair.
 | 
			
		||||
        var head = stack.getLast();
 | 
			
		||||
        if (head instanceof DocList) {
 | 
			
		||||
            ((DocList) head).add(object);
 | 
			
		||||
        if (head instanceof DocList headList) {
 | 
			
		||||
            headList.add(object);
 | 
			
		||||
        } else {
 | 
			
		||||
            stack.removeLast();
 | 
			
		||||
            ((DocList) stack.getLast()).add(new Pair((String) head, object));
 | 
			
		||||
 
 | 
			
		||||
@@ -165,7 +165,7 @@ public final class TickScheduler {
 | 
			
		||||
        UNLOADED,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private record ChunkReference(ResourceKey<Level> level, Long position) {
 | 
			
		||||
    private record ChunkReference(ResourceKey<Level> level, long position) {
 | 
			
		||||
        @Override
 | 
			
		||||
        public String toString() {
 | 
			
		||||
            return "ChunkReference(" + level + " at " + new ChunkPos(position) + ")";
 | 
			
		||||
 
 | 
			
		||||
@@ -205,7 +205,9 @@
 | 
			
		||||
    "item.computercraft.treasure_disk": "Disketa",
 | 
			
		||||
    "itemGroup.computercraft": "ComputerCraft",
 | 
			
		||||
    "tag.item.computercraft.computer": "Počítače",
 | 
			
		||||
    "tag.item.computercraft.disks": "Disky",
 | 
			
		||||
    "tag.item.computercraft.monitor": "Monitory",
 | 
			
		||||
    "tag.item.computercraft.pocket_computers": "Kapesní počítače",
 | 
			
		||||
    "tag.item.computercraft.turtle": "Roboti",
 | 
			
		||||
    "tag.item.computercraft.wired_modem": "Drátové modemy",
 | 
			
		||||
    "tracking_field.computercraft.avg": "%s (průměr)",
 | 
			
		||||
@@ -215,7 +217,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "Stahování HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "Požadavky HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "Nahrávání HTTP",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Java alokace",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (max)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "Periferní volání",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "Serverové úlohy",
 | 
			
		||||
 
 | 
			
		||||
@@ -206,7 +206,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "Descarga HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "Peticiones HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "Subida HTTP",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Asignaciones de Java",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (max)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "Llamadas del periférico",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "Tareas del servidor",
 | 
			
		||||
 
 | 
			
		||||
@@ -215,7 +215,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "Téléchargement HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "Requêtes HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "Publication HTTP",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Allocations Java",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (max)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "Appels aux périphériques",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "Tâches du serveur",
 | 
			
		||||
 
 | 
			
		||||
@@ -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"
 | 
			
		||||
}
 | 
			
		||||
@@ -12,9 +12,12 @@
 | 
			
		||||
    "block.computercraft.cable": "Cavo Di Rete",
 | 
			
		||||
    "block.computercraft.computer_advanced": "Computer Avanzato",
 | 
			
		||||
    "block.computercraft.computer_command": "Computer Comando",
 | 
			
		||||
    "block.computercraft.computer_normal": "Computer",
 | 
			
		||||
    "block.computercraft.disk_drive": "Lettore Di Dischi",
 | 
			
		||||
    "block.computercraft.monitor_advanced": "Monitor Avanzato",
 | 
			
		||||
    "block.computercraft.monitor_normal": "Monitor",
 | 
			
		||||
    "block.computercraft.printer": "Stampante",
 | 
			
		||||
    "block.computercraft.redstone_relay": "Relè di redstone",
 | 
			
		||||
    "block.computercraft.speaker": "Altoparlante",
 | 
			
		||||
    "block.computercraft.turtle_advanced": "Tartaruga Avanzata",
 | 
			
		||||
    "block.computercraft.turtle_advanced.upgraded": "Tartaruga %s Avanzata",
 | 
			
		||||
@@ -35,6 +38,7 @@
 | 
			
		||||
    "commands.computercraft.dump.synopsis": "Mostra lo stato dei computer.",
 | 
			
		||||
    "commands.computercraft.generic.additional_rows": "%d colonne aggiuntive…",
 | 
			
		||||
    "commands.computercraft.generic.exception": "Eccezione non gestita (%s)",
 | 
			
		||||
    "commands.computercraft.generic.no": "N",
 | 
			
		||||
    "commands.computercraft.generic.yes": "S",
 | 
			
		||||
    "commands.computercraft.help.desc": "Mostra questo messaggio d'aiuto",
 | 
			
		||||
    "commands.computercraft.help.no_children": "%s non ha sottocomandi",
 | 
			
		||||
@@ -50,6 +54,7 @@
 | 
			
		||||
    "commands.computercraft.tp.desc": "Teletrasporta alla posizione di un computer. Puoi specificare il computer con l'instance id (e.g. 123) o con l'id (e.g. #123).",
 | 
			
		||||
    "commands.computercraft.tp.synopsis": "Teletrasporta al computer specificato.",
 | 
			
		||||
    "commands.computercraft.track.desc": "Monitora per quanto tempo i computer vengono eseguiti e quanti eventi ricevono. Questo comando fornisce le informazioni in modo simile a /forge track e può essere utile per diagnosticare il lag.",
 | 
			
		||||
    "commands.computercraft.track.dump.computer": "Computer",
 | 
			
		||||
    "commands.computercraft.track.dump.desc": "Cancella gli ultimi risultati del monitoraggio dei computer.",
 | 
			
		||||
    "commands.computercraft.track.dump.no_timings": "No ci sono tempi disponibili",
 | 
			
		||||
    "commands.computercraft.track.dump.synopsis": "Cancella gli ultimi risultati monitorati",
 | 
			
		||||
@@ -86,6 +91,7 @@
 | 
			
		||||
    "gui.computercraft.config.execution.tooltip": "Controlla comportamento esecuzione dei computer. Questo è largamente utilizzato\nper ritoccare la performance dei server, e generale non dovrebbe essere toccato.",
 | 
			
		||||
    "gui.computercraft.config.floppy_space_limit": "Limite spazio Disco Floppy (bytes)",
 | 
			
		||||
    "gui.computercraft.config.floppy_space_limit.tooltip": "Limite di spazio di archiviazione per i dischi floppy, in byte.",
 | 
			
		||||
    "gui.computercraft.config.http": "HTTP",
 | 
			
		||||
    "gui.computercraft.config.http.bandwidth": "Banda larga",
 | 
			
		||||
    "gui.computercraft.config.http.bandwidth.global_download": "Limite download globale",
 | 
			
		||||
    "gui.computercraft.config.http.bandwidth.global_download.tooltip": "Numero di byte che possono essere scaricati in un secondo. Questo è condiviso tra tutti i computer. (bytes/s).",
 | 
			
		||||
@@ -98,6 +104,7 @@
 | 
			
		||||
    "gui.computercraft.config.http.max_requests.tooltip": "Il numero di richieste http che un computer può fare alla volta. Ulteriori richieste verranno messe in coda, ed inviate quando le richieste correnti sono terminate. Imposta a 0 per illimitato.",
 | 
			
		||||
    "gui.computercraft.config.http.max_websockets": "Connessioni websocket massime",
 | 
			
		||||
    "gui.computercraft.config.http.max_websockets.tooltip": "Il numero di websocket che un computer può avere aperte allo stesso momento.Imposta a 0 per illimitato.",
 | 
			
		||||
    "gui.computercraft.config.http.proxy": "Proxy",
 | 
			
		||||
    "gui.computercraft.config.http.proxy.host": "Nome host",
 | 
			
		||||
    "gui.computercraft.config.http.proxy.host.tooltip": "Il nome dell'host o l'indirizzo IP del server proxy.",
 | 
			
		||||
    "gui.computercraft.config.http.proxy.port": "Porta",
 | 
			
		||||
@@ -135,16 +142,24 @@
 | 
			
		||||
    "gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "Il limite di quanti dati dei monitor possono essere inviati *al tick*. Nota:\n - La banda larga è misurata prima della compressione, così che il dato inviato al client è\n   più piccolo.\n - Questo ignora il numero di giocatori a cui viene inviato il pacchetto. Aggiornare un monitor\n   per un giocatore consuma lo stesso limite di banda larga dell'invio a 20 giocatori.\n - Un monitor alla massima grandezza invia ~25kb di dati. Quindi il valore predefinito (1MB) concede\n   ~40 monitor di essere aggiornati in un singolo tick.\nImposta a 0 per disattivare.",
 | 
			
		||||
    "gui.computercraft.config.peripheral.tooltip": "Opzioni varie riguardo le periferiche.",
 | 
			
		||||
    "gui.computercraft.config.term_sizes": "Dimensioni terminale",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer": "Computer",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer.height": "Altezza terminale",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer.height.tooltip": "Altezza del terminale del computer",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer.tooltip": "Dimensioni del terminale dei computer.",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer.width": "Larghezza terminale",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer.width.tooltip": "Larghezza del terminale del computer",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.monitor": "Monitor",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.monitor.height": "Massima altezza del monitor",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.monitor.height.tooltip": "Altezza massima dei monitor",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.monitor.tooltip": "Massima grandezza dei monitor (in blocchi).",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.monitor.width": "Larghezza massima del monitor",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.monitor.width.tooltip": "Larghezza massima dei monitor",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.pocket_computer": "Computer Tascabile",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.pocket_computer.height": "Altezza terminale",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "Altezza del terminale dei computer tascabili",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.pocket_computer.tooltip": "Dimensioni del terminale dei computer tascabili.",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.pocket_computer.width": "Larghezza terminale",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "Larghezza del terminale del computer tascabile",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.tooltip": "Configura le dimensioni dei terminali di vari computer.\nTerminali più grandi richiedono più banda larga, usa con cautela.",
 | 
			
		||||
    "gui.computercraft.config.turtle": "Tartarughe",
 | 
			
		||||
    "gui.computercraft.config.turtle.advanced_fuel_limit": "Limite carburante tartarughe avanzate",
 | 
			
		||||
@@ -188,6 +203,7 @@
 | 
			
		||||
    "item.computercraft.printed_page": "Pagina Stampata",
 | 
			
		||||
    "item.computercraft.printed_pages": "Pagine Stampate",
 | 
			
		||||
    "item.computercraft.treasure_disk": "Disco Floppy",
 | 
			
		||||
    "itemGroup.computercraft": "ComputerCraft",
 | 
			
		||||
    "tag.item.computercraft.computer": "Computer",
 | 
			
		||||
    "tag.item.computercraft.monitor": "Monitor",
 | 
			
		||||
    "tag.item.computercraft.turtle": "Tartarughe",
 | 
			
		||||
@@ -199,7 +215,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "Download HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "Richieste HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "Upload HTTP",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Allocazioni Java",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (massimo)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "Chiamate alle periferiche",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "Attività server",
 | 
			
		||||
@@ -207,6 +222,8 @@
 | 
			
		||||
    "tracking_field.computercraft.websocket_incoming.name": "Websocket in arrivo",
 | 
			
		||||
    "tracking_field.computercraft.websocket_outgoing.name": "Websocket in uscita",
 | 
			
		||||
    "upgrade.computercraft.speaker.adjective": "Rumoroso",
 | 
			
		||||
    "upgrade.computercraft.wireless_modem_advanced.adjective": "Ender",
 | 
			
		||||
    "upgrade.computercraft.wireless_modem_normal.adjective": "Senza fili",
 | 
			
		||||
    "upgrade.minecraft.crafting_table.adjective": "Artigiana",
 | 
			
		||||
    "upgrade.minecraft.diamond_axe.adjective": "Taglialegna",
 | 
			
		||||
    "upgrade.minecraft.diamond_hoe.adjective": "Contadina",
 | 
			
		||||
 
 | 
			
		||||
@@ -205,7 +205,9 @@
 | 
			
		||||
    "item.computercraft.treasure_disk": "フロッピーディスク",
 | 
			
		||||
    "itemGroup.computercraft": "ComputerCraft",
 | 
			
		||||
    "tag.item.computercraft.computer": "コンピューター",
 | 
			
		||||
    "tag.item.computercraft.disks": "ディスク",
 | 
			
		||||
    "tag.item.computercraft.monitor": "モニター",
 | 
			
		||||
    "tag.item.computercraft.pocket_computers": "ポケットコンピューター",
 | 
			
		||||
    "tag.item.computercraft.turtle": "タートル",
 | 
			
		||||
    "tag.item.computercraft.wired_modem": "有線モデム",
 | 
			
		||||
    "tracking_field.computercraft.avg": "%s (平均)",
 | 
			
		||||
@@ -215,7 +217,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "HTTPダウンロード",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "HTTPリクエスト",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "HTTPアップロード",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Java割当",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (最大)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "実行呼び出し",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "サーバータスク",
 | 
			
		||||
 
 | 
			
		||||
@@ -208,7 +208,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "Download HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "Solicitações HTTP",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "Upload de HTTP",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Alocações Java",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (máximo)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "Chamadas Periféricas",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "Tarefas do servidor",
 | 
			
		||||
 
 | 
			
		||||
@@ -109,6 +109,7 @@
 | 
			
		||||
    "gui.computercraft.config.log_computer_errors": "Регистрировать ошибки компьютера",
 | 
			
		||||
    "gui.computercraft.config.log_computer_errors.tooltip": "Регистрировать исключения, вызванные периферийными устройствами и другими объектами Lua. Это облегчает\nдля авторам модов устранение проблем, но может привести к спаму в логах, если люди будут использовать\nглючные методы.",
 | 
			
		||||
    "gui.computercraft.config.maximum_open_files": "Максимальное количество файлов, открытых на одном компьютере",
 | 
			
		||||
    "gui.computercraft.config.peripheral": "Периферия",
 | 
			
		||||
    "gui.computercraft.config.term_sizes": "Размер терминала",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer": "Компьютер",
 | 
			
		||||
    "gui.computercraft.config.term_sizes.computer.height": "Высота терминала",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,14 @@
 | 
			
		||||
{
 | 
			
		||||
    "argument.computercraft.argument_expected": "Argument förväntas",
 | 
			
		||||
    "argument.computercraft.computer.distance": "Distans till entitet",
 | 
			
		||||
    "argument.computercraft.computer.family": "Datorfamilj",
 | 
			
		||||
    "argument.computercraft.computer.id": "Dator-ID",
 | 
			
		||||
    "argument.computercraft.computer.instance": "Unikt instans-ID",
 | 
			
		||||
    "argument.computercraft.computer.label": "Datoretikett",
 | 
			
		||||
    "argument.computercraft.computer.many_matching": "Flera datorer matchar '%s' (%s träffar)",
 | 
			
		||||
    "argument.computercraft.computer.no_matching": "Inga datorer matchar '%s'",
 | 
			
		||||
    "argument.computercraft.tracking_field.no_field": "Okänt fält '%s'",
 | 
			
		||||
    "argument.computercraft.unknown_computer_family": "Okänd datorfamilj '%s'",
 | 
			
		||||
    "block.computercraft.cable": "Nätverkskabel",
 | 
			
		||||
    "block.computercraft.computer_advanced": "Avancerad Dator",
 | 
			
		||||
    "block.computercraft.computer_command": "Kommandodator",
 | 
			
		||||
@@ -66,7 +72,10 @@
 | 
			
		||||
    "commands.computercraft.view.desc": "Öppna datorns terminal för att möjligöra fjärrstyrning. Detta ger inte tillgång till turtlens inventory. Du kan ange en dators instans-id (t.ex. 123) eller dator-id (t.ex. #123).",
 | 
			
		||||
    "commands.computercraft.view.not_player": "Kan inte öppna terminalen för en ickespelare",
 | 
			
		||||
    "commands.computercraft.view.synopsis": "Titta på datorns terminal.",
 | 
			
		||||
    "gui.computercraft.config.command_require_creative": "Kommandodatorer kräver kreativt läge",
 | 
			
		||||
    "gui.computercraft.config.command_require_creative.tooltip": "Kräv att spelare är i kreativt läge och har operatörsrättigheter för att kunna interagera med kommandodatorer.\nDetta är standardbeteendet för vaniljversionens kommandoblock.",
 | 
			
		||||
    "gui.computercraft.config.computer_space_limit": "Dator maximalt utrymme (bytes)",
 | 
			
		||||
    "gui.computercraft.config.computer_space_limit.tooltip": "Gränsen för diskutrymme för datorer och sköldpaddor, i bytes.",
 | 
			
		||||
    "gui.computercraft.config.default_computer_settings": "Standard Datorinställningar",
 | 
			
		||||
    "gui.computercraft.config.execution.computer_threads": "Dator trådar",
 | 
			
		||||
    "gui.computercraft.config.floppy_space_limit": "Diskett maximalt utrymme (bytes)",
 | 
			
		||||
 
 | 
			
		||||
@@ -205,7 +205,9 @@
 | 
			
		||||
    "item.computercraft.treasure_disk": "Disket",
 | 
			
		||||
    "itemGroup.computercraft": "ComputerCraft",
 | 
			
		||||
    "tag.item.computercraft.computer": "Bilgisayarlar",
 | 
			
		||||
    "tag.item.computercraft.disks": "Diskler",
 | 
			
		||||
    "tag.item.computercraft.monitor": "Monitörler",
 | 
			
		||||
    "tag.item.computercraft.pocket_computers": "Cep Bilgisayarları",
 | 
			
		||||
    "tag.item.computercraft.turtle": "Turtlelar",
 | 
			
		||||
    "tag.item.computercraft.wired_modem": "Kablolu modemler",
 | 
			
		||||
    "tracking_field.computercraft.avg": "%s (ort.)",
 | 
			
		||||
@@ -215,7 +217,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "HTTP indirme",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "HTTP istekleri",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "HTTP yükleme",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Java'ya Ayrılan",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (azami)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "Çevre birimi çağrıları",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "Sunucu görevleri",
 | 
			
		||||
 
 | 
			
		||||
@@ -215,7 +215,6 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "HTTP завантаження",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "HTTP запитів",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "HTTP завантаження",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Java Виділення",
 | 
			
		||||
    "tracking_field.computercraft.max": "%s (макс)",
 | 
			
		||||
    "tracking_field.computercraft.peripheral.name": "Викликів преферійних девайсів",
 | 
			
		||||
    "tracking_field.computercraft.server_tasks.name": "Серверних задач",
 | 
			
		||||
 
 | 
			
		||||
@@ -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,17 +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.monitor": "监视器",
 | 
			
		||||
    "tag.item.computercraft.disks": "软盘",
 | 
			
		||||
    "tag.item.computercraft.monitor": "显示器",
 | 
			
		||||
    "tag.item.computercraft.pocket_computers": "便携式计算机",
 | 
			
		||||
    "tag.item.computercraft.turtle": "海龟",
 | 
			
		||||
    "tag.item.computercraft.wired_modem": "有线调制解调器",
 | 
			
		||||
    "tracking_field.computercraft.avg": "%s (平均)",
 | 
			
		||||
@@ -215,14 +217,13 @@
 | 
			
		||||
    "tracking_field.computercraft.http_download.name": "HTTP下载",
 | 
			
		||||
    "tracking_field.computercraft.http_requests.name": "HTTP请求",
 | 
			
		||||
    "tracking_field.computercraft.http_upload.name": "HTTP上传",
 | 
			
		||||
    "tracking_field.computercraft.java_allocation.name": "Java分配",
 | 
			
		||||
    "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": "合成",
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
    "parent": "computercraft:block/turtle_base",
 | 
			
		||||
    "textures": {
 | 
			
		||||
        "texture": "computercraft:block/turtle_colour",
 | 
			
		||||
        "particle": "computercraft:block/turtle_colour_body_front",
 | 
			
		||||
        "body_back": "computercraft:block/turtle_colour_body_back",
 | 
			
		||||
        "body_backpack": "computercraft:block/turtle_colour_body_backpack",
 | 
			
		||||
        "body_bottom": "computercraft:block/turtle_colour_body_bottom",
 | 
			
		||||
 
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 136 B  | 
@@ -142,7 +142,7 @@ public class NetworkBenchmark {
 | 
			
		||||
        return networks;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static class Grid<T> {
 | 
			
		||||
    private static final class Grid<T> {
 | 
			
		||||
        private final int size;
 | 
			
		||||
        private final T[] box;
 | 
			
		||||
 | 
			
		||||
@@ -152,7 +152,7 @@ public class NetworkBenchmark {
 | 
			
		||||
            this.box = (T[]) new Object[size * size * size];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public T get(BlockPos pos) {
 | 
			
		||||
        private T get(BlockPos pos) {
 | 
			
		||||
            int x = pos.getX(), y = pos.getY(), z = pos.getZ();
 | 
			
		||||
 | 
			
		||||
            return x >= 0 && x < size && y >= 0 && y < size && z >= 0 && z < size
 | 
			
		||||
@@ -160,7 +160,7 @@ public class NetworkBenchmark {
 | 
			
		||||
                : null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void forEach(BiConsumer<T, BlockPos> transform) {
 | 
			
		||||
        private void forEach(BiConsumer<T, BlockPos> transform) {
 | 
			
		||||
            for (var x = 0; x < size; x++) {
 | 
			
		||||
                for (var y = 0; y < size; y++) {
 | 
			
		||||
                    for (var z = 0; z < size; z++) {
 | 
			
		||||
@@ -170,7 +170,7 @@ public class NetworkBenchmark {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public void map(BiFunction<T, BlockPos, T> transform) {
 | 
			
		||||
        private void map(BiFunction<T, BlockPos, T> transform) {
 | 
			
		||||
            for (var x = 0; x < size; x++) {
 | 
			
		||||
                for (var y = 0; y < size; y++) {
 | 
			
		||||
                    for (var z = 0; z < size; z++) {
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,11 @@ public class ItemStackMatcher extends TypeSafeMatcher<ItemStack> {
 | 
			
		||||
        description.appendValue(stack).appendValue(stack.getTag());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void describeMismatchSafely(ItemStack item, Description description) {
 | 
			
		||||
        description.appendText("was ").appendValue(item).appendValue(item.getTag());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Matcher<ItemStack> isStack(ItemStack stack) {
 | 
			
		||||
        return new ItemStackMatcher(stack);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ class CCTestCommand {
 | 
			
		||||
            }))
 | 
			
		||||
            .then(literal("regen-structures").executes(context -> {
 | 
			
		||||
                for (var function : GameTestRegistry.getAllTestFunctions()) {
 | 
			
		||||
                    dispatcher.execute("test import " + function.getTestName(), context.getSource());
 | 
			
		||||
                    dispatcher.execute("test import " + function.getStructureName(), context.getSource());
 | 
			
		||||
                    TestCommandAccessor.callExportTestStructure(context.getSource(), function.getStructureName());
 | 
			
		||||
                }
 | 
			
		||||
                return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,39 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.mixin.gametest;
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.gametest.core.TestHooks;
 | 
			
		||||
import net.minecraft.nbt.CompoundTag;
 | 
			
		||||
import net.minecraft.nbt.NbtUtils;
 | 
			
		||||
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.Objects;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Patches {@link NbtUtils#structureToSnbt(CompoundTag)} to remove air blocks from the structure file. This
 | 
			
		||||
 * significantly reduces the size of our generated templates.
 | 
			
		||||
 *
 | 
			
		||||
 * @see StructureUtilsMixin Loading structures
 | 
			
		||||
 * @see NbtUtils#structureToSnbt(CompoundTag)
 | 
			
		||||
 */
 | 
			
		||||
@Mixin(NbtUtils.class)
 | 
			
		||||
class NbtUtilsMixin {
 | 
			
		||||
    @Inject(method = "structureToSnbt", at = @At("HEAD"))
 | 
			
		||||
    @SuppressWarnings("unused")
 | 
			
		||||
    private static void structureToSnbt(CompoundTag tag, CallbackInfoReturnable<String> ci) {
 | 
			
		||||
        // Load in the structure, strip out air, then save it back again.
 | 
			
		||||
        var structure = Objects.requireNonNull(TestHooks.getStructureManager()).readStructure(tag);
 | 
			
		||||
        var palette = ((StructureTemplateAccessor) structure).getPalettes().get(0);
 | 
			
		||||
        palette.blocks().removeIf(x -> x.state().isAir());
 | 
			
		||||
        var newTag = structure.save(new CompoundTag());
 | 
			
		||||
 | 
			
		||||
        // Overwrite the existing tag.
 | 
			
		||||
        tag.getAllKeys().clear();
 | 
			
		||||
        for (var key : newTag.getAllKeys()) tag.put(key, newTag.get(key));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,17 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.mixin.gametest;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
 | 
			
		||||
import org.spongepowered.asm.mixin.Mixin;
 | 
			
		||||
import org.spongepowered.asm.mixin.gen.Accessor;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
@Mixin(StructureTemplate.class)
 | 
			
		||||
interface StructureTemplateAccessor {
 | 
			
		||||
    @Accessor
 | 
			
		||||
    List<StructureTemplate.Palette> getPalettes();
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,55 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.mixin.gametest;
 | 
			
		||||
 | 
			
		||||
import net.minecraft.core.BlockPos;
 | 
			
		||||
import net.minecraft.gametest.framework.StructureUtils;
 | 
			
		||||
import net.minecraft.server.level.ServerLevel;
 | 
			
		||||
import net.minecraft.world.level.block.Blocks;
 | 
			
		||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate;
 | 
			
		||||
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.HashSet;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add missing {@link Blocks#AIR} to our "reduced" game test structures.
 | 
			
		||||
 *
 | 
			
		||||
 * @see NbtUtilsMixin Saving structures
 | 
			
		||||
 * @see StructureUtils#getStructureTemplate(String, ServerLevel)
 | 
			
		||||
 */
 | 
			
		||||
@Mixin(StructureUtils.class)
 | 
			
		||||
class StructureUtilsMixin {
 | 
			
		||||
    @Inject(
 | 
			
		||||
        method = "getStructureTemplate",
 | 
			
		||||
        at = @At(
 | 
			
		||||
            value = "INVOKE",
 | 
			
		||||
            target = "Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplateManager;readStructure(Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate;",
 | 
			
		||||
            shift = At.Shift.AFTER
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    @SuppressWarnings("unused")
 | 
			
		||||
    private static void getStructureTemplate(String structureName, ServerLevel serverLevel, CallbackInfoReturnable<StructureTemplate> ci) {
 | 
			
		||||
        var template = ci.getReturnValue();
 | 
			
		||||
        var size = template.getSize();
 | 
			
		||||
        var palette = ((StructureTemplateAccessor) template).getPalettes().get(0);
 | 
			
		||||
 | 
			
		||||
        Set<BlockPos> positions = new HashSet<>();
 | 
			
		||||
        for (var x = 0; x < size.getX(); x++) {
 | 
			
		||||
            for (var y = 0; y < size.getY(); y++) {
 | 
			
		||||
                for (var z = 0; z < size.getZ(); z++) positions.add(new BlockPos(x, y, z));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (var block : palette.blocks()) positions.remove(block.pos());
 | 
			
		||||
 | 
			
		||||
        for (var pos : positions) {
 | 
			
		||||
            palette.blocks().add(new StructureTemplate.StructureBlockInfo(pos, Blocks.AIR.defaultBlockState(), null));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -187,4 +187,22 @@ class Disk_Drive_Test {
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts items can be inserted into a disk drive.
 | 
			
		||||
     */
 | 
			
		||||
    @GameTest
 | 
			
		||||
    fun Can_insert_items(helper: GameTestHelper) = helper.sequence {
 | 
			
		||||
        thenWaitUntil {
 | 
			
		||||
            helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(ModRegistry.Items.COMPUTER_NORMAL.get())))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts items can be removed from a disk drive.
 | 
			
		||||
     */
 | 
			
		||||
    @GameTest
 | 
			
		||||
    fun Can_extract_items(helper: GameTestHelper) = helper.sequence {
 | 
			
		||||
        thenWaitUntil { helper.assertContainerEmpty(BlockPos(2, 3, 2)) }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,36 @@
 | 
			
		||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
 | 
			
		||||
//
 | 
			
		||||
// SPDX-License-Identifier: MPL-2.0
 | 
			
		||||
 | 
			
		||||
package dan200.computercraft.gametest
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.core.util.Colour
 | 
			
		||||
import dan200.computercraft.gametest.api.craftItem
 | 
			
		||||
import dan200.computercraft.gametest.api.immediate
 | 
			
		||||
import dan200.computercraft.shared.media.items.DiskItem
 | 
			
		||||
import dan200.computercraft.test.shared.ItemStackMatcher.isStack
 | 
			
		||||
import net.minecraft.gametest.framework.GameTest
 | 
			
		||||
import net.minecraft.gametest.framework.GameTestHelper
 | 
			
		||||
import net.minecraft.world.item.ItemStack
 | 
			
		||||
import net.minecraft.world.item.Items
 | 
			
		||||
import org.hamcrest.MatcherAssert.assertThat
 | 
			
		||||
 | 
			
		||||
class Disk_Test {
 | 
			
		||||
    /**
 | 
			
		||||
     * Ensure disks
 | 
			
		||||
     */
 | 
			
		||||
    @GameTest(template = "default")
 | 
			
		||||
    fun Can_craft_disk(helper: GameTestHelper) = helper.immediate {
 | 
			
		||||
        assertThat(
 | 
			
		||||
            "Disk without dye",
 | 
			
		||||
            helper.craftItem(ItemStack(Items.REDSTONE), ItemStack(Items.PAPER)),
 | 
			
		||||
            isStack(DiskItem.createFromIDAndColour(-1, null, Colour.BLUE.hex)),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        assertThat(
 | 
			
		||||
            "Disk with dye",
 | 
			
		||||
            helper.craftItem(ItemStack(Items.REDSTONE), ItemStack(Items.PAPER), ItemStack(Items.GREEN_DYE)),
 | 
			
		||||
            isStack(DiskItem.createFromIDAndColour(-1, null, Colour.GREEN.hex)),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -188,6 +188,25 @@ class Printer_Test {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts items can be inserted into a printer.
 | 
			
		||||
     */
 | 
			
		||||
    @GameTest(required = false) // Allow on Forge for now, see #1951.
 | 
			
		||||
    fun Can_insert_items(helper: GameTestHelper) = helper.sequence {
 | 
			
		||||
        thenWaitUntil {
 | 
			
		||||
            helper.assertContainerExactly(BlockPos(1, 2, 2), listOf(ItemStack.EMPTY, ItemStack(Items.PAPER)))
 | 
			
		||||
            helper.assertContainerExactly(BlockPos(3, 2, 2), listOf(ItemStack(Items.BLACK_DYE)))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Asserts items can be removed from a printer.
 | 
			
		||||
     */
 | 
			
		||||
    @GameTest
 | 
			
		||||
    fun Can_extract_items(helper: GameTestHelper) = helper.sequence {
 | 
			
		||||
        thenWaitUntil { helper.assertContainerEmpty(BlockPos(2, 3, 2)) }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun createPageOf(c: Char): Array<String> {
 | 
			
		||||
        val line = c.toString().repeat(PrintoutItem.LINE_MAX_LENGTH)
 | 
			
		||||
        return Array(PrintoutItem.LINES_PER_PAGE) { line }
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,17 @@
 | 
			
		||||
package dan200.computercraft.gametest
 | 
			
		||||
 | 
			
		||||
import dan200.computercraft.gametest.api.*
 | 
			
		||||
import dan200.computercraft.shared.ModRegistry
 | 
			
		||||
import dan200.computercraft.shared.media.items.PrintoutItem
 | 
			
		||||
import dan200.computercraft.test.shared.ItemStackMatcher.isStack
 | 
			
		||||
import net.minecraft.gametest.framework.GameTest
 | 
			
		||||
import net.minecraft.gametest.framework.GameTestGenerator
 | 
			
		||||
import net.minecraft.gametest.framework.GameTestHelper
 | 
			
		||||
import net.minecraft.gametest.framework.TestFunction
 | 
			
		||||
import net.minecraft.world.item.ItemStack
 | 
			
		||||
import net.minecraft.world.item.Items
 | 
			
		||||
import org.hamcrest.MatcherAssert.assertThat
 | 
			
		||||
import org.junit.jupiter.api.Assertions.assertEquals
 | 
			
		||||
 | 
			
		||||
class Printout_Test {
 | 
			
		||||
    /**
 | 
			
		||||
@@ -56,4 +64,52 @@ class Printout_Test {
 | 
			
		||||
 | 
			
		||||
        thenExecute { helper.level.dayTime = Times.NOON }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GameTest(template = "default")
 | 
			
		||||
    fun Craft_pages(helper: GameTestHelper) = helper.immediate {
 | 
			
		||||
        // Assert that crafting with only one page fails
 | 
			
		||||
        helper.assertNotCraftable(ItemStack(ModRegistry.Items.PRINTED_PAGE.get()), ItemStack(Items.STRING))
 | 
			
		||||
 | 
			
		||||
        // Assert that crafting with no pages fails
 | 
			
		||||
        helper.assertNotCraftable(ItemStack(Items.PAPER), ItemStack(Items.PAPER), ItemStack(Items.STRING))
 | 
			
		||||
 | 
			
		||||
        // Assert that crafting with a book fails
 | 
			
		||||
        helper.assertNotCraftable(ItemStack(ModRegistry.Items.PRINTED_PAGE.get()), ItemStack(ModRegistry.Items.PRINTED_BOOK.get()), ItemStack(Items.STRING))
 | 
			
		||||
 | 
			
		||||
        assertThat(
 | 
			
		||||
            helper.craftItem(
 | 
			
		||||
                PrintoutItem.createSingleFromTitleAndText("First", createPagesOf(' '), createPagesOf('b')),
 | 
			
		||||
                PrintoutItem.createMultipleFromTitleAndText("Second", createPagesOf(' '), createPagesOf('b')),
 | 
			
		||||
                ItemStack(Items.STRING),
 | 
			
		||||
            ),
 | 
			
		||||
            isStack(PrintoutItem.createMultipleFromTitleAndText("First", createPagesOf(' ', 2), createPagesOf('b', 2))),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @GameTest(template = "default")
 | 
			
		||||
    fun Craft_book(helper: GameTestHelper) = helper.immediate {
 | 
			
		||||
        // Assert that crafting with no pages fails
 | 
			
		||||
        helper.assertNotCraftable(ItemStack(Items.PAPER), ItemStack(Items.PAPER), ItemStack(Items.STRING), ItemStack(Items.LEATHER))
 | 
			
		||||
 | 
			
		||||
        // Assert that crafting with only one page works
 | 
			
		||||
        assertEquals(
 | 
			
		||||
            ModRegistry.Items.PRINTED_BOOK.get(),
 | 
			
		||||
            helper.craftItem(ItemStack(ModRegistry.Items.PRINTED_PAGE.get()), ItemStack(Items.STRING), ItemStack(Items.LEATHER)).item,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        assertThat(
 | 
			
		||||
            helper.craftItem(
 | 
			
		||||
                PrintoutItem.createSingleFromTitleAndText("First", createPagesOf(' '), createPagesOf('b')),
 | 
			
		||||
                PrintoutItem.createMultipleFromTitleAndText("Second", createPagesOf(' '), createPagesOf('b')),
 | 
			
		||||
                ItemStack(Items.STRING),
 | 
			
		||||
                ItemStack(Items.LEATHER),
 | 
			
		||||
            ),
 | 
			
		||||
            isStack(PrintoutItem.createBookFromTitleAndText("First", createPagesOf(' ', 2), createPagesOf('b', 2))),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun createPagesOf(c: Char, pages: Int = 1): Array<String> {
 | 
			
		||||
        val line = c.toString().repeat(PrintoutItem.LINE_MAX_LENGTH)
 | 
			
		||||
        return Array(PrintoutItem.LINES_PER_PAGE * pages) { line }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user