From 8711512769943ea74ea5867ab75c1c51d375db88 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 21 Apr 2025 08:32:03 +0100 Subject: [PATCH 1/4] Remove allocation tracking for computers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts 76968f2f28435ddd8cf1efe5dc7330410e87cc09. We'd originally added this to gather some numbers for #1580, with the hope that it would also be useful for server admins. Sadly, it's not as accurate as I originally hoped — the number sometimes goes down for unclear reasons (something to do with the TLAB maybe??). Closes #1739. --- .../computercraft/data/LanguageProvider.java | 1 - .../assets/computercraft/lang/en_us.json | 1 - .../shared/util/TickScheduler.java | 2 +- .../assets/computercraft/lang/cs_cz.json | 1 - .../assets/computercraft/lang/es_es.json | 1 - .../assets/computercraft/lang/fr_fr.json | 1 - .../assets/computercraft/lang/it_it.json | 19 ++- .../assets/computercraft/lang/ja_jp.json | 1 - .../assets/computercraft/lang/pt_br.json | 1 - .../assets/computercraft/lang/ru_ru.json | 1 + .../assets/computercraft/lang/sv_se.json | 9 ++ .../assets/computercraft/lang/tr_tr.json | 1 - .../assets/computercraft/lang/uk_ua.json | 1 - .../assets/computercraft/lang/zh_cn.json | 1 - .../computerthread/ComputerThread.java | 111 +---------------- .../computercraft/core/metrics/Metrics.java | 2 - .../core/metrics/ThreadAllocations.java | 114 ------------------ .../computerthread/ComputerThreadTest.java | 28 +---- 18 files changed, 38 insertions(+), 258 deletions(-) delete mode 100644 projects/core/src/main/java/dan200/computercraft/core/metrics/ThreadAllocations.java diff --git a/projects/common/src/datagen/java/dan200/computercraft/data/LanguageProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/LanguageProvider.java index 920f87870..224173428 100644 --- a/projects/common/src/datagen/java/dan200/computercraft/data/LanguageProvider.java +++ b/projects/common/src/datagen/java/dan200/computercraft/data/LanguageProvider.java @@ -185,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"); diff --git a/projects/common/src/generated/resources/assets/computercraft/lang/en_us.json b/projects/common/src/generated/resources/assets/computercraft/lang/en_us.json index ae3198632..cf9137d0d 100644 --- a/projects/common/src/generated/resources/assets/computercraft/lang/en_us.json +++ b/projects/common/src/generated/resources/assets/computercraft/lang/en_us.json @@ -217,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", diff --git a/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java b/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java index 1ae910185..8ddaa1fcf 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/util/TickScheduler.java @@ -165,7 +165,7 @@ public final class TickScheduler { UNLOADED, } - private record ChunkReference(ResourceKey level, Long position) { + private record ChunkReference(ResourceKey level, long position) { @Override public String toString() { return "ChunkReference(" + level + " at " + new ChunkPos(position) + ")"; diff --git a/projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json b/projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json index 582892135..acd444f34 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json @@ -215,7 +215,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", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/es_es.json b/projects/common/src/main/resources/assets/computercraft/lang/es_es.json index 7cc2f9220..1d7dc4db5 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/es_es.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/es_es.json @@ -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", 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 414d410ee..e47a8a202 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 @@ -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", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/it_it.json b/projects/common/src/main/resources/assets/computercraft/lang/it_it.json index 5860e8329..97fc805e3 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/it_it.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/it_it.json @@ -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", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/ja_jp.json b/projects/common/src/main/resources/assets/computercraft/lang/ja_jp.json index 83230c752..4e1c7e8f4 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/ja_jp.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/ja_jp.json @@ -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": "サーバータスク", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/pt_br.json b/projects/common/src/main/resources/assets/computercraft/lang/pt_br.json index 25df945d2..1cee680d3 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/pt_br.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/pt_br.json @@ -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", 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 c1491e199..de8609777 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 @@ -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": "Высота терминала", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/sv_se.json b/projects/common/src/main/resources/assets/computercraft/lang/sv_se.json index 04fd86b5b..a1aa606e7 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/sv_se.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/sv_se.json @@ -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)", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/tr_tr.json b/projects/common/src/main/resources/assets/computercraft/lang/tr_tr.json index 25edd3c4b..0b5d4b1af 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/tr_tr.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/tr_tr.json @@ -215,7 +215,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", diff --git a/projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json b/projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json index 4246a2d9b..902af22b6 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json @@ -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": "Серверних задач", 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 2047644d3..ffff6fc65 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 @@ -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": "服务器任务", diff --git a/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java b/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java index 67672bc54..cf8410731 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java +++ b/projects/core/src/main/java/dan200/computercraft/core/computer/computerthread/ComputerThread.java @@ -12,13 +12,11 @@ import dan200.computercraft.core.Logging; import dan200.computercraft.core.computer.TimeoutState; import dan200.computercraft.core.metrics.Metrics; import dan200.computercraft.core.metrics.MetricsObserver; -import dan200.computercraft.core.metrics.ThreadAllocations; import dan200.computercraft.core.util.ThreadUtils; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Arrays; import java.util.Objects; import java.util.TreeSet; import java.util.concurrent.ThreadFactory; @@ -489,9 +487,6 @@ public final class ComputerThread implements ComputerScheduler { } private void runImpl() { - var workerThreadIds = new long[workersReadOnly().length]; - Arrays.fill(workerThreadIds, Thread.currentThread().getId()); - while (state.get() < CLOSED) { computerLock.lock(); try { @@ -506,33 +501,12 @@ public final class ComputerThread implements ComputerScheduler { computerLock.unlock(); } - checkRunners(workerThreadIds); + checkRunners(); } } - private void checkRunners(long[] workerThreadIds) { - var workers = workersReadOnly(); - - long[] allocations; - if (ThreadAllocations.isSupported()) { - // If allocation tracking is supported, update the current thread IDs and then fetch the total allocated - // memory. When dealing with multiple workers, it's more efficient to getAllocatedBytes in bulk rather - // than, hence doing it within the worker loop. - // However, this does mean we need to maintain an array of worker thread IDs. We could have a shared - // array and update it within .addWorker(_), but that's got all sorts of thread-safety issues. It ends - // up being easier (and not too inefficient) to just recompute the array each time. - for (var i = 0; i < workers.length; i++) { - var runner = workers[i]; - if (runner != null) workerThreadIds[i] = runner.owner.getId(); - } - allocations = ThreadAllocations.getAllocatedBytes(workerThreadIds); - } else { - allocations = null; - } - var allocationTime = System.nanoTime(); - - for (var i = 0; i < workers.length; i++) { - var runner = workers[i]; + private void checkRunners() { + for (var runner : workersReadOnly()) { if (runner == null) continue; // If the worker has no work, skip @@ -542,11 +516,6 @@ public final class ComputerThread implements ComputerScheduler { // Refresh the timeout state. Will set the pause/soft timeout flags as appropriate. executor.timeout.refresh(); - // And track the allocated memory. - if (allocations != null) { - executor.updateAllocations(new ThreadAllocation(workerThreadIds[i], allocations[i], allocationTime)); - } - // If we're still within normal execution times (TIMEOUT) or soft abort (ABORT_TIMEOUT), // then we can let the Lua machine do its work. var remainingTime = executor.timeout.getRemainingTime(); @@ -774,9 +743,6 @@ public final class ComputerThread implements ComputerScheduler { public static final AtomicReferenceFieldUpdater STATE = AtomicReferenceFieldUpdater.newUpdater( ExecutorImpl.class, ExecutorState.class, "$state" ); - public static final AtomicReferenceFieldUpdater THREAD_ALLOCATION = AtomicReferenceFieldUpdater.newUpdater( - ExecutorImpl.class, ThreadAllocation.class, "$threadAllocation" - ); final Worker worker; private final MetricsObserver metrics; @@ -788,17 +754,6 @@ public final class ComputerThread implements ComputerScheduler { @Keep private volatile ExecutorState $state = ExecutorState.IDLE; - /** - * Information about allocations on the currently executing thread. - *

- * {@linkplain #beforeWork() Before starting any work}, we set this to the current thread and the current - * {@linkplain ThreadAllocations#getAllocatedBytes(long) amount of allocated memory}. When the computer - * {@linkplain #afterWork()} finishes executing, we set this back to null and compute the difference between the - * two, updating the {@link Metrics#JAVA_ALLOCATION} metric. - */ - @Keep - private volatile @Nullable ThreadAllocation $threadAllocation = null; - /** * The amount of time this computer has used on a theoretical machine which shares work evenly amongst computers. * @@ -825,11 +780,6 @@ public final class ComputerThread implements ComputerScheduler { void beforeWork() { vRuntimeStart = System.nanoTime(); timeout.startTimer(scaledPeriod()); - - if (ThreadAllocations.isSupported()) { - var current = Thread.currentThread().getId(); - THREAD_ALLOCATION.set(this, new ThreadAllocation(current, ThreadAllocations.getAllocatedBytes(current), System.nanoTime())); - } } /** @@ -841,55 +791,10 @@ public final class ComputerThread implements ComputerScheduler { timeout.reset(); metrics.observe(Metrics.COMPUTER_TASKS, timeout.getExecutionTime()); - if (ThreadAllocations.isSupported()) { - var current = Thread.currentThread().getId(); - var info = THREAD_ALLOCATION.getAndSet(this, null); - assert info.threadId() == current; - - var allocatedTotal = ThreadAllocations.getAllocatedBytes(current); - var allocated = allocatedTotal - info.allocatedBytes(); - if (allocated > 0) { - metrics.observe(Metrics.JAVA_ALLOCATION, allocated); - } else if (allocated < 0) { - LOG.warn( - """ - Allocated a negative number of bytes ({})! - Previous measurement at t={} on Thread #{} = {} - Current measurement at t={} on Thread #{} = {}""", - allocated, - info.time(), info.threadId(), info.allocatedBytes(), - System.nanoTime(), current, allocatedTotal - ); - } - } - var state = STATE.getAndUpdate(this, ExecutorState::requeue); return state == ExecutorState.REPEAT; } - /** - * Update the per-thread allocation information. - * - * @param allocation The latest allocation information. - */ - void updateAllocations(ThreadAllocation allocation) { - ThreadAllocation current; - long allocated; - do { - // Probe the current information - if it's null or the thread has changed, then the worker has already - // finished and this information is out-of-date, so just abort. - current = THREAD_ALLOCATION.get(this); - if (current == null || current.threadId() != allocation.threadId()) return; - - // Then compute the difference since the previous measurement. If the new value is less than the current - // one, then it must be out-of-date. Again, just abort. - allocated = allocation.allocatedBytes() - current.allocatedBytes(); - if (allocated <= 0) return; - } while (!THREAD_ALLOCATION.compareAndSet(this, current, allocation)); - - metrics.observe(Metrics.JAVA_ALLOCATION, allocated); - } - @Override public void submit() { var state = STATE.getAndUpdate(this, ExecutorState::enqueue); @@ -918,14 +823,4 @@ public final class ComputerThread implements ComputerScheduler { return hasPendingWork(); } } - - /** - * Allocation information about a specific thread. - * - * @param threadId The ID of this thread. - * @param allocatedBytes The amount of memory this thread has allocated. - * @param time The time (in nanoseconds) when this time was computed. - */ - private record ThreadAllocation(long threadId, long allocatedBytes, long time) { - } } diff --git a/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java b/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java index 088c98b8d..903967026 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java +++ b/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java @@ -14,8 +14,6 @@ public final class Metrics { public static final Metric.Event COMPUTER_TASKS = new Metric.Event("computer_tasks", "ns", Metric::formatTime); public static final Metric.Event SERVER_TASKS = new Metric.Event("server_tasks", "ns", Metric::formatTime); - public static final Metric.Event JAVA_ALLOCATION = new Metric.Event("java_allocation", "bytes", Metric::formatBytes); - public static final Metric.Event PERIPHERAL_OPS = new Metric.Event("peripheral", "ns", Metric::formatTime); public static final Metric.Event FS_OPS = new Metric.Event("fs", "ns", Metric::formatTime); diff --git a/projects/core/src/main/java/dan200/computercraft/core/metrics/ThreadAllocations.java b/projects/core/src/main/java/dan200/computercraft/core/metrics/ThreadAllocations.java deleted file mode 100644 index 953a832db..000000000 --- a/projects/core/src/main/java/dan200/computercraft/core/metrics/ThreadAllocations.java +++ /dev/null @@ -1,114 +0,0 @@ -// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers -// -// SPDX-License-Identifier: MPL-2.0 - -package dan200.computercraft.core.metrics; - -import org.jspecify.annotations.Nullable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.management.ManagementFactory; -import java.lang.management.ThreadMXBean; - -/** - * Provides a way to get the memory allocated by a specific thread. - *

- * This uses Hotspot-specific functionality, so may not be available on all JVMs. Consumers should call - * {@link #isSupported()} before calling more specific methods. - * - * @see com.sun.management.ThreadMXBean - */ -public final class ThreadAllocations { - private static final Logger LOG = LoggerFactory.getLogger(ThreadAllocations.class); - - private static final @Nullable MethodHandle threadAllocatedBytes; - private static final @Nullable MethodHandle threadsAllocatedBytes; - - static { - MethodHandle threadAllocatedBytesHandle, threadsAllocatedBytesHandle; - try { - var threadMxBean = Class.forName("com.sun.management.ThreadMXBean").asSubclass(ThreadMXBean.class); - var bean = ManagementFactory.getPlatformMXBean(threadMxBean); - - // Enable allocation tracking. - threadMxBean.getMethod("setThreadAllocatedMemoryEnabled", boolean.class).invoke(bean, true); - - // Just probe this method once to check it doesn't error. - threadMxBean.getMethod("getCurrentThreadAllocatedBytes").invoke(bean); - - threadAllocatedBytesHandle = MethodHandles.publicLookup() - .findVirtual(threadMxBean, "getThreadAllocatedBytes", MethodType.methodType(long.class, long.class)) - .bindTo(bean); - threadsAllocatedBytesHandle = MethodHandles.publicLookup() - .findVirtual(threadMxBean, "getThreadAllocatedBytes", MethodType.methodType(long[].class, long[].class)) - .bindTo(bean); - } catch (LinkageError | ReflectiveOperationException | RuntimeException e) { - LOG.warn("Cannot track allocated memory of computer threads", e); - threadAllocatedBytesHandle = threadsAllocatedBytesHandle = null; - } - - threadAllocatedBytes = threadAllocatedBytesHandle; - threadsAllocatedBytes = threadsAllocatedBytesHandle; - } - - private ThreadAllocations() { - } - - /** - * Check whether the current JVM provides information about per-thread allocations. - * - * @return Whether per-thread allocation information is available. - */ - public static boolean isSupported() { - return threadAllocatedBytes != null; - } - - /** - * Get an approximation the amount of memory a thread has allocated over its lifetime. - * - * @param threadId The ID of the thread. - * @return The allocated memory, in bytes. - * @see com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long) - */ - public static long getAllocatedBytes(long threadId) { - if (threadAllocatedBytes == null) { - throw new UnsupportedOperationException("Allocated bytes are not supported"); - } - - try { - return (long) threadAllocatedBytes.invokeExact(threadId); - } catch (Throwable t) { - throw throwUnchecked0(t); // Should never occur, but if it does it's guaranteed to be a runtime exception. - } - } - - /** - * Get an approximation the amount of memory a thread has allocated over its lifetime. - *

- * This is equivalent to calling {@link #getAllocatedBytes(long)} for each thread in {@code threadIds}. - * - * @param threadIds An array of thread IDs. - * @return An array with the same length as {@code threadIds}, containing the allocated memory for each thread. - * @see com.sun.management.ThreadMXBean#getThreadAllocatedBytes(long[]) - */ - public static long[] getAllocatedBytes(long[] threadIds) { - if (threadsAllocatedBytes == null) { - throw new UnsupportedOperationException("Allocated bytes are not supported"); - } - - try { - return (long[]) threadsAllocatedBytes.invokeExact(threadIds); - } catch (Throwable t) { - throw throwUnchecked0(t); // Should never occur, but if it does it's guaranteed to be a runtime exception. - } - } - - @SuppressWarnings({ "unchecked", "TypeParameterUnusedInFormals" }) - private static T throwUnchecked0(Throwable t) throws T { - throw (T) t; - } -} diff --git a/projects/core/src/test/java/dan200/computercraft/core/computer/computerthread/ComputerThreadTest.java b/projects/core/src/test/java/dan200/computercraft/core/computer/computerthread/ComputerThreadTest.java index e954d8643..08b3933d4 100644 --- a/projects/core/src/test/java/dan200/computercraft/core/computer/computerthread/ComputerThreadTest.java +++ b/projects/core/src/test/java/dan200/computercraft/core/computer/computerthread/ComputerThreadTest.java @@ -5,21 +5,22 @@ package dan200.computercraft.core.computer.computerthread; import dan200.computercraft.core.computer.TimeoutState; -import dan200.computercraft.core.metrics.Metrics; -import dan200.computercraft.core.metrics.ThreadAllocations; import dan200.computercraft.test.core.ConcurrentHelpers; -import org.junit.jupiter.api.*; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.ExecutionMode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Locale; -import java.util.Objects; import java.util.concurrent.TimeUnit; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.junit.jupiter.api.Assertions.*; @Timeout(value = 15) @@ -91,21 +92,4 @@ public class ComputerThreadTest { manager.startAndWait(computer); } - - @Test - public void testAllocationTracking() throws Exception { - Assumptions.assumeTrue(ThreadAllocations.isSupported(), "Allocation tracking is supported"); - - var size = 1024 * 1024 * 64; - var computer = manager.createWorker((executor, timeout) -> { - // Allocate some slab of memory. We try to blackhole the allocated object, but it's pretty naive - // so who knows how useful it'll be. - assertNotEquals(0, Objects.toString(new byte[size]).length()); - }); - manager.startAndWait(computer); - - assertThat(computer.getMetric(Metrics.JAVA_ALLOCATION), allOf( - greaterThan((long) size), lessThan((long) (size + (size >> 2))) - )); - } } From 947001104d8cd7a487f54ff5c7ae057f186d4c61 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 21 Apr 2025 14:36:44 +0100 Subject: [PATCH 2/4] Update Cobalt to 0.9.6 - Allow heterogenous __lt/__le. --- gradle/libs.versions.toml | 2 +- .../java/dan200/computercraft/core/lua/CobaltLuaMachine.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c174d1e16..948f8a959 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,7 @@ slf4j = "2.0.1" asm = "9.6" autoService = "1.1.1" checkerFramework = "3.42.0" -cobalt = { strictly = "0.9.5" } +cobalt = { strictly = "0.9.6" } commonsCli = "1.6.0" jetbrainsAnnotations = "24.1.0" jspecify = "1.0.0" diff --git a/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 527bf03bc..e937039e6 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -77,7 +77,7 @@ public class CobaltLuaMachine implements ILuaMachine { try { var globals = state.globals(); CoreLibraries.debugGlobals(state); - Bit32Lib.add(state, globals); + Bit32Lib.add(state); ErrorInfoLib.add(state); globals.rawset("_HOST", ValueFactory.valueOf(environment.hostString())); globals.rawset("_CC_DEFAULT_SETTINGS", ValueFactory.valueOf(CoreConfig.defaultComputerSettings)); From 4344c3072f8eb1becf193aca84b975c073c169c3 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 10 May 2025 14:35:26 +0100 Subject: [PATCH 3/4] Add a test for turtle upgrade crafting Every few years I get confused about which side turtle upgrades go on when crafting. The fact that it's flipped always throws me! Let's add a comment to the recipe, and add some tests to reassure myself. --- .../turtle/recipes/TurtleUpgradeRecipe.java | 4 +- .../test/shared/ItemStackMatcher.java | 2 +- .../computercraft/gametest/Turtle_Test.kt | 78 +++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java index 3ad657e47..8fc59ea06 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/recipes/TurtleUpgradeRecipe.java @@ -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()) { diff --git a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java index dc6b50285..ace7d0cee 100644 --- a/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java +++ b/projects/common/src/testFixtures/java/dan200/computercraft/test/shared/ItemStackMatcher.java @@ -29,7 +29,7 @@ public class ItemStackMatcher extends TypeSafeMatcher { @Override protected void describeMismatchSafely(ItemStack item, Description description) { - description.appendText("was ").appendValue(stack).appendValue(stack.getTag()); + description.appendText("was ").appendValue(item).appendValue(item.getTag()); } public static Matcher isStack(ItemStack stack) { diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt index 44a1a1755..c24126db2 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/Turtle_Test.kt @@ -29,6 +29,7 @@ import dan200.computercraft.shared.util.WaterloggableHelpers import dan200.computercraft.test.core.assertArrayEquals import dan200.computercraft.test.core.computer.LuaTaskContext import dan200.computercraft.test.core.computer.getApi +import dan200.computercraft.test.shared.ItemStackMatcher.isStack import net.minecraft.core.BlockPos import net.minecraft.gametest.framework.GameTest import net.minecraft.gametest.framework.GameTestHelper @@ -908,6 +909,83 @@ class Turtle_Test { thenWaitUntil { helper.assertContainerEmpty(BlockPos(2, 3, 2)) } } + /** + * Test that turtles can be crafted with upgrades. + */ + @GameTest(template = Structures.DEFAULT) + fun Can_upgrades_be_crafted(helper: GameTestHelper) = helper.immediate { + fun turtle(left: UpgradeData? = null, right: UpgradeData? = null): ItemStack = + ModRegistry.Items.TURTLE_NORMAL.get() + .create(-1, null, -1, left, right, 0, null) + + val pick = TurtleUpgrades.instance().get(ItemStack(Items.DIAMOND_PICKAXE))!! + val sword = TurtleUpgrades.instance().get(ItemStack(Items.DIAMOND_SWORD))!! + + // Check we can craft with upgrades + assertThat( + "Craft with item on left equips on right", + helper.craftItem( + ItemStack(Items.DIAMOND_PICKAXE), turtle(), ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ), + isStack(turtle(right = pick)), + ) + assertThat( + "Craft with item on right equips on left", + helper.craftItem( + ItemStack.EMPTY, turtle(), ItemStack(Items.DIAMOND_PICKAXE), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ), + isStack(turtle(left = pick)), + ) + assertThat( + "Craft with two items", + helper.craftItem( + ItemStack(Items.DIAMOND_SWORD), turtle(), ItemStack(Items.DIAMOND_PICKAXE), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ), + isStack(turtle(left = pick, right = sword)), + ) + assertThat( + "Maintains upgrades", + helper.craftItem( + ItemStack(Items.DIAMOND_SWORD), turtle(left = pick), ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ), + isStack(turtle(left = pick, right = sword)), + ) + + // Cannot craft when already have item + helper.assertNotCraftable( + ItemStack.EMPTY, turtle(left = sword), ItemStack(Items.DIAMOND_PICKAXE), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ) + + // Cannot craft with an invalid upgrade + helper.assertNotCraftable( + ItemStack.EMPTY, turtle(), ItemStack(Items.DIRT), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ) + + // Cannot craft with extra items in the inventory + helper.assertNotCraftable( + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack(Items.DIRT), + ItemStack.EMPTY, turtle(), ItemStack(Items.DIAMOND_PICKAXE), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ) + helper.assertNotCraftable( + ItemStack.EMPTY, turtle(), ItemStack(Items.DIAMOND_PICKAXE), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack(Items.DIRT), + ItemStack.EMPTY, ItemStack.EMPTY, ItemStack.EMPTY, + ) + } + /** * Render turtles as an item. */ From 418c9be7ac0f166953fb2b6b3e6e1b5404a2b8ab Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 16 May 2025 18:22:20 +0100 Subject: [PATCH 4/4] Allow changing terminal size with components We add a new computercraft:term_size component that allows changing the terminal size of computers and pocket computers. --- .../computercraft/shared/ModRegistry.java | 8 +++ .../computer/blocks/ComputerBlockEntity.java | 56 ++++++++++++++++++- .../shared/computer/core/ServerComputer.java | 7 +-- .../shared/computer/core/TerminalSize.java | 43 ++++++++++++++ .../shared/config/ConfigSpec.java | 9 +-- .../pocket/core/PocketServerComputer.java | 6 +- .../pocket/items/PocketComputerItem.java | 10 ++-- .../turtle/blocks/TurtleBlockEntity.java | 3 +- 8 files changed, 123 insertions(+), 19 deletions(-) create mode 100644 projects/common/src/main/java/dan200/computercraft/shared/computer/core/TerminalSize.java diff --git a/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java b/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java index e941e8a37..dd8f43761 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java @@ -34,6 +34,7 @@ import dan200.computercraft.shared.computer.blocks.ComputerBlock; import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.TerminalSize; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.computer.items.ServerComputerReference; import dan200.computercraft.shared.config.Config; @@ -322,6 +323,13 @@ public final class ModRegistry { .persistent(StorageCapacity.CODEC).networkSynchronized(StorageCapacity.STREAM_CODEC) ); + /** + * The terminal size of a computer. + */ + public static final RegistryEntry> TERMINAL_SIZE = register("terminal_size", b -> b + .persistent(TerminalSize.CODEC).networkSynchronized(TerminalSize.STREAM_CODEC) + ); + /** * The left upgrade of a turtle. * diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java index 1cd56979b..4e7585ef0 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java @@ -10,10 +10,15 @@ import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.TerminalSize; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.config.ConfigSpec; +import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; @@ -23,17 +28,66 @@ import net.minecraft.world.level.block.state.BlockState; import org.jspecify.annotations.Nullable; public class ComputerBlockEntity extends AbstractComputerBlockEntity { + private static final String NBT_TERMINAL_SIZE = "TerminalSize"; + + private @Nullable TerminalSize terminalSize; + private @Nullable IPeripheral peripheral; public ComputerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state, ComputerFamily family) { super(type, pos, state, family); } + @Override + protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadServer(nbt, registries); + terminalSize = NBTUtil.decodeFrom(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE); + } + + @Override + public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.saveAdditional(nbt, registries); + NBTUtil.encodeTo(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE, terminalSize); + } + + @Override + protected void loadClient(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadClient(nbt, registries); + terminalSize = NBTUtil.decodeFrom(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE); + } + + @Override + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + var tag = super.getUpdateTag(registries); + NBTUtil.encodeTo(TerminalSize.CODEC, registries, tag, NBT_TERMINAL_SIZE, terminalSize); + return tag; + } + + @Override + protected void applyImplicitComponents(DataComponentInput component) { + super.applyImplicitComponents(component); + terminalSize = component.get(ModRegistry.DataComponents.TERMINAL_SIZE.get()); + } + + + @Override + protected void collectSafeComponents(DataComponentMap.Builder builder) { + super.collectSafeComponents(builder); + builder.set(ModRegistry.DataComponents.TERMINAL_SIZE.get(), terminalSize); + } + + @Override + @Deprecated + public void removeComponentsFromTag(CompoundTag tag) { + super.removeComponentsFromTag(tag); + tag.remove(NBT_TERMINAL_SIZE); + } + @Override protected ServerComputer createComputer(int id) { return new ServerComputer((ServerLevel) getLevel(), getBlockPos(), ServerComputer.properties(id, getFamily()) .label(getLabel()) - .terminalSize(ConfigSpec.computerTermWidth.get(), ConfigSpec.computerTermHeight.get()) + .terminalSize(terminalSize != null ? terminalSize : new TerminalSize(ConfigSpec.computerTermWidth.get(), ConfigSpec.computerTermHeight.get())) .storageCapacity(storageCapacity) ); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 54fea5803..b61d44180 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -295,10 +295,9 @@ public class ServerComputer implements ComputerEnvironment, ComputerEvents.Recei return this; } - public Properties terminalSize(int width, int height) { - if (width <= 0 || height <= 0) throw new IllegalArgumentException("Terminal size must be positive"); - this.terminalWidth = width; - this.terminalHeight = height; + public Properties terminalSize(TerminalSize size) { + this.terminalWidth = size.width(); + this.terminalHeight = size.height(); return this; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/TerminalSize.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/TerminalSize.java new file mode 100644 index 000000000..81fd90bf9 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/TerminalSize.java @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.computer.core; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.util.ExtraCodecs; + +/** + * The size of a computer terminal. + * + * @param width The terminal's width. + * @param height The terminal's height. + */ +public record TerminalSize(int width, int height) { + public static final int MAX_SIZE = 255; + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + ExtraCodecs.intRange(1, MAX_SIZE).fieldOf("width").forGetter(TerminalSize::width), + ExtraCodecs.intRange(1, MAX_SIZE).fieldOf("height").forGetter(TerminalSize::height) + ).apply(instance, TerminalSize::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, TerminalSize::width, + ByteBufCodecs.VAR_INT, TerminalSize::height, + TerminalSize::new + ); + + public TerminalSize { + checkBounds("width", width); + checkBounds("height", height); + } + + private static void checkBounds(String name, int value) { + if (value < 1 || value > MAX_SIZE) { + throw new IllegalArgumentException(name + " must be between 1 and " + MAX_SIZE); + } + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java b/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java index 47e30bce2..3d45dac83 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java @@ -11,6 +11,7 @@ import dan200.computercraft.core.Logging; import dan200.computercraft.core.apis.http.NetworkUtils; import dan200.computercraft.core.apis.http.options.ProxyType; import dan200.computercraft.core.computer.mainthread.MainThreadConfig; +import dan200.computercraft.shared.computer.core.TerminalSize; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.platform.PlatformHelper; import org.apache.logging.log4j.LogManager; @@ -344,13 +345,13 @@ public final class ConfigSpec { .push("term_sizes"); builder.comment("Terminal size of computers.").push("computer"); - computerTermWidth = builder.comment("Width of computer terminal").defineInRange("width", Config.DEFAULT_COMPUTER_TERM_WIDTH, 1, 255); - computerTermHeight = builder.comment("Height of computer terminal").defineInRange("height", Config.DEFAULT_COMPUTER_TERM_HEIGHT, 1, 255); + computerTermWidth = builder.comment("Width of computer terminal").defineInRange("width", Config.DEFAULT_COMPUTER_TERM_WIDTH, 1, TerminalSize.MAX_SIZE); + computerTermHeight = builder.comment("Height of computer terminal").defineInRange("height", Config.DEFAULT_COMPUTER_TERM_HEIGHT, 1, TerminalSize.MAX_SIZE); builder.pop(); builder.comment("Terminal size of pocket computers.").push("pocket_computer"); - pocketTermWidth = builder.comment("Width of pocket computer terminal").defineInRange("width", Config.DEFAULT_POCKET_TERM_WIDTH, 1, 255); - pocketTermHeight = builder.comment("Height of pocket computer terminal").defineInRange("height", Config.DEFAULT_POCKET_TERM_HEIGHT, 1, 255); + pocketTermWidth = builder.comment("Width of pocket computer terminal").defineInRange("width", Config.DEFAULT_POCKET_TERM_WIDTH, 1, TerminalSize.MAX_SIZE); + pocketTermHeight = builder.comment("Height of pocket computer terminal").defineInRange("height", Config.DEFAULT_POCKET_TERM_HEIGHT, 1, TerminalSize.MAX_SIZE); builder.pop(); builder.comment("Maximum size of monitors (in blocks).").push("monitor"); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index efa4a5c24..3e7a52378 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.pocket.core; import dan200.computercraft.api.component.ComputerComponents; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.network.client.PocketComputerDataMessage; import dan200.computercraft.shared.network.client.PocketComputerDeletedClientMessage; import dan200.computercraft.shared.network.server.ServerNetworking; @@ -40,10 +39,7 @@ public final class PocketServerComputer extends ServerComputer { private Set tracking = Set.of(); PocketServerComputer(PocketBrain brain, PocketHolder holder, ServerComputer.Properties properties) { - super(holder.level(), holder.blockPos(), properties - .terminalSize(ConfigSpec.pocketTermWidth.get(), ConfigSpec.pocketTermHeight.get()) - .addComponent(ComputerComponents.POCKET, brain) - ); + super(holder.level(), holder.blockPos(), properties.addComponent(ComputerComponents.POCKET, brain)); this.brain = brain; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java index b9c6ef3aa..de1dc1169 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java @@ -11,12 +11,10 @@ import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.impl.PocketUpgrades; import dan200.computercraft.shared.ModRegistry; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.computer.core.ServerComputerRegistry; -import dan200.computercraft.shared.computer.core.ServerContext; +import dan200.computercraft.shared.computer.core.*; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.computer.items.ServerComputerReference; +import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.pocket.core.PocketBrain; @@ -207,6 +205,10 @@ public class PocketComputerItem extends Item { ServerComputer.properties(computerID, getFamily()) .label(getLabel(stack)) .storageCapacity(StorageCapacity.getOrDefault(stack.get(ModRegistry.DataComponents.STORAGE_CAPACITY.get()), -1)) + .terminalSize(stack.getOrDefault( + ModRegistry.DataComponents.TERMINAL_SIZE.get(), + new TerminalSize(ConfigSpec.pocketTermWidth.get(), ConfigSpec.pocketTermHeight.get()) + )) ); var computer = brain.computer(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java index 2f3e3df44..8a5f189d8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java @@ -18,6 +18,7 @@ import dan200.computercraft.shared.computer.blocks.ComputerPeripheral; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.TerminalSize; import dan200.computercraft.shared.config.Config; import dan200.computercraft.shared.container.BasicContainer; import dan200.computercraft.shared.platform.PlatformHelper; @@ -81,7 +82,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba protected ServerComputer createComputer(int id) { var computer = new ServerComputer((ServerLevel) getLevel(), getBlockPos(), ServerComputer.properties(id, getFamily()) .label(getLabel()) - .terminalSize(Config.TURTLE_TERM_WIDTH, Config.TURTLE_TERM_HEIGHT) + .terminalSize(new TerminalSize(Config.TURTLE_TERM_WIDTH, Config.TURTLE_TERM_HEIGHT)) .storageCapacity(storageCapacity) .addComponent(ComputerComponents.TURTLE, brain) );