diff --git a/.github/workflows/main-ci.yml b/.github/workflows/main-ci.yml
index 497a3556a..8a10d43ea 100644
--- a/.github/workflows/main-ci.yml
+++ b/.github/workflows/main-ci.yml
@@ -30,6 +30,18 @@ jobs:
- name: ⚒️ Build
run: ./gradlew assemble || ./gradlew assemble
+ - name: 📦 Prepare Jars
+ run: |
+ # Find the main jar and append the git hash onto it.
+ mkdir -p jars
+ find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
+
+ - name: 📤 Upload Jar
+ uses: actions/upload-artifact@v4
+ with:
+ name: CC-Tweaked
+ path: ./jars
+
- name: Cache pre-commit
uses: actions/cache@v4
with:
@@ -54,18 +66,6 @@ jobs:
run: ./tools/parse-reports.py
if: ${{ failure() }}
- - name: 📦 Prepare Jars
- run: |
- # Find the main jar and append the git hash onto it.
- mkdir -p jars
- find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
-
- - name: 📤 Upload Jar
- uses: actions/upload-artifact@v4
- with:
- name: CC-Tweaked
- path: ./jars
-
build-core:
strategy:
fail-fast: false
diff --git a/REUSE.toml b/REUSE.toml
index 82da03ae1..273ab494d 100644
--- a/REUSE.toml
+++ b/REUSE.toml
@@ -40,8 +40,8 @@ path = [
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/.ignoreme",
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/turtle/.ignoreme",
"projects/core/src/main/resources/data/computercraft/lua/rom/motd.txt",
- "projects/fabric-api/src/main/modJson/fabric.mod.json",
"projects/fabric/src/client/resources/computercraft-client.fabric.mixins.json",
+ "projects/fabric/src/datagen/resources/fabric.mod.json",
"projects/fabric/src/main/resources/computercraft.fabric.mixins.json",
"projects/fabric/src/main/resources/fabric.mod.json",
"projects/fabric/src/testMod/resources/computercraft-gametest.fabric.mixins.json",
diff --git a/buildSrc/src/main/kotlin/cc-tweaked.gametest.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.mod.gradle.kts
similarity index 67%
rename from buildSrc/src/main/kotlin/cc-tweaked.gametest.gradle.kts
rename to buildSrc/src/main/kotlin/cc-tweaked.mod.gradle.kts
index 712b5e857..fb12f8120 100644
--- a/buildSrc/src/main/kotlin/cc-tweaked.gametest.gradle.kts
+++ b/buildSrc/src/main/kotlin/cc-tweaked.mod.gradle.kts
@@ -19,26 +19,32 @@ plugins {
val main = sourceSets["main"]
val client = sourceSets["client"]
-// Both testMod and testFixtures inherit from the main and client classpath, just so we have access to Minecraft classes.
+// datagen and testMod inherit from the main and client classpath, just so we have access to Minecraft classes.
+val datagen by sourceSets.creating {
+ compileClasspath += main.compileClasspath + client.compileClasspath
+ runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
+}
+
val testMod by sourceSets.creating {
compileClasspath += main.compileClasspath + client.compileClasspath
runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
}
-configurations {
- named(testMod.compileClasspathConfigurationName) {
- shouldResolveConsistentlyWith(compileClasspath.get())
- }
+val extraConfigurations = listOf(datagen, testMod)
- named(testMod.runtimeClasspathConfigurationName) {
- shouldResolveConsistentlyWith(runtimeClasspath.get())
+configurations {
+ for (config in extraConfigurations) {
+ named(config.compileClasspathConfigurationName) { shouldResolveConsistentlyWith(compileClasspath.get()) }
+ named(config.runtimeClasspathConfigurationName) { shouldResolveConsistentlyWith(runtimeClasspath.get()) }
}
}
// Like the main test configurations, we're safe to depend on source set outputs.
dependencies {
- add(testMod.implementationConfigurationName, main.output)
- add(testMod.implementationConfigurationName, client.output)
+ for (config in extraConfigurations) {
+ add(config.implementationConfigurationName, main.output)
+ add(config.implementationConfigurationName, client.output)
+ }
}
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt
index 70b3d1f3e..0124fee5c 100644
--- a/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt
+++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/CCTweakedExtension.kt
@@ -109,14 +109,13 @@ abstract class CCTweakedExtension(
val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
val main = otherJava.sourceSets.getByName("main")
val client = otherJava.sourceSets.getByName("client")
- val testMod = otherJava.sourceSets.findByName("testMod")
- val testFixtures = otherJava.sourceSets.findByName("testFixtures")
// Pull in sources from the other project.
extendSourceSet(otherProject, main)
extendSourceSet(otherProject, client)
- if (testMod != null) extendSourceSet(otherProject, testMod)
- if (testFixtures != null) extendSourceSet(otherProject, testFixtures)
+ for (sourceSet in listOf("datagen", "testMod", "testFixtures")) {
+ otherJava.sourceSets.findByName(sourceSet)?.let { extendSourceSet(otherProject, it) }
+ }
// The extra source-processing tasks should include these files too.
project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
diff --git a/doc/events/monitor_resize.md b/doc/events/monitor_resize.md
index 0bd4ef98e..bbc72be08 100644
--- a/doc/events/monitor_resize.md
+++ b/doc/events/monitor_resize.md
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
SPDX-License-Identifier: MPL-2.0
-->
-The [`monitor_resize`] event is fired when an adjacent or networked monitor's size is changed.
+The [`monitor_resize`] event is fired when an adjacent or networked [monitor's][`monitor`] size is changed.
## Return Values
1. [`string`]: The event name.
diff --git a/doc/events/monitor_touch.md b/doc/events/monitor_touch.md
index 400b57881..099ffd719 100644
--- a/doc/events/monitor_touch.md
+++ b/doc/events/monitor_touch.md
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
SPDX-License-Identifier: MPL-2.0
-->
-The [`monitor_touch`] event is fired when an adjacent or networked Advanced Monitor is right-clicked.
+The [`monitor_touch`] event is fired when an adjacent or networked [Advanced Monitor][`monitor`] is right-clicked.
## Return Values
1. [`string`]: The event name.
diff --git a/projects/common/build.gradle.kts b/projects/common/build.gradle.kts
index 952639cbf..a90db51a2 100644
--- a/projects/common/build.gradle.kts
+++ b/projects/common/build.gradle.kts
@@ -6,8 +6,8 @@ import cc.tweaked.gradle.*
plugins {
id("cc-tweaked.vanilla")
- id("cc-tweaked.gametest")
id("cc-tweaked.illuaminate")
+ id("cc-tweaked.mod")
id("cc-tweaked.publishing")
}
diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/GuiSprites.java b/projects/common/src/client/java/dan200/computercraft/client/gui/GuiSprites.java
index e6025c221..7428196c9 100644
--- a/projects/common/src/client/java/dan200/computercraft/client/gui/GuiSprites.java
+++ b/projects/common/src/client/java/dan200/computercraft/client/gui/GuiSprites.java
@@ -6,7 +6,6 @@ package dan200.computercraft.client.gui;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.client.render.ComputerBorderRenderer;
-import dan200.computercraft.data.client.ClientDataProviders;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureManager;
@@ -113,7 +112,6 @@ public final class GuiSprites extends TextureAtlasHolder {
* @param pocketBottom The texture for the bottom of a pocket computer.
* @param sidebar The texture for the computer sidebar.
* @see ComputerBorderRenderer
- * @see ClientDataProviders
*/
public record ComputerTextures(
ResourceLocation border,
diff --git a/projects/common/src/client/java/dan200/computercraft/data/client/ClientDataProviders.java b/projects/common/src/client/java/dan200/computercraft/data/client/ClientDataProviders.java
deleted file mode 100644
index 5d7b1a084..000000000
--- a/projects/common/src/client/java/dan200/computercraft/data/client/ClientDataProviders.java
+++ /dev/null
@@ -1,60 +0,0 @@
-// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
-//
-// SPDX-License-Identifier: MPL-2.0
-
-package dan200.computercraft.data.client;
-
-import dan200.computercraft.client.gui.GuiSprites;
-import dan200.computercraft.client.model.LecternPrintoutModel;
-import dan200.computercraft.data.DataProviders;
-import dan200.computercraft.shared.turtle.TurtleOverlay;
-import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
-import net.minecraft.client.renderer.texture.atlas.SpriteSource;
-import net.minecraft.client.renderer.texture.atlas.SpriteSources;
-import net.minecraft.client.renderer.texture.atlas.sources.SingleFile;
-import net.minecraft.core.HolderLookup;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.packs.PackType;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Stream;
-
-/**
- * A version of {@link DataProviders} which relies on client-side classes.
- *
- * This is called from {@link DataProviders#add(DataProviders.GeneratorSink)}.
- */
-public final class ClientDataProviders {
- private ClientDataProviders() {
- }
-
- public static void add(DataProviders.GeneratorSink generator, CompletableFuture registries) {
- generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
- out.accept(ResourceLocation.withDefaultNamespace("blocks"), List.of(
- new SingleFile(UpgradeSlot.LEFT_UPGRADE, Optional.empty()),
- new SingleFile(UpgradeSlot.RIGHT_UPGRADE, Optional.empty()),
- new SingleFile(LecternPrintoutModel.TEXTURE, Optional.empty())
- ));
- out.accept(GuiSprites.SPRITE_SHEET, Stream.of(
- // Buttons
- GuiSprites.TURNED_OFF.textures(),
- GuiSprites.TURNED_ON.textures(),
- GuiSprites.TERMINATE.textures(),
- // Computers
- GuiSprites.COMPUTER_NORMAL.textures(),
- GuiSprites.COMPUTER_ADVANCED.textures(),
- GuiSprites.COMPUTER_COMMAND.textures(),
- GuiSprites.COMPUTER_COLOUR.textures()
- ).flatMap(x -> x).map(x -> new SingleFile(x, Optional.empty())).toList());
- });
-
- generator.add(pack -> new ExtraModelsProvider(pack, registries) {
- @Override
- public Stream getModels(HolderLookup.Provider registries) {
- return registries.lookupOrThrow(TurtleOverlay.REGISTRY).listElements().map(x -> x.value().model());
- }
- });
- }
-}
diff --git a/projects/common/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/BlockModelProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/BlockModelProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/BlockModelProvider.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java b/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java
similarity index 60%
rename from projects/common/src/main/java/dan200/computercraft/data/DataProviders.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java
index dd68cf5b7..55c86db8d 100644
--- a/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java
+++ b/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java
@@ -7,8 +7,15 @@ package dan200.computercraft.data;
import com.mojang.serialization.Codec;
import dan200.computercraft.api.pocket.IPocketUpgrade;
import dan200.computercraft.api.turtle.ITurtleUpgrade;
+import dan200.computercraft.client.gui.GuiSprites;
+import dan200.computercraft.client.model.LecternPrintoutModel;
+import dan200.computercraft.data.client.ExtraModelsProvider;
import dan200.computercraft.shared.turtle.TurtleOverlay;
+import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
import net.minecraft.Util;
+import net.minecraft.client.renderer.texture.atlas.SpriteSource;
+import net.minecraft.client.renderer.texture.atlas.SpriteSources;
+import net.minecraft.client.renderer.texture.atlas.sources.SingleFile;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.data.DataProvider;
@@ -20,10 +27,15 @@ import net.minecraft.server.packs.PackType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
/**
* All data providers for ComputerCraft. We require a mod-loader abstraction {@link GeneratorSink} (instead of
@@ -55,15 +67,37 @@ public final class DataProviders {
generator.add(out -> new LanguageProvider(out, fullRegistries));
- // Unfortunately we rely on some client-side classes in this code. We just load in the client side data provider
- // and invoke that.
- try {
- Class.forName("dan200.computercraft.data.client.ClientDataProviders")
- .getMethod("add", GeneratorSink.class, CompletableFuture.class)
- .invoke(null, generator, fullRegistries);
- } catch (ReflectiveOperationException e) {
- throw new RuntimeException(e);
- }
+ generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
+ out.accept(ResourceLocation.withDefaultNamespace("blocks"), makeSprites(Stream.of(
+ UpgradeSlot.LEFT_UPGRADE,
+ UpgradeSlot.RIGHT_UPGRADE,
+ LecternPrintoutModel.TEXTURE
+ )));
+ out.accept(GuiSprites.SPRITE_SHEET, makeSprites(
+ // Buttons
+ GuiSprites.TURNED_OFF.textures(),
+ GuiSprites.TURNED_ON.textures(),
+ GuiSprites.TERMINATE.textures(),
+ // Computers
+ GuiSprites.COMPUTER_NORMAL.textures(),
+ GuiSprites.COMPUTER_ADVANCED.textures(),
+ GuiSprites.COMPUTER_COMMAND.textures(),
+ GuiSprites.COMPUTER_COLOUR.textures()
+ ));
+ });
+
+ generator.add(pack -> new ExtraModelsProvider(pack, fullRegistries) {
+ @Override
+ public Stream getModels(HolderLookup.Provider registries) {
+ return registries.lookupOrThrow(TurtleOverlay.REGISTRY).listElements().map(x -> x.value().model());
+ }
+ });
+ }
+
+ @SafeVarargs
+ @SuppressWarnings("varargs")
+ private static List makeSprites(final Stream... files) {
+ return Arrays.stream(files).flatMap(Function.identity()).map(x -> new SingleFile(x, Optional.empty())).toList();
}
public interface GeneratorSink {
diff --git a/projects/common/src/main/java/dan200/computercraft/data/ItemModelProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/ItemModelProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/ItemModelProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/ItemModelProvider.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/LanguageProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/LanguageProvider.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/LootTableProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/LootTableProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/LootTableProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/LootTableProvider.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/ModelProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/ModelProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/ModelProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/ModelProvider.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/PocketUpgradeProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/PocketUpgradeProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/PocketUpgradeProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/PocketUpgradeProvider.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/PrettyDataProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/PrettyDataProvider.java
similarity index 96%
rename from projects/common/src/main/java/dan200/computercraft/data/PrettyDataProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/PrettyDataProvider.java
index 9c78e245c..fc2ef47e3 100644
--- a/projects/common/src/main/java/dan200/computercraft/data/PrettyDataProvider.java
+++ b/projects/common/src/datagen/java/dan200/computercraft/data/PrettyDataProvider.java
@@ -7,6 +7,7 @@ package dan200.computercraft.data;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
+import dan200.computercraft.shared.util.PrettyJsonWriter;
import net.minecraft.data.CachedOutput;
import net.minecraft.data.DataProvider;
diff --git a/projects/common/src/main/java/dan200/computercraft/data/RecipeProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/RecipeProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/RecipeProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/RecipeProvider.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/TagProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/TagProvider.java
similarity index 98%
rename from projects/common/src/main/java/dan200/computercraft/data/TagProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/TagProvider.java
index a184a6cc9..e0e60f990 100644
--- a/projects/common/src/main/java/dan200/computercraft/data/TagProvider.java
+++ b/projects/common/src/datagen/java/dan200/computercraft/data/TagProvider.java
@@ -148,7 +148,7 @@ class TagProvider {
/**
* A wrapper over {@link ItemTagsProvider}.
*/
- interface ItemTagConsumer extends TagConsumer {
+ public interface ItemTagConsumer extends TagConsumer {
void copy(TagKey block, TagKey item);
}
}
diff --git a/projects/common/src/main/java/dan200/computercraft/data/TurtleOverlays.java b/projects/common/src/datagen/java/dan200/computercraft/data/TurtleOverlays.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/TurtleOverlays.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/TurtleOverlays.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/TurtleUpgradeProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/TurtleUpgradeProvider.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/TurtleUpgradeProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/TurtleUpgradeProvider.java
diff --git a/projects/common/src/client/java/dan200/computercraft/data/client/ExtraModelsProvider.java b/projects/common/src/datagen/java/dan200/computercraft/data/client/ExtraModelsProvider.java
similarity index 90%
rename from projects/common/src/client/java/dan200/computercraft/data/client/ExtraModelsProvider.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/client/ExtraModelsProvider.java
index 1c6ce5476..6fdcae771 100644
--- a/projects/common/src/client/java/dan200/computercraft/data/client/ExtraModelsProvider.java
+++ b/projects/common/src/datagen/java/dan200/computercraft/data/client/ExtraModelsProvider.java
@@ -19,11 +19,11 @@ import java.util.stream.Stream;
/**
* A data provider to generate {@link ExtraModels}.
*/
-abstract class ExtraModelsProvider implements DataProvider {
+public abstract class ExtraModelsProvider implements DataProvider {
private final Path path;
private final CompletableFuture registries;
- ExtraModelsProvider(PackOutput output, CompletableFuture registries) {
+ public ExtraModelsProvider(PackOutput output, CompletableFuture registries) {
path = output.getOutputFolder(PackOutput.Target.RESOURCE_PACK).resolve(ExtraModels.PATH.getNamespace()).resolve(ExtraModels.PATH.getPath());
this.registries = registries;
}
diff --git a/projects/common/src/main/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java b/projects/common/src/datagen/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/recipe/AbstractRecipeBuilder.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/recipe/ShapedSpecBuilder.java b/projects/common/src/datagen/java/dan200/computercraft/data/recipe/ShapedSpecBuilder.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/recipe/ShapedSpecBuilder.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/recipe/ShapedSpecBuilder.java
diff --git a/projects/common/src/main/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java b/projects/common/src/datagen/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java
similarity index 100%
rename from projects/common/src/main/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java
rename to projects/common/src/datagen/java/dan200/computercraft/data/recipe/ShapelessSpecBuilder.java
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 dd334cb3c..a650ab69f 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
@@ -83,35 +83,35 @@
"gui.computercraft.config.disabled_generic_methods.tooltip": "A list of generic methods or method sources to disable. Generic methods are\nmethods added to a block/block entity when there is no explicit peripheral\nprovider. This includes inventory methods (i.e. inventory.getItemDetail,\ninventory.pushItems), and (if on Forge), the fluid_storage and energy_storage\nmethods.\nMethods in this list can either be a whole group of methods (computercraft:inventory)\nor a single method (computercraft:inventory#pushItems).\n",
"gui.computercraft.config.execution": "Execution",
"gui.computercraft.config.execution.computer_threads": "Computer threads",
- "gui.computercraft.config.execution.computer_threads.tooltip": "Set the number of threads computers can run on. A higher number means more\ncomputers can run at once, but may induce lag. Please note that some mods may\nnot work with a thread count higher than 1. Use with caution.\nRange: > 1",
+ "gui.computercraft.config.execution.computer_threads.tooltip": "Set the number of threads computers can run on. A higher number means more\ncomputers can run at once, but may induce lag. Please note that some mods may\nnot work with a thread count higher than 1. Use with caution.",
"gui.computercraft.config.execution.max_main_computer_time": "Server tick computer time limit",
- "gui.computercraft.config.execution.max_main_computer_time.tooltip": "The ideal maximum time a computer can execute for in a tick, in milliseconds.\nNote, we will quite possibly go over this limit, as there's no way to tell how\nlong a will take - this aims to be the upper bound of the average time.\nRange: > 1",
+ "gui.computercraft.config.execution.max_main_computer_time.tooltip": "The ideal maximum time a computer can execute for in a tick, in milliseconds.\nNote, we will quite possibly go over this limit, as there's no way to tell how\nlong a will take - this aims to be the upper bound of the average time.",
"gui.computercraft.config.execution.max_main_global_time": "Server tick global time limit",
- "gui.computercraft.config.execution.max_main_global_time.tooltip": "The maximum time that can be spent executing tasks in a single tick, in\nmilliseconds.\nNote, we will quite possibly go over this limit, as there's no way to tell how\nlong a will take - this aims to be the upper bound of the average time.\nRange: > 1",
+ "gui.computercraft.config.execution.max_main_global_time.tooltip": "The maximum time that can be spent executing tasks in a single tick, in\nmilliseconds.\nNote, we will quite possibly go over this limit, as there's no way to tell how\nlong a will take - this aims to be the upper bound of the average time.",
"gui.computercraft.config.execution.tooltip": "Controls execution behaviour of computers. This is largely intended for\nfine-tuning servers, and generally shouldn't need to be touched.",
"gui.computercraft.config.floppy_space_limit": "Floppy Disk space limit (bytes)",
"gui.computercraft.config.floppy_space_limit.tooltip": "The disk space limit for floppy disks, in bytes.",
"gui.computercraft.config.http": "HTTP",
"gui.computercraft.config.http.bandwidth": "Bandwidth",
"gui.computercraft.config.http.bandwidth.global_download": "Global download limit",
- "gui.computercraft.config.http.bandwidth.global_download.tooltip": "The number of bytes which can be downloaded in a second. This is shared across all computers. (bytes/s).\nRange: > 1",
+ "gui.computercraft.config.http.bandwidth.global_download.tooltip": "The number of bytes which can be downloaded in a second. This is shared across all computers. (bytes/s).",
"gui.computercraft.config.http.bandwidth.global_upload": "Global upload limit",
- "gui.computercraft.config.http.bandwidth.global_upload.tooltip": "The number of bytes which can be uploaded in a second. This is shared across all computers. (bytes/s).\nRange: > 1",
+ "gui.computercraft.config.http.bandwidth.global_upload.tooltip": "The number of bytes which can be uploaded in a second. This is shared across all computers. (bytes/s).",
"gui.computercraft.config.http.bandwidth.tooltip": "Limits bandwidth used by computers.",
"gui.computercraft.config.http.enabled": "Enable the HTTP API",
"gui.computercraft.config.http.enabled.tooltip": "Enable the \"http\" API on Computers. Disabling this also disables the \"pastebin\" and\n\"wget\" programs, that many users rely on. It's recommended to leave this on and use\nthe \"rules\" config option to impose more fine-grained control.",
"gui.computercraft.config.http.max_requests": "Maximum concurrent requests",
- "gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.\nRange: > 0",
+ "gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.",
"gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets",
- "gui.computercraft.config.http.max_websockets.tooltip": "The number of websockets a computer can have open at one time.\nRange: > 1",
+ "gui.computercraft.config.http.max_websockets.tooltip": "The number of websockets a computer can have open at one time.",
"gui.computercraft.config.http.proxy": "Proxy",
"gui.computercraft.config.http.proxy.host": "Host name",
"gui.computercraft.config.http.proxy.host.tooltip": "The hostname or IP address of the proxy server.",
"gui.computercraft.config.http.proxy.port": "Port",
- "gui.computercraft.config.http.proxy.port.tooltip": "The port of the proxy server.\nRange: 1 ~ 65536",
+ "gui.computercraft.config.http.proxy.port.tooltip": "The port of the proxy server.",
"gui.computercraft.config.http.proxy.tooltip": "Tunnels HTTP and websocket requests through a proxy server. Only affects HTTP\nrules with \"use_proxy\" set to true (off by default).\nIf authentication is required for the proxy, create a \"computercraft-proxy.pw\"\nfile in the same directory as \"computercraft-server.toml\", containing the\nusername and password separated by a colon, e.g. \"myuser:mypassword\". For\nSOCKS4 proxies only the username is required.",
"gui.computercraft.config.http.proxy.type": "Proxy type",
- "gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5",
+ "gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.",
"gui.computercraft.config.http.rules": "Allow/deny rules",
"gui.computercraft.config.http.rules.tooltip": "A list of rules which control behaviour of the \"http\" API for specific domains or\nIPs. Each rule matches against a hostname and an optional port, and then sets several\nproperties for the request. Rules are evaluated in order, meaning earlier rules override\nlater ones.\n\nValid properties:\n - \"host\" (required): The domain or IP address this rule matches. This may be a domain name\n (\"pastebin.com\"), wildcard (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\").\n - \"port\" (optional): Only match requests for a specific port, such as 80 or 443.\n\n - \"action\" (optional): Whether to allow or deny this request.\n - \"max_download\" (optional): The maximum size (in bytes) that a computer can download in this\n request.\n - \"max_upload\" (optional): The maximum size (in bytes) that a computer can upload in a this request.\n - \"max_websocket_message\" (optional): The maximum size (in bytes) that a computer can send or\n receive in one websocket packet.\n - \"use_proxy\" (optional): Enable use of the HTTP/SOCKS proxy if it is configured.",
"gui.computercraft.config.http.tooltip": "Controls the HTTP API",
@@ -120,61 +120,61 @@
"gui.computercraft.config.log_computer_errors": "Log computer errors",
"gui.computercraft.config.log_computer_errors.tooltip": "Log exceptions thrown by peripherals and other Lua objects. This makes it easier\nfor mod authors to debug problems, but may result in log spam should people use\nbuggy methods.",
"gui.computercraft.config.maximum_open_files": "Maximum files open per computer",
- "gui.computercraft.config.maximum_open_files.tooltip": "Set how many files a computer can have open at the same time. Set to 0 for unlimited.\nRange: > 0",
+ "gui.computercraft.config.maximum_open_files.tooltip": "Set how many files a computer can have open at the same time. Set to 0 for unlimited.",
"gui.computercraft.config.monitor_distance": "Monitor distance",
- "gui.computercraft.config.monitor_distance.tooltip": "The maximum distance monitors will render at. This defaults to the standard tile\nentity limit, but may be extended if you wish to build larger monitors.\nRange: 16 ~ 1024",
+ "gui.computercraft.config.monitor_distance.tooltip": "The maximum distance monitors will render at. This defaults to the standard tile\nentity limit, but may be extended if you wish to build larger monitors.",
"gui.computercraft.config.monitor_renderer": "Monitor renderer",
- "gui.computercraft.config.monitor_renderer.tooltip": "The renderer to use for monitors. Generally this should be kept at \"best\" - if\nmonitors have performance issues, you may wish to experiment with alternative\nrenderers.\nAllowed Values: BEST, TBO, VBO",
+ "gui.computercraft.config.monitor_renderer.tooltip": "The renderer to use for monitors. Generally this should be kept at \"best\" - if\nmonitors have performance issues, you may wish to experiment with alternative\nrenderers.",
"gui.computercraft.config.peripheral": "Peripherals",
"gui.computercraft.config.peripheral.command_block_enabled": "Enable command block peripheral",
"gui.computercraft.config.peripheral.command_block_enabled.tooltip": "Enable Command Block peripheral support",
"gui.computercraft.config.peripheral.max_notes_per_tick": "Maximum notes that a computer can play at once",
- "gui.computercraft.config.peripheral.max_notes_per_tick.tooltip": "Maximum amount of notes a speaker can play at once.\nRange: > 1",
+ "gui.computercraft.config.peripheral.max_notes_per_tick.tooltip": "Maximum amount of notes a speaker can play at once.",
"gui.computercraft.config.peripheral.modem_high_altitude_range": "Modem range (high-altitude)",
- "gui.computercraft.config.peripheral.modem_high_altitude_range.tooltip": "The range of Wireless Modems at maximum altitude in clear weather, in meters.\nRange: 0 ~ 100000",
+ "gui.computercraft.config.peripheral.modem_high_altitude_range.tooltip": "The range of Wireless Modems at maximum altitude in clear weather, in meters.",
"gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm": "Modem range (high-altitude, bad weather)",
- "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm.tooltip": "The range of Wireless Modems at maximum altitude in stormy weather, in meters.\nRange: 0 ~ 100000",
+ "gui.computercraft.config.peripheral.modem_high_altitude_range_during_storm.tooltip": "The range of Wireless Modems at maximum altitude in stormy weather, in meters.",
"gui.computercraft.config.peripheral.modem_range": "Modem range (default)",
- "gui.computercraft.config.peripheral.modem_range.tooltip": "The range of Wireless Modems at low altitude in clear weather, in meters.\nRange: 0 ~ 100000",
+ "gui.computercraft.config.peripheral.modem_range.tooltip": "The range of Wireless Modems at low altitude in clear weather, in meters.",
"gui.computercraft.config.peripheral.modem_range_during_storm": "Modem range (bad weather)",
- "gui.computercraft.config.peripheral.modem_range_during_storm.tooltip": "The range of Wireless Modems at low altitude in stormy weather, in meters.\nRange: 0 ~ 100000",
+ "gui.computercraft.config.peripheral.modem_range_during_storm.tooltip": "The range of Wireless Modems at low altitude in stormy weather, in meters.",
"gui.computercraft.config.peripheral.monitor_bandwidth": "Monitor bandwidth",
- "gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "The limit to how much monitor data can be sent *per tick*. Note:\n - Bandwidth is measured before compression, so the data sent to the client is\n smaller.\n - This ignores the number of players a packet is sent to. Updating a monitor for\n one player consumes the same bandwidth limit as sending to 20.\n - A full sized monitor sends ~25kb of data. So the default (1MB) allows for ~40\n monitors to be updated in a single tick.\nSet to 0 to disable.\nRange: > 0",
+ "gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "The limit to how much monitor data can be sent *per tick*. Note:\n - Bandwidth is measured before compression, so the data sent to the client is\n smaller.\n - This ignores the number of players a packet is sent to. Updating a monitor for\n one player consumes the same bandwidth limit as sending to 20.\n - A full sized monitor sends ~25kb of data. So the default (1MB) allows for ~40\n monitors to be updated in a single tick.\nSet to 0 to disable.",
"gui.computercraft.config.peripheral.tooltip": "Various options relating to peripherals.",
"gui.computercraft.config.term_sizes": "Terminal sizes",
"gui.computercraft.config.term_sizes.computer": "Computer",
"gui.computercraft.config.term_sizes.computer.height": "Terminal height",
- "gui.computercraft.config.term_sizes.computer.height.tooltip": "Range: 1 ~ 255",
+ "gui.computercraft.config.term_sizes.computer.height.tooltip": "Height of computer terminal",
"gui.computercraft.config.term_sizes.computer.tooltip": "Terminal size of computers.",
"gui.computercraft.config.term_sizes.computer.width": "Terminal width",
- "gui.computercraft.config.term_sizes.computer.width.tooltip": "Range: 1 ~ 255",
+ "gui.computercraft.config.term_sizes.computer.width.tooltip": "Width of computer terminal",
"gui.computercraft.config.term_sizes.monitor": "Monitor",
"gui.computercraft.config.term_sizes.monitor.height": "Max monitor height",
- "gui.computercraft.config.term_sizes.monitor.height.tooltip": "Range: 1 ~ 32",
+ "gui.computercraft.config.term_sizes.monitor.height.tooltip": "Maximum height of monitors",
"gui.computercraft.config.term_sizes.monitor.tooltip": "Maximum size of monitors (in blocks).",
"gui.computercraft.config.term_sizes.monitor.width": "Max monitor width",
- "gui.computercraft.config.term_sizes.monitor.width.tooltip": "Range: 1 ~ 32",
+ "gui.computercraft.config.term_sizes.monitor.width.tooltip": "Maximum width of monitors",
"gui.computercraft.config.term_sizes.pocket_computer": "Pocket Computer",
"gui.computercraft.config.term_sizes.pocket_computer.height": "Terminal height",
- "gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "Range: 1 ~ 255",
+ "gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "Height of pocket computer terminal",
"gui.computercraft.config.term_sizes.pocket_computer.tooltip": "Terminal size of pocket computers.",
"gui.computercraft.config.term_sizes.pocket_computer.width": "Terminal width",
- "gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "Range: 1 ~ 255",
+ "gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "Width of pocket computer terminal",
"gui.computercraft.config.term_sizes.tooltip": "Configure the size of various computer's terminals.\nLarger terminals require more bandwidth, so use with care.",
"gui.computercraft.config.turtle": "Turtles",
"gui.computercraft.config.turtle.advanced_fuel_limit": "Advanced Turtle fuel limit",
- "gui.computercraft.config.turtle.advanced_fuel_limit.tooltip": "The fuel limit for Advanced Turtles.\nRange: > 0",
+ "gui.computercraft.config.turtle.advanced_fuel_limit.tooltip": "The fuel limit for Advanced Turtles.",
"gui.computercraft.config.turtle.can_push": "Turtles can push entities",
"gui.computercraft.config.turtle.can_push.tooltip": "If set to true, Turtles will push entities out of the way instead of stopping if\nthere is space to do so.",
"gui.computercraft.config.turtle.need_fuel": "Enable fuel",
"gui.computercraft.config.turtle.need_fuel.tooltip": "Set whether Turtles require fuel to move.",
"gui.computercraft.config.turtle.normal_fuel_limit": "Turtle fuel limit",
- "gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "The fuel limit for Turtles.\nRange: > 0",
+ "gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "The fuel limit for Turtles.",
"gui.computercraft.config.turtle.tooltip": "Various options relating to turtles.",
"gui.computercraft.config.upload_max_size": "File upload size limit (bytes)",
- "gui.computercraft.config.upload_max_size.tooltip": "The file upload size limit, in bytes. Must be in range of 1 KiB and 16 MiB.\nKeep in mind that uploads are processed in a single tick - large files or\npoor network performance can stall the networking thread. And mind the disk space!\nRange: 1024 ~ 16777216",
+ "gui.computercraft.config.upload_max_size.tooltip": "The file upload size limit, in bytes. Must be in range of 1 KiB and 16 MiB.\nKeep in mind that uploads are processed in a single tick - large files or\npoor network performance can stall the networking thread. And mind the disk space!",
"gui.computercraft.config.upload_nag_delay": "Upload nag delay",
- "gui.computercraft.config.upload_nag_delay.tooltip": "The delay in seconds after which we'll notify about unhandled imports. Set to 0 to disable.\nRange: 0 ~ 60",
+ "gui.computercraft.config.upload_nag_delay.tooltip": "The delay in seconds after which we'll notify about unhandled imports. Set to 0 to disable.",
"gui.computercraft.pocket_computer_overlay": "Pocket computer open. Press ESC to close.",
"gui.computercraft.terminal": "Computer terminal",
"gui.computercraft.tooltip.computer_id": "Computer ID: %s",
diff --git a/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigFile.java b/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigFile.java
index 5fe5f01d2..6f4feed74 100644
--- a/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigFile.java
+++ b/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigFile.java
@@ -9,9 +9,7 @@ import com.google.common.base.Splitter;
import javax.annotation.Nullable;
import javax.annotation.OverridingMethodsMustInvokeSuper;
import java.nio.file.Path;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.List;
+import java.util.*;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;
@@ -19,27 +17,47 @@ import java.util.stream.Stream;
/**
* A config file which the user can modify.
*/
-public interface ConfigFile {
- String TRANSLATION_PREFIX = "gui.computercraft.config.";
- Splitter SPLITTER = Splitter.on('.');
+public abstract class ConfigFile {
+ public static final String TRANSLATION_PREFIX = "gui.computercraft.config.";
+ public static final Splitter SPLITTER = Splitter.on('.');
/**
* An entry in the config file, either a {@link Value} or {@linkplain Group group of other entries}.
*/
- sealed interface Entry permits Group, Value {
+ public abstract static sealed class Entry permits Group, Value {
+ protected final String path;
+ private final String translationKey;
+ private final String comment;
+
+ protected Entry(String path, String comment) {
+ this.path = path;
+ this.translationKey = TRANSLATION_PREFIX + path;
+ this.comment = comment;
+ }
+
+ public final String path() {
+ return path;
+ }
+
/**
* Get the translation key of this config entry.
*
* @return This entry's translation key.
*/
- String translationKey();
+ public final String translationKey() {
+ return translationKey;
+ }
/**
* Get the comment about this config entry.
*
* @return The comment for this config entry.
*/
- String comment();
+ public final String comment() {
+ return comment;
+ }
+
+ abstract Stream entries();
}
/**
@@ -47,13 +65,38 @@ public interface ConfigFile {
*
* @param The type of the stored value.
*/
- non-sealed interface Value extends Entry, Supplier {
+ public abstract static non-sealed class Value extends Entry implements Supplier {
+ protected Value(String translationKey, String comment) {
+ super(translationKey, comment);
+ }
+
+ @Override
+ Stream entries() {
+ return Stream.of(this);
+ }
}
/**
* A group of config entries.
*/
- non-sealed interface Group extends Entry {
+ public static final class Group extends Entry {
+ private final Map children;
+
+ public Group(String translationKey, String comment, Map children) {
+ super(translationKey, comment);
+ this.children = children;
+ }
+
+ @Override
+ Stream entries() {
+ return Stream.concat(Stream.of(this), children.values().stream().flatMap(Entry::entries));
+ }
+ }
+
+ protected final Map entries;
+
+ protected ConfigFile(Map entries) {
+ this.entries = entries;
}
/**
@@ -61,16 +104,46 @@ public interface ConfigFile {
*
* @return All config keys.
*/
- Stream entries();
+ public final Stream entries() {
+ return entries.values().stream().flatMap(Entry::entries);
+ }
- @Nullable
- Entry getEntry(String path);
+ public final @Nullable Entry getEntry(String path) {
+ var iterator = SPLITTER.split(path).iterator();
+
+ var entry = entries.get(iterator.next());
+ while (iterator.hasNext()) {
+ if (!(entry instanceof Group group)) return null;
+ entry = group.children.get(iterator.next());
+ }
+
+ return entry;
+ }
/**
* A builder which can be used to generate a config object.
*/
- abstract class Builder {
- protected final Deque groupStack = new ArrayDeque<>();
+ public abstract static class Builder {
+ protected record RootGroup(String path, Map children) {
+ public RootGroup {
+ }
+ }
+
+ protected final Deque groupStack = new ArrayDeque<>();
+ private @Nullable String pendingComment;
+
+ protected Builder() {
+ groupStack.addLast(new RootGroup("", new HashMap<>()));
+ }
+
+ protected final String getPath() {
+ return groupStack.getLast().path();
+ }
+
+ protected final String getPath(String name) {
+ var path = groupStack.getLast().path();
+ return path.isEmpty() ? name : path + "." + name;
+ }
protected String getTranslation(String name) {
var key = new StringBuilder(TRANSLATION_PREFIX);
@@ -86,7 +159,19 @@ public interface ConfigFile {
* @param comment The comment.
* @return The current object, for chaining.
*/
- public abstract Builder comment(String comment);
+ @OverridingMethodsMustInvokeSuper
+ public ConfigFile.Builder comment(String comment) {
+ if (pendingComment != null) throw new IllegalStateException("Already have a comment");
+ pendingComment = comment;
+ return this;
+ }
+
+ protected String takeComment() {
+ var comment = pendingComment;
+ if (comment == null) throw new IllegalStateException("No comment specified");
+ pendingComment = null;
+ return comment;
+ }
/**
* Push a new config group.
@@ -95,7 +180,10 @@ public interface ConfigFile {
*/
@OverridingMethodsMustInvokeSuper
public void push(String name) {
- groupStack.addLast(name);
+ var path = getPath(name);
+ Map children = new HashMap<>();
+ groupStack.getLast().children().put(name, new Group(path, takeComment(), children));
+ groupStack.addLast(new RootGroup(path, children));
}
/**
@@ -113,22 +201,22 @@ public interface ConfigFile {
*/
public abstract Builder worldRestart();
- public abstract ConfigFile.Value define(String path, T defaultValue);
+ public abstract ConfigFile.Value define(String name, T defaultValue);
/**
* A boolean-specific override of the above {@link #define(String, Object)} method.
*
- * @param path The path to the value we're defining.
+ * @param name The name of the value we're defining.
* @param defaultValue The default value.
* @return The accessor for this config option.
*/
- public abstract ConfigFile.Value define(String path, boolean defaultValue);
+ public abstract ConfigFile.Value define(String name, boolean defaultValue);
- public abstract ConfigFile.Value defineInRange(String path, int defaultValue, int min, int max);
+ public abstract ConfigFile.Value defineInRange(String name, int defaultValue, int min, int max);
- public abstract ConfigFile.Value> defineList(String path, List extends T> defaultValue, Supplier newValue, Predicate