From 67732ace066ef36f5d5c1c24fca5f93931673b30 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 8 Aug 2026 17:03:53 +0100 Subject: [PATCH 1/5] Sync translations from Crowdin --- .../resources/assets/computercraft/lang/fr_fr.json | 1 + .../resources/assets/computercraft/lang/ru_ru.json | 10 ++++++++++ .../resources/assets/computercraft/lang/zh_cn.json | 8 ++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/projects/common/src/main/resources/assets/computercraft/lang/fr_fr.json b/projects/common/src/main/resources/assets/computercraft/lang/fr_fr.json index e47a8a202..b83c08f8e 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/fr_fr.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/fr_fr.json @@ -205,6 +205,7 @@ "item.computercraft.treasure_disk": "Disquette", "itemGroup.computercraft": "ComputerCraft", "tag.item.computercraft.computer": "Ordinateurs", + "tag.item.computercraft.disks": "Disques", "tag.item.computercraft.monitor": "Moniteurs", "tag.item.computercraft.turtle": "Tortues", "tag.item.computercraft.wired_modem": "Modems câblés", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json b/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json index de8609777..a1be9534b 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json @@ -1,5 +1,8 @@ { "argument.computercraft.argument_expected": "Ожидается аргумент", + "argument.computercraft.computer.distance": "Дистанция до существа", + "argument.computercraft.computer.family": "Группа компьютеров", + "argument.computercraft.computer.id": "ID компьютера", "argument.computercraft.computer.many_matching": "Несколько компьютеров соответствуют с '%s' (экземпляры %s)", "argument.computercraft.computer.no_matching": "Нет соответствующих компьютеров с '%s'", "argument.computercraft.tracking_field.no_field": "Неизвестное поле '%s'", @@ -11,6 +14,7 @@ "block.computercraft.monitor_advanced": "Продвинутый монитор", "block.computercraft.monitor_normal": "Монитор", "block.computercraft.printer": "Принтер", + "block.computercraft.redstone_relay": "Редстоуновый релей", "block.computercraft.speaker": "Колонка", "block.computercraft.turtle_advanced": "Продвинутая черепашка", "block.computercraft.turtle_advanced.upgraded": "Продвинутая черепашка: %s", @@ -104,11 +108,13 @@ "gui.computercraft.config.http.proxy.type.tooltip": "Тип используемого прокси-сервера.", "gui.computercraft.config.http.rules": "Разрешающие/запрещающие правила", "gui.computercraft.config.http.rules.tooltip": "Список правил, которые контролируют поведение «http» API для определенных доменов или\nIP-адресов. Каждое правило представляет собой элемент с «узлом» для сопоставления и набором\nсвойств. Правила оцениваются по порядку, то есть более ранние правила перевешивают\nболее поздние.\nХост может быть доменным именем (\"pastebin.com\"), wildcard-сертификатом (\"*.pastebin.com\") или\nнотацией CIDR (\"127.0.0.0/8\").\nЕсли правил нет, домен блокируется.", + "gui.computercraft.config.http.tooltip": "Контроль HTTP API", "gui.computercraft.config.http.websocket_enabled": "Включить веб-сокеты", "gui.computercraft.config.http.websocket_enabled.tooltip": "Включить использование http веб-сокетов. Для этого необходимо, чтобы параметр «http_enable» был true.", "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.monitor_renderer": "Рендер монитора", "gui.computercraft.config.peripheral": "Периферия", "gui.computercraft.config.term_sizes": "Размер терминала", "gui.computercraft.config.term_sizes.computer": "Компьютер", @@ -129,6 +135,7 @@ "gui.computercraft.config.turtle.normal_fuel_limit": "Лимит топлива Черепашек", "gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "Лимит топлива для Черепашек", "gui.computercraft.config.turtle.tooltip": "Разные настройки, связанные с черепашками.", + "gui.computercraft.config.upload_max_size": "Лимит размера загрузки (в байтах)", "gui.computercraft.pocket_computer_overlay": "Карманный компьютер открыт. Чтобы закрыть, нажми ESC.", "gui.computercraft.terminal": "Компьютерный терминал", "gui.computercraft.tooltip.computer_id": "Идентификатор компьютера: %s", @@ -158,6 +165,9 @@ "item.computercraft.printed_pages": "Напечатанные страницы", "item.computercraft.treasure_disk": "Дискета", "itemGroup.computercraft": "ComputerCraft", + "tag.item.computercraft.computer": "Компьютеры", + "tag.item.computercraft.disks": "Диски", + "tag.item.computercraft.monitor": "Мониторы", "tracking_field.computercraft.avg": "%s (среднее)", "tracking_field.computercraft.computer_tasks.name": "Задачи", "tracking_field.computercraft.count": "%s (количество)", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json b/projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json index 1c2513da6..29417dee6 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json @@ -20,11 +20,11 @@ "block.computercraft.redstone_relay": "红石继电器", "block.computercraft.speaker": "扬声器", "block.computercraft.turtle_advanced": "高级海龟", - "block.computercraft.turtle_advanced.upgraded": "高级%s海龟", - "block.computercraft.turtle_advanced.upgraded_twice": "高级%s%s海龟", + "block.computercraft.turtle_advanced.upgraded": "高级海龟(%s)", + "block.computercraft.turtle_advanced.upgraded_twice": "高级海龟(%s)%s", "block.computercraft.turtle_normal": "海龟", - "block.computercraft.turtle_normal.upgraded": "%s海龟", - "block.computercraft.turtle_normal.upgraded_twice": "%s%s海龟", + "block.computercraft.turtle_normal.upgraded": "海龟(%s)", + "block.computercraft.turtle_normal.upgraded_twice": "海龟(%s)%s", "block.computercraft.wired_modem": "有线调制解调器", "block.computercraft.wired_modem_full": "有线调制解调器", "block.computercraft.wireless_modem_advanced": "末影调制解调器", From 9c1a9a63192e1b6db446c439b2d7f57f159083c3 Mon Sep 17 00:00:00 2001 From: ItsVingtdeux <98675277+ItsNotVingtdeux@users.noreply.github.com> Date: Fri, 14 Aug 2026 01:54:16 -0700 Subject: [PATCH 2/5] Fix random indentation of two lines in bios.lua (#2495) The "type" field definitions for the "edit.autocomplete" and "lua.autocomplete" settings were both randomly indented, compared to the rest of the setting definitions. --- .../core/src/main/resources/data/computercraft/lua/bios.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/core/src/main/resources/data/computercraft/lua/bios.lua b/projects/core/src/main/resources/data/computercraft/lua/bios.lua index 2ba511e82..f9c90d316 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/bios.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/bios.lua @@ -628,12 +628,12 @@ settings.define("shell.autocomplete", { settings.define("edit.autocomplete", { default = true, description = "Autocomplete API and function names in the editor.", - type = "boolean", + type = "boolean", }) settings.define("lua.autocomplete", { default = true, description = "Autocomplete API and function names in the Lua REPL.", - type = "boolean", + type = "boolean", }) settings.define("edit.default_extension", { From 8bdea64474143a081ac8689c225bcc17bd8be213 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 14 Aug 2026 16:41:38 +0100 Subject: [PATCH 3/5] Fix multishell not culling after changing focus When we resume a process, the code looks like: resumeProcess(nCurrentProcess, ...) if cullProcess(nCurrentProcess, ...) then ... end However, if the focused tab changes while resuming (via multishell.setFocus), then we don't cull the correct process! To fix this, we just add a helper function which resumes+culls, meaning we only read the mutable global once. --- projects/common-api/src/overview.html | 1 + .../lua/rom/programs/advanced/multishell.lua | 26 ++++++----- .../programs/advanced/multishell_spec.lua | 44 +++++++++++++++++++ 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/projects/common-api/src/overview.html b/projects/common-api/src/overview.html index f55e97826..64babf771 100644 --- a/projects/common-api/src/overview.html +++ b/projects/common-api/src/overview.html @@ -14,6 +14,7 @@ SPDX-License-Identifier: MPL-2.0

Quick links

diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua index f2cd68b88..56728be43 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/programs/advanced/multishell.lua @@ -127,6 +127,17 @@ local function cullProcess(nProcess) return false end +--[[- Resume and then cull a process. + +This helps avoid the pattern where one calls +`resumeProcess(nCurrentProcess, ...); cullProcess(nCurrentProcess)`, and the +current process changes while the code is running. +]] +local function resumeAndCullProcess(process, ...) + resumeProcess(process, ...) + return cullProcess(process) +end + local function cullProcesses() local culled = false for n = #tProcesses, 1, -1 do @@ -341,8 +352,7 @@ while #tProcesses > 0 do elseif sEvent == "char" or sEvent == "key" or sEvent == "key_up" or sEvent == "paste" or sEvent == "terminate" or sEvent == "file_transfer" then -- Basic input, just passthrough to current process - resumeProcess(nCurrentProcess, table.unpack(tEventData, 1, tEventData.n)) - if cullProcess(nCurrentProcess) then + if resumeAndCullProcess(nCurrentProcess, table.unpack(tEventData, 1, tEventData.n)) then setMenuVisible(#tProcesses >= 2) redrawMenu() end @@ -375,8 +385,7 @@ while #tProcesses > 0 do end else -- Passthrough to current process - resumeProcess(nCurrentProcess, sEvent, button, x, bShowMenu and y - 1 or y) - if cullProcess(nCurrentProcess) then + if resumeAndCullProcess(nCurrentProcess, sEvent, button, x, bShowMenu and y - 1 or y) then setMenuVisible(#tProcesses >= 2) redrawMenu() end @@ -395,8 +404,7 @@ while #tProcesses > 0 do end elseif not (bShowMenu and y == 1) then -- Passthrough to current process - resumeProcess(nCurrentProcess, sEvent, p1, x, bShowMenu and y - 1 or y) - if cullProcess(nCurrentProcess) then + if resumeAndCullProcess(nCurrentProcess, sEvent, p1, x, bShowMenu and y - 1 or y) then setMenuVisible(#tProcesses >= 2) redrawMenu() end @@ -405,8 +413,7 @@ while #tProcesses > 0 do else -- Other event -- Passthrough to all processes - local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event - for n = 1, nLimit do + for n = 1, #tProcesses do resumeProcess(n, table.unpack(tEventData, 1, tEventData.n)) end if cullProcesses() then @@ -417,8 +424,7 @@ while #tProcesses > 0 do if bWindowsResized then -- Pass term_resize to all processes - local nLimit = #tProcesses -- Storing this ensures any new things spawned don't get the event - for n = 1, nLimit do + for n = 1, #tProcesses do resumeProcess(n, "term_resize") end bWindowsResized = false diff --git a/projects/core/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua b/projects/core/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua index f06904fcb..1fcbf6e72 100644 --- a/projects/core/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua +++ b/projects/core/src/test/resources/test-rom/spec/programs/advanced/multishell_spec.lua @@ -31,4 +31,48 @@ describe("The multishell program", function() expect.error(multishell.launch, _ENV, nil):eq("bad argument #2 (string expected, got nil)") end) end) + + describe("the main loop", function() + it("culls a process after exiting", function() + local function find_local(co, find) + for level = 1, 10 do + for var = 1, 255 do + local name, value = debug.getlocal(co, level, var) + if name == nil then break end + if find == name then return value end + end + end + + fail("Cannot find local " .. find) + end + + -- We create a very awkward program here which pulls an event (so we can inspect the intermediate state), + -- then switches to a different tab before exiting, causing nCurrentProcess to change in the multishell + -- loop. + io.open("/test-files/a.lua", "w"):write([[os.pullEvent("mouse_click"); multishell.setFocus(1)]]):close() + + local window = window.create(term.current(), 1, 1, 51, 19, false) + local co = coroutine.create(function() os.run({ shell = shell }, "rom/programs/advanced/multishell.lua") end) + local function resume(...) + local old = term.redirect(window) + local ok, err = coroutine.resume(co, ...) + term.redirect(old) + if not ok then fail("Coroutine failed: " .. err) end + end + + resume() + local multishell = find_local(co, "multishell") + expect(multishell.getFocus()):eq(1) + expect(multishell.getCount()):eq(1) + + resume("paste", "fg /test-files/a.lua") + resume("key", keys.enter, false) + expect(multishell.getFocus()):eq(2) + expect(multishell.getCount()):eq(2) + + resume("mouse_click", 1, 1, 2) + expect(multishell.getFocus()):eq(1) + expect(multishell.getCount()):eq(1) + end) + end) end) From 7b7039c677fb276854c16568bea15efa5cef9f12 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 21 Aug 2026 13:53:02 +0100 Subject: [PATCH 4/5] Fix turtle.place() not skipping ItemStack.useOn --- .../shared/turtle/core/TurtlePlaceCommand.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 2d9822302..7e82228e7 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -213,8 +213,10 @@ public class TurtlePlaceCommand implements TurtleCommand { if (useResult.consumesAction()) return useResult; } - var useOnResult = stack.useOn(new UseOnContext(player, InteractionHand.MAIN_HAND, hit)); - if (useOnResult != InteractionResult.PASS) return useOnResult; + if (canUse.item()) { + var useOnResult = stack.useOn(new UseOnContext(player, InteractionHand.MAIN_HAND, hit)); + if (useOnResult != InteractionResult.PASS) return useOnResult; + } } // We special case some items that we try to place as blocks, such as boats or water buckets. From 7d05fa9ac2c04f6044dcc282610ea74a83e5e946 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 25 Aug 2026 14:56:45 +0100 Subject: [PATCH 5/5] Remove MC version from project name This dates back from when we had multiple MC versions in a single project (see the build-tools branch). We don't do this any more, so no need for it. (More importantly, something has changed in IDEA/Gradle so that the 1.20.1 now is escaped as 1_20_1, which breaks Fabric Loom). --- build.gradle.kts | 3 ++- buildSrc/src/main/kotlin/cc-tweaked.fabric.gradle.kts | 4 +--- buildSrc/src/main/kotlin/cc-tweaked.forge.gradle.kts | 4 +--- .../src/main/kotlin/cc-tweaked.java-convention.gradle.kts | 7 +++---- .../src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts | 3 ++- buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts | 4 +--- gradle.properties | 3 --- gradle/libs.versions.toml | 2 +- projects/common-api/build.gradle.kts | 3 ++- settings.gradle.kts | 3 +-- 10 files changed, 14 insertions(+), 22 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4d5991ea0..296916aea 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,8 @@ plugins { val isUnstable = project.properties["isUnstable"] == "true" val modVersion: String by extra -val mcVersion: String by extra +val mcVersion = project.extensions.getByType().named("libs") + .findVersion("minecraft").get().toString() githubRelease { token(findProperty("githubApiKey") as String? ?: "") diff --git a/buildSrc/src/main/kotlin/cc-tweaked.fabric.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.fabric.gradle.kts index 59da72adc..8d93d904a 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.fabric.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.fabric.gradle.kts @@ -17,8 +17,6 @@ plugins { plugins.apply(CCTweakedPlugin::class.java) -val mcVersion: String by extra - repositories { maven("https://maven.parchmentmc.org/") { name = "Parchment" @@ -42,7 +40,7 @@ extensions.configure(CCTweakedExtension::class.java) { dependencies { val libs = project.extensions.getByType().named("libs") - minecraft("com.mojang:minecraft:$mcVersion") + minecraft("com.mojang:minecraft:${libs.findVersion("minecraft").get()}") mappings( loom.layered { officialMojangMappings() diff --git a/buildSrc/src/main/kotlin/cc-tweaked.forge.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.forge.gradle.kts index e1170bc05..44de854e0 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.forge.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.forge.gradle.kts @@ -15,12 +15,10 @@ plugins { plugins.apply(CCTweakedPlugin::class.java) -val mcVersion: String by extra - legacyForge { val libs = project.extensions.getByType().named("libs") enable { - forgeVersion = "$mcVersion-${libs.findVersion("forge").get()}" + forgeVersion = "${libs.findVersion("minecraft").get()}-${libs.findVersion("forge").get()}" // This causes parameters to not be renamed, which causes issues with ErrorProne. // See https://github.com/google/error-prone/issues/5398. isDisableRecompilation = false diff --git a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts index c29cd29fc..f7eec2495 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts @@ -22,12 +22,12 @@ plugins { } val modVersion: String by extra -val mcVersion: String by extra + +val libs = project.extensions.getByType().named("libs") group = "cc.tweaked" version = modVersion - -base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}") +base.archivesName.set("cc-tweaked-${libs.findVersion("minecraft").get()}-${project.name}") java { toolchain { languageVersion = CCTweakedPlugin.JDK_VERSION } @@ -64,7 +64,6 @@ repositories { } dependencies { - val libs = project.extensions.getByType().named("libs") checkstyle(libs.findLibrary("checkstyle").get()) constraints { diff --git a/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts index ec1254e6f..5f2451d0c 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts @@ -21,7 +21,8 @@ val modPublishing = project.extensions.create("modPublishing", ModPublishingExte val isUnstable = project.properties["isUnstable"] == "true" val modVersion: String by extra -val mcVersion: String by extra +val mcVersion = project.extensions.getByType().named("libs") + .findVersion("minecraft").get().toString() modrinth { token = findProperty("modrinthApiKey") as String? ?: "" diff --git a/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts index efcc7dbf5..785ef5e99 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts @@ -15,12 +15,10 @@ plugins { plugins.apply(CCTweakedPlugin::class.java) -val mcVersion: String by extra - val libs = project.extensions.getByType().named("libs") minecraft { - version(mcVersion) + version(libs.findVersion("minecraft").get().toString()) mappings { parchment(libs.findVersion("parchmentMc").get().toString(), libs.findVersion("parchment").get().toString()) diff --git a/gradle.properties b/gradle.properties index 17df00602..8a492cbf0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,6 +12,3 @@ kotlin.jvm.target.validation.mode=error modVersion=1.120.2 isUnstable=false - -# Minecraft properties: We want to configure this here so we can read it in settings.gradle -mcVersion=1.20.1 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a32a9c022..fb74a23ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,8 +5,8 @@ [versions] # Minecraft -# MC version is specified in gradle.properties, as we need that in settings.gradle. # Remember to update corresponding versions in fabric.mod.json/mods.toml +minecraft = "1.20.1" fabric-api = "0.86.1+1.20.1" fabric-loader = "0.18.4" forge = "47.1.0" diff --git a/projects/common-api/build.gradle.kts b/projects/common-api/build.gradle.kts index b5649f8c1..961974e61 100644 --- a/projects/common-api/build.gradle.kts +++ b/projects/common-api/build.gradle.kts @@ -8,7 +8,8 @@ plugins { id("cc-tweaked.vanilla") } -val mcVersion: String by extra +val mcVersion = project.extensions.getByType().named("libs") + .findVersion("minecraft").get().toString() java { withJavadocJar() diff --git a/settings.gradle.kts b/settings.gradle.kts index 38302d6b1..1c9fb6ba6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -30,8 +30,7 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version("1.0.0") } -val mcVersion: String by settings -rootProject.name = "cc-tweaked-$mcVersion" +rootProject.name = "cc-tweaked" include(":core-api") include(":core")