1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-28 02:35:13 +00:00

Update to Gradle 9.2

- Update to Loom 1.12. This requires Java 21, so we now build with Java
   21, but targetting 17. The new "-release" flag does make this much
   easier, so hopefully shouldn't cause too many issues.

 - Bump versions of a lot of other things.

 - Fix various errorprone/checkstyle grumbles.
This commit is contained in:
Jonathan Coates
2025-10-31 19:50:44 +00:00
parent 157ce4fa55
commit 569de7fafb
39 changed files with 584 additions and 587 deletions

View File

@@ -4,13 +4,11 @@
import cc.tweaked.gradle.JUnitExt
import net.fabricmc.loom.api.LoomGradleExtensionAPI
import net.fabricmc.loom.util.gradle.SourceSetHelper
import org.jetbrains.gradle.ext.*
import org.jetbrains.gradle.ext.Application
plugins {
publishing
alias(libs.plugins.taskTree)
alias(libs.plugins.githubRelease)
alias(libs.plugins.gradleVersions)
alias(libs.plugins.versionCatalogUpdate)
@@ -70,7 +68,7 @@ idea.project.settings.runConfigurations {
val fabricProject = evaluationDependsOn(":fabric")
val classPathGroup = fabricProject.extensions.getByType<LoomGradleExtensionAPI>().mods
.joinToString(File.pathSeparator + File.pathSeparator) { modSettings ->
SourceSetHelper.getClasspath(modSettings, project).joinToString(File.pathSeparator) { it.absolutePath }
modSettings.modFiles.joinToString(File.pathSeparator) { it.absolutePath }
}
vmParameters = "-ea -Dfabric.classPathGroups=$classPathGroup"
@@ -115,8 +113,12 @@ idea.project.settings.compiler.javac {
.toMap()
}
repositories() {
mavenCentral()
}
versionCatalogUpdate {
sortByKey = false
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
keep { keepUnusedLibraries = true }
keep { keepUnusedVersions = true }
}

View File

@@ -25,6 +25,7 @@ repositories {
name = "Fabric"
content {
includeGroup("net.fabricmc")
includeGroup("net.fabricmc.unpick")
}
}
@@ -69,6 +70,6 @@ gradlePlugin {
versionCatalogUpdate {
sortByKey = false
keep { keepUnusedLibraries = true }
keep { keepUnusedVersions = true }
catalogFile = file("../gradle/libs.versions.toml")
}

View File

@@ -4,10 +4,7 @@
/** Default configuration for Fabric projects. */
import cc.tweaked.gradle.CCTweakedExtension
import cc.tweaked.gradle.CCTweakedPlugin
import cc.tweaked.gradle.IdeaRunConfigurations
import cc.tweaked.gradle.MinecraftConfigurations
import cc.tweaked.gradle.*
plugins {
`java-library`
@@ -67,3 +64,19 @@ dependencies {
tasks.ideaSyncTask {
doLast { IdeaRunConfigurations(project).patch() }
}
tasks.named("checkDependencyConsistency", DependencyCheck::class.java) {
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
// Minecraft depends on lwjgl, but Fabric forces it to a more recent version
for (lwjgl in listOf(
"lwjgl",
"lwjgl-glfw",
"lwjgl-jemalloc",
"lwjgl-openal",
"lwjgl-opengl",
"lwjgl-stb",
"lwjgl-tinyfd",
)) {
override("org.lwjgl", lwjgl, "3.3.2")
}
}

View File

@@ -17,6 +17,8 @@ plugins {
checkstyle
id("com.diffplug.spotless")
id("net.ltgt.errorprone")
// Required for cross-project dependencies in Fabric
id("net.fabricmc.fabric-loom-companion")
}
val modVersion: String by extra
@@ -28,9 +30,9 @@ version = modVersion
base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
java {
toolchain {
languageVersion = CCTweakedPlugin.JAVA_VERSION
}
toolchain { languageVersion = CCTweakedPlugin.JDK_VERSION }
sourceCompatibility = CCTweakedPlugin.JAVA_VERSION
targetCompatibility = CCTweakedPlugin.JAVA_VERSION
withSourcesJar()
}
@@ -79,8 +81,18 @@ dependencies {
// Configure default JavaCompile tasks with our arguments.
sourceSets.all {
tasks.named(compileJavaTaskName, JavaCompile::class.java) {
// Processing just gives us "No processor claimed any of these annotations", so skip that!
options.compilerArgs.addAll(listOf("-Xlint", "-Xlint:-processing"))
// Explicitly set release, as that limits the APIs we can use to the right version of Java.
options.release = CCTweakedPlugin.JAVA_TARGET.asInt()
options.compilerArgs.addAll(
listOf(
"-Xlint",
// Processing just gives us "No processor claimed any of these annotations", so skip that!
"-Xlint:-processing",
// We violate this pattern too often for it to be a helpful warning. Something to improve one day!
"-Xlint:-this-escape",
),
)
options.errorprone {
check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
@@ -93,6 +105,7 @@ sourceSets.all {
check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
check("InvalidInlineTag", CheckSeverity.OFF) // Triggered by @snippet. Can be removed on Java 21.
option("UnusedMethod:ExemptingMethodAnnotations", "dan200.computercraft.api.lua.LuaFunction")
check("NullAway", CheckSeverity.ERROR)
option(

View File

@@ -8,6 +8,7 @@
* See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
*/
import cc.tweaked.gradle.CCTweakedPlugin
import cc.tweaked.gradle.MinecraftConfigurations
import cc.tweaked.gradle.clientClasses
import cc.tweaked.gradle.commonClasses
@@ -52,3 +53,5 @@ dependencies {
testImplementation(testFixtures(project))
}
kotlin.compilerOptions.jvmTarget = CCTweakedPlugin.KOTLIN_TARGET

View File

@@ -223,7 +223,7 @@ abstract class CCTweakedExtension(private val project: Project) {
).resolve().single()
}
private fun <T> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
private fun <T: Any> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
val baseResult = project.providers.exec {
commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command
}

View File

@@ -4,6 +4,7 @@
package cc.tweaked.gradle
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
@@ -13,6 +14,7 @@ import org.gradle.plugins.ide.idea.model.IdeaModel
import org.jetbrains.gradle.ext.IdeaExtPlugin
import org.jetbrains.gradle.ext.runConfigurations
import org.jetbrains.gradle.ext.settings
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
/**
* Configures projects to match a shared configuration.
@@ -42,6 +44,17 @@ class CCTweakedPlugin : Plugin<Project> {
}
companion object {
val JAVA_VERSION = JavaLanguageVersion.of(17)
/**
* The version we run with. We use Java 21 here, as our Gradle build requires that.
*/
val JDK_VERSION = JavaLanguageVersion.of(21)
/**
* The Java version we target. Should be the same as what Minecraft uses.
*/
val JAVA_TARGET = JavaLanguageVersion.of(17)
val JAVA_VERSION = JavaVersion.toVersion(JAVA_TARGET.asInt())
val KOTLIN_TARGET = JvmTarget.fromTarget(JAVA_TARGET.toString())
}
}

View File

@@ -45,6 +45,10 @@ abstract class DependencyCheck : DefaultTask() {
overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
}
fun override(group: String, module: String, version: String) {
overrides.put("$group:$module", version)
}
/**
* Add a configuration to check.
*/

View File

@@ -124,7 +124,7 @@ class CloseScope : AutoCloseable {
}
/** Proxy method to avoid overload ambiguity. */
fun <T> Property<T>.setProvider(provider: Provider<out T>) = set(provider)
fun <T: Any> Property<T >.setProvider(provider: Provider<out T>) = set(provider)
/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */
fun Provider<out FileSystemLocation>.getAbsolutePath(): String = get().asFile.absolutePath

View File

@@ -40,7 +40,6 @@ class MinecraftConfigurations private constructor(private val project: Project)
// Set up an API configuration for clients (to ensure it's consistent with the main source set).
val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
isVisible = false
isCanBeConsumed = false
isCanBeResolved = false
}

View File

@@ -1,2 +1,2 @@
#This file is generated by updateDaemonJvm
toolchainVersion=17
toolchainVersion=21

View File

@@ -23,17 +23,17 @@ netty = "4.1.82.Final"
slf4j = "2.0.1"
# Core dependencies (independent of Minecraft)
asm = "9.6"
asm = "9.9"
autoService = "1.1.1"
checkerFramework = "3.42.0"
checkerFramework = "3.51.1"
cobalt = { strictly = "0.9.6" }
commonsCli = "1.6.0"
jetbrainsAnnotations = "24.1.0"
commonsCli = "1.10.0"
jetbrainsAnnotations = "26.0.2-1"
jspecify = "1.0.0"
jzlib = "1.1.3"
kotlin = "2.1.10"
kotlin-coroutines = "1.10.1"
nightConfig = "3.8.1"
kotlin = "2.2.21"
kotlin-coroutines = "1.10.2"
nightConfig = "3.8.3"
# Minecraft mods
emi = "1.0.8+1.20.1"
@@ -50,32 +50,31 @@ create-forge = "6.0.0-9"
create-fabric = "6.0.7.0+mc1.20.1-build.1716"
# Testing
hamcrest = "2.2"
jqwik = "1.8.2"
junit = "5.11.4"
junitPlatform = "1.11.4"
hamcrest = "3.0"
jqwik = "1.9.3"
junit = "6.0.1"
junitPlatform = "6.0.1"
jmh = "1.37"
# Build tools
cctJavadoc = "1.8.4"
checkstyle = "10.23.1"
errorProne-core = "2.38.0"
errorProne-plugin = "4.1.0"
fabric-loom = "1.10.4"
checkstyle = "12.1.1"
errorProne-core = "2.43.0"
errorProne-plugin = "4.3.0"
fabric-loom = "1.12.3"
githubRelease = "2.5.2"
gradleVersions = "0.50.0"
ideaExt = "1.1.7"
gradleVersions = "0.53.0"
ideaExt = "1.3"
illuaminate = "0.1.0-83-g1131f68"
lwjgl = "3.3.3"
lwjgl = "3.3.6"
minotaur = "2.8.7"
modDevGradle = "2.0.95"
nullAway = "0.12.7"
shadow = "8.3.1"
spotless = "7.0.2"
taskTree = "2.1.1"
teavm = "0.13.0-SQUID.1"
modDevGradle = "2.0.116"
nullAway = "0.12.11"
shadow = "9.2.2"
spotless = "8.0.0"
teavm = "0.13.0-SQUID.2"
vanillaExtract = "0.2.1"
versionCatalogUpdate = "0.8.1"
versionCatalogUpdate = "1.0.1"
[libraries]
# Normal dependencies
@@ -174,7 +173,6 @@ githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "g
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
[bundles]

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

754
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -63,16 +63,25 @@ tasks.javadoc {
""".trimIndent(),
)
taglets("cc.tweaked.javadoc.SnippetTaglet")
tagletPath(configurations.detachedConfiguration(dependencies.project(":lints")).toList())
val snippetSources = listOf(":common", ":fabric", ":forge").flatMap {
project(it).sourceSets["examples"].allSource.sourceDirectories
}
inputs.files(snippetSources)
jFlags("-Dcc.snippet-path=" + snippetSources.joinToString(File.pathSeparator) { it.absolutePath })
addPathOption("-snippet-path").value = snippetSources
}
// Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump.
source(project(":core-api").sourceSets.main.map { it.allJava })
options {
this as StandardJavadocDocletOptions
addBooleanOption("-allow-script-in-comments", true)
bottom(
"""
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
<link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet">
""".trimIndent(),
)
}
}

View File

@@ -27,7 +27,7 @@ import java.util.function.BiFunction;
* <h3>Registering the upgrade serialiser</h3>
* First, let's create a new class that implements {@link ITurtleUpgrade}. It is recommended to subclass
* {@link AbstractTurtleUpgrade}, as that provides a default implementation of most methods.
* <p>
*
* {@snippet class=com.example.examplemod.ExampleTurtleUpgrade region=body}
* <p>
* Now we must construct a new upgrade serialiser. In most cases, you can use one of the helper methods

View File

@@ -81,7 +81,7 @@ val luaJavadoc by tasks.registering(Javadoc::class) {
options.addStringOption("project-root", rootProject.file(".").absolutePath)
options.noTimestamp(false)
javadocTool = javaToolchains.javadocToolFor { languageVersion = CCTweakedPlugin.JAVA_VERSION }
javadocTool = javaToolchains.javadocToolFor { languageVersion = CCTweakedPlugin.JDK_VERSION }
}
val lintLua by tasks.registering(IlluaminateExec::class) {

View File

@@ -4,7 +4,6 @@
package dan200.computercraft.impl.network.wired;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -61,7 +60,6 @@ final class InvariantChecker {
return okay;
}
@Contract("")
private static <T> @Nullable T makeNullable(T object) {
return object;
}

View File

@@ -123,7 +123,7 @@ import java.util.function.Predicate;
/**
* Registers ComputerCraft's registry entries and additional objects, such as {@link CauldronInteraction}s and
* {@link DetailProvider}s
* {@link DetailProvider}s.
* <p>
* The functions in this class should be called from a loader-specific class.
*/

View File

@@ -13,7 +13,7 @@ import net.minecraft.network.FriendlyByteBuf;
import java.util.UUID;
/**
* Stops a sound on the client
* Stops a sound on the client.
* <p>
* Called when a speaker is broken.
*

View File

@@ -305,7 +305,7 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
return wrappers == null ? null : wrappers.get(remoteName);
}
private static class RemotePeripheralWrapper implements IComputerAccess, GuardedLuaContext.Guard {
private static final class RemotePeripheralWrapper implements IComputerAccess, GuardedLuaContext.Guard {
private final WiredModemElement element;
private final IPeripheral peripheral;
private final IComputerAccess computer;
@@ -331,13 +331,13 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
methodMap = methods;
}
public void attach() {
private void attach() {
attached = true;
peripheral.attach(this);
computer.queueEvent("peripheral", getAttachmentName());
}
public void detach() {
private void detach() {
peripheral.detach(this);
computer.queueEvent("peripheral_detach", getAttachmentName());
attached = false;
@@ -352,19 +352,19 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements Wi
}
}
public String getType() {
private String getType() {
return type;
}
public Set<String> getAdditionalTypes() {
private Set<String> getAdditionalTypes() {
return additionalTypes;
}
public Collection<String> getMethodNames() {
private Collection<String> getMethodNames() {
return methodMap.keySet();
}
public MethodResult callMethod(ILuaContext context, String methodName, IArguments arguments) throws LuaException {
private MethodResult callMethod(ILuaContext context, String methodName, IArguments arguments) throws LuaException {
var method = methodMap.get(methodName);
if (method == null) throw new LuaException("No such method " + methodName);

View File

@@ -142,7 +142,7 @@ public class NetworkBenchmark {
return networks;
}
private static class Grid<T> {
private static final class Grid<T> {
private final int size;
private final T[] box;
@@ -152,7 +152,7 @@ public class NetworkBenchmark {
this.box = (T[]) new Object[size * size * size];
}
public T get(BlockPos pos) {
private T get(BlockPos pos) {
int x = pos.getX(), y = pos.getY(), z = pos.getZ();
return x >= 0 && x < size && y >= 0 && y < size && z >= 0 && z < size
@@ -160,7 +160,7 @@ public class NetworkBenchmark {
: null;
}
public void forEach(BiConsumer<T, BlockPos> transform) {
private void forEach(BiConsumer<T, BlockPos> transform) {
for (var x = 0; x < size; x++) {
for (var y = 0; y < size; y++) {
for (var z = 0; z < size; z++) {
@@ -170,7 +170,7 @@ public class NetworkBenchmark {
}
}
public void map(BiFunction<T, BlockPos, T> transform) {
private void map(BiFunction<T, BlockPos, T> transform) {
for (var x = 0; x < size; x++) {
for (var y = 0; y < size; y++) {
for (var z = 0; z < size; z++) {

View File

@@ -2,6 +2,7 @@
//
// SPDX-License-Identifier: MPL-2.0
import cc.tweaked.gradle.CCTweakedPlugin
import cc.tweaked.gradle.getAbsolutePath
plugins {
@@ -39,6 +40,8 @@ dependencies {
testRuntimeOnly(libs.slf4j.simple)
}
kotlin.compilerOptions.jvmTarget = CCTweakedPlugin.KOTLIN_TARGET
tasks.processResources {
inputs.property("gitHash", cct.gitHash)

View File

@@ -27,7 +27,7 @@ import java.util.*;
* @hidden
*/
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener {
private class PeripheralWrapper extends ComputerAccess implements GuardedLuaContext.Guard {
private final class PeripheralWrapper extends ComputerAccess implements GuardedLuaContext.Guard {
private final String side;
private final IPeripheral peripheral;
@@ -49,32 +49,32 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
methodMap = peripheralMethods.getSelfMethods(peripheral);
}
public IPeripheral getPeripheral() {
private IPeripheral getPeripheral() {
return peripheral;
}
public String getType() {
private String getType() {
return type;
}
public Set<String> getAdditionalTypes() {
private Set<String> getAdditionalTypes() {
return additionalTypes;
}
public Collection<String> getMethods() {
private Collection<String> getMethods() {
return methodMap.keySet();
}
public synchronized boolean isAttached() {
private synchronized boolean isAttached() {
return attached;
}
public synchronized void attach() {
private synchronized void attach() {
attached = true;
peripheral.attach(this);
}
public void detach() {
private void detach() {
// Call detach
peripheral.detach(this);
@@ -86,7 +86,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
attached = false;
}
public MethodResult call(ILuaContext context, String methodName, IArguments arguments) throws LuaException {
private MethodResult call(ILuaContext context, String methodName, IArguments arguments) throws LuaException {
PeripheralMethod method;
synchronized (this) {
method = methodMap.get(methodName);

View File

@@ -11,7 +11,7 @@ import java.net.URI;
import java.util.concurrent.Future;
/**
* Checks a URL using {@link NetworkUtils#getAddress(String, int, boolean)}}
* Checks a URL using {@link NetworkUtils#getAddress(String, int, boolean)}.
* <p>
* This requires a DNS lookup, and so needs to occur off-thread.
*/

View File

@@ -61,7 +61,7 @@ public abstract class Resource<T extends Resource<T>> implements Closeable {
}
/**
* Clean up any pending resources
* Clean up any pending resources.
* <p>
* Note, this may be called multiple times, and so should be thread-safe and
* avoid any major side effects.

View File

@@ -47,7 +47,7 @@ final class Generator<T> {
private static final MethodHandle ARG_GET_OBJECT, ARG_GET_ENUM, ARG_OPT_ENUM, ARG_GET_STRING_COERCED, ARG_GET_BYTES_COERCED;
private record ArgMethods(MethodHandle get, MethodHandle opt) {
public static ArgMethods of(Class<?> type, String name) throws ReflectiveOperationException {
private static ArgMethods of(Class<?> type, String name) throws ReflectiveOperationException {
return new ArgMethods(
LOOKUP.findVirtual(IArguments.class, "get" + name, MethodType.methodType(type, int.class)),
LOOKUP.findVirtual(IArguments.class, "opt" + name, MethodType.methodType(Optional.class, int.class))

View File

@@ -740,7 +740,7 @@ public final class ComputerThread implements ComputerScheduler {
}
private final class ExecutorImpl implements Executor {
public static final AtomicReferenceFieldUpdater<ExecutorImpl, ExecutorState> STATE = AtomicReferenceFieldUpdater.newUpdater(
private static final AtomicReferenceFieldUpdater<ExecutorImpl, ExecutorState> STATE = AtomicReferenceFieldUpdater.newUpdater(
ExecutorImpl.class, ExecutorState.class, "$state"
);

View File

@@ -8,6 +8,7 @@ import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import java.lang.reflect.Method;
import java.util.List;
/**
* A {@link DisplayNameGenerator} which replaces underscores with spaces. This is equivalent to
@@ -17,7 +18,7 @@ import java.lang.reflect.Method;
*/
public class ReplaceUnderscoresDisplayNameGenerator extends DisplayNameGenerator.ReplaceUnderscores {
@Override
public String generateDisplayNameForMethod(Class<?> testClass, Method testMethod) {
public String generateDisplayNameForMethod(List<Class<?>> enclosingInstanceTypes, Class<?> testClass, Method testMethod) {
return testMethod.getName().replace('_', ' ');
}
}

View File

@@ -67,7 +67,6 @@ configurations {
val localImplementation by registering {
isCanBeResolved = false
isCanBeConsumed = false
isVisible = false
}
compileClasspath { extendsFrom(localImplementation.get()) }
runtimeClasspath { extendsFrom(localImplementation.get()) }
@@ -118,7 +117,6 @@ dependencies {
loom {
accessWidenerPath = project(":common").file("src/main/resources/computercraft.accesswidener")
mixin.defaultRefmapName = "computercraft.refmap.json"
mods {
register("computercraft") {

View File

@@ -35,11 +35,11 @@ public class FabricDataProviders implements DataGeneratorEntrypoint {
}
private record PlatformGeneratorsImpl(FabricDataGenerator.Pack generator) implements DataProviders.GeneratorSink {
public <T extends DataProvider> T addWithFabricOutput(FabricDataGenerator.Pack.Factory<T> factory) {
private <T extends DataProvider> T addWithFabricOutput(FabricDataGenerator.Pack.Factory<T> factory) {
return generator.addProvider((FabricDataOutput p) -> new PrettyDataProvider<>(factory.create(p))).provider();
}
public <T extends DataProvider> T addWithRegistries(FabricDataGenerator.Pack.RegistryDependentFactory<T> factory) {
private <T extends DataProvider> T addWithRegistries(FabricDataGenerator.Pack.RegistryDependentFactory<T> factory) {
return generator.addProvider((r, p) -> new PrettyDataProvider<>(factory.create(r, p))).provider();
}

View File

@@ -142,7 +142,6 @@ configurations {
val localImplementation by registering {
isCanBeResolved = false
isCanBeConsumed = false
isVisible = false
}
compileClasspath { extendsFrom(localImplementation.get()) }
runtimeClasspath { extendsFrom(localImplementation.get()) }

View File

@@ -2,6 +2,8 @@
//
// SPDX-License-Identifier: MPL-2.0
import cc.tweaked.gradle.CCTweakedPlugin
plugins {
kotlin("jvm")
id("cc-tweaked.java-convention")
@@ -28,6 +30,8 @@ dependencies {
testRuntimeOnly(libs.bundles.testRuntime)
}
kotlin.compilerOptions.jvmTarget = CCTweakedPlugin.KOTLIN_TARGET
tasks.test {
jvmArgs(
"--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",

View File

@@ -1,138 +0,0 @@
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package cc.tweaked.javadoc
import com.sun.source.doctree.DocTree
import com.sun.source.doctree.TextTree
import com.sun.source.doctree.UnknownInlineTagTree
import com.sun.source.util.DocTreePath
import jdk.javadoc.doclet.*
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
import java.util.regex.Pattern
import javax.lang.model.element.Element
import javax.tools.Diagnostic
import kotlin.io.path.extension
/**
* A primitive reimplementation of Java 21's `@snippet` tag. This only supports including external snippets via `file`
* and `class`, and not the inline body.
*/
class SnippetTaglet : Taglet {
override fun getName(): String = "snippet"
override fun isInlineTag(): Boolean = true
override fun getAllowedLocations(): Set<Taglet.Location> = locations
private lateinit var env: DocletEnvironment
private lateinit var reporter: Reporter
private lateinit var snippetPath: List<File>
override fun init(env: DocletEnvironment, doclet: Doclet) {
super.init(env, doclet)
this.env = env
reporter = (doclet as StandardDoclet).reporter
this.snippetPath =
System.getProperty("cc.snippet-path")?.split(File.pathSeparatorChar)?.map { File(it) } ?: emptyList()
}
/** Parse our attributes into a key/value map */
private fun parseAttributes(contents: String): Map<String, String> {
val attributes = mutableMapOf<String, String>()
val attributeMatcher = attribute.matcher(contents)
var lastIndex = 0
while (attributeMatcher.find()) {
val key = attributeMatcher.group(1)
val value = attributeMatcher.group(2)
if (attributes.contains(key)) throw SnippetException("Duplicate attribute '$key'")
attributes[key] = value
lastIndex = attributeMatcher.end()
}
while (lastIndex < contents.length) {
val c = contents[lastIndex]
if (c != ' ') throw SnippetException("Unexpected '$c'")
}
return attributes
}
/** Locate our snippet file within the [snippetPath] */
private fun findSnippetFile(fileName: String): Path = snippetPath.firstNotNullOfOrNull {
val found = it.resolve(fileName)
if (found.exists()) found.toPath() else null
} ?: throw SnippetException("Cannot find file '$fileName'")
private fun processInlineTag(tag: UnknownInlineTagTree): String {
val tagContent = tag.content
if (tagContent.size != 1 || tagContent[0].kind != DocTree.Kind.TEXT) throw SnippetException("Expected a single text node")
val attributes = parseAttributes((tagContent[0] as TextTree).body)
val hasFile = attributes.contains("file")
val hasClass = attributes.contains("class")
if (hasFile && hasClass) throw SnippetException("Cannot specify file and class")
val file = when {
hasFile -> findSnippetFile(attributes["file"]!!)
hasClass -> findSnippetFile(attributes["class"]!!.replace('.', '/') + ".java")
else -> throw SnippetException("Snippet has no contents (must have file or class)")
}
// And generate our snippet
var snippetContents = Files.readString(file)
val region = attributes["region"]
if (region != null) {
val matcher =
Pattern.compile("// @start region=" + Pattern.quote(region) + "\n(.*)\\s*// @end region=" + Pattern.quote(region), Pattern.DOTALL)
.matcher(snippetContents)
if (!matcher.find()) throw SnippetException("Cannot find region '$region'")
snippetContents = matcher.group(1).trimIndent()
}
return makeSnippet(file.extension, snippetContents)
}
override fun toString(tags: List<DocTree>, element: Element): String {
if (tags.size != 1) throw IllegalArgumentException("Tags should be length 1")
val tag = tags[0] as UnknownInlineTagTree
try {
return processInlineTag(tag)
} catch (e: SnippetException) {
reporter.print(
Diagnostic.Kind.ERROR,
DocTreePath.getPath(env.docTrees.getPath(element), env.docTrees.getDocCommentTree(element), tag),
"Invalid @snippet. ${e.message}",
)
return "@snippet"
}
}
companion object {
private val locations = EnumSet.allOf(Taglet.Location::class.java)
private val attribute = Pattern.compile(" *([a-z]+) *= *([^ ]+)")
/** Escape our snippet HTML and wrap it into a code block */
private fun makeSnippet(extension: String, contents: String): String {
val out = StringBuilder(contents.length + 60)
out.append("<pre class=\"language language-$extension\"><code>")
for (element in contents) {
when (element) {
'<' -> out.append("&lt;")
'>' -> out.append("&gt;")
'&' -> out.append("&amp;")
else -> out.append(element)
}
}
out.append("</code></pre>")
return out.toString()
}
}
}
private class SnippetException(message: String) : Exception(message)

View File

@@ -19,6 +19,7 @@ import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.core.util.Colour;
import org.apache.commons.cli.*;
import org.apache.commons.cli.help.HelpFormatter;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
@@ -31,9 +32,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -70,10 +70,10 @@ public class Main {
}
private record TermSize(int width, int height) {
public static final TermSize DEFAULT = new TermSize(51, 19);
public static final Pattern PATTERN = Pattern.compile("^(\\d+)x(\\d+)$");
private static final TermSize DEFAULT = new TermSize(51, 19);
private static final Pattern PATTERN = Pattern.compile("^(\\d+)x(\\d+)$");
public static TermSize parse(String value) throws ParseException {
private static TermSize parse(String value) throws ParseException {
var matcher = TermSize.PATTERN.matcher(value);
if (!matcher.matches()) throw new ParseException("'" + value + "' is not a valid terminal size.");
@@ -82,9 +82,9 @@ public class Main {
}
private record MountPaths(Path src, String dest) {
public static final Pattern PATTERN = Pattern.compile("^([^:]+):([^:]+)$");
private static final Pattern PATTERN = Pattern.compile("^([^:]+):([^:]+)$");
public static MountPaths parse(String value) throws ParseException {
private static MountPaths parse(String value) throws ParseException {
var matcher = MountPaths.PATTERN.matcher(value);
if (!matcher.matches()) throw new ParseException("'" + value + "' is not a mount spec.");
@@ -115,26 +115,26 @@ public class Main {
Option resourceOpt, computerOpt, termSizeOpt, allowLocalDomainsOpt, helpOpt, mountOpt, mountRoOpt;
options.addOption(resourceOpt = Option.builder("r").argName("PATH").longOpt("resources").hasArg()
.desc("The path to the resources directory")
.build());
.get());
options.addOption(computerOpt = Option.builder("c").argName("PATH").longOpt("computer").hasArg()
.desc("The root directory of the computer. Defaults to a temporary directory.")
.build());
.get());
options.addOption(termSizeOpt = Option.builder("t").argName("WIDTHxHEIGHT").longOpt("term-size").hasArg()
.desc("The size of the terminal, defaults to 51x19.")
.build());
.get());
options.addOption(allowLocalDomainsOpt = Option.builder("L").longOpt("allow-local-domains")
.desc("Allow accessing local domains with the HTTP API.")
.build());
.get());
options.addOption(mountOpt = Option.builder().longOpt("mount").hasArg().argName("SRC:DEST")
.desc("Mount a folder SRC at directory DEST on the computer.")
.build());
.get());
options.addOption(mountRoOpt = Option.builder().longOpt("mount-ro").hasArg().argName("SRC:DEST")
.desc("Mount a read-only folder SRC at directory DEST on the computer.")
.build());
.get());
options.addOption(helpOpt = Option.builder("h").longOpt("help")
.desc("Print help message")
.build());
.get());
Path resourcesDirectory;
Path computerDirectory;
@@ -144,7 +144,11 @@ public class Main {
try {
var cli = new DefaultParser().parse(options, args);
if (cli.hasOption(helpOpt)) {
new HelpFormatter().printHelp("standalone.jar", options, true);
try {
HelpFormatter.builder().get().printHelp("standalone.jar", "", options, "", true);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return;
}
if (!cli.hasOption(resourceOpt)) throw new ParseException("--resources directory is required");
@@ -157,10 +161,7 @@ public class Main {
readOnlyMounts = getParsedOptionValues(cli, mountRoOpt, MountPaths::parse);
} catch (ParseException e) {
System.err.println(e.getLocalizedMessage());
var writer = new PrintWriter(System.err, false, StandardCharsets.UTF_8);
new HelpFormatter().printUsage(writer, HelpFormatter.DEFAULT_WIDTH, "standalone.jar", options);
writer.flush();
System.err.println(HelpFormatter.builder().get().toSyntaxOptions(options));
System.exit(1);
return;

View File

@@ -8,6 +8,7 @@ import org.jspecify.annotations.Nullable;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.ClassRemapper;
import org.objectweb.asm.commons.Remapper;
@@ -38,7 +39,7 @@ public class TransformingClassLoader extends ClassLoader {
private final Map<String, Path> remappedResources = new HashMap<>();
private final List<BiFunction<String, ClassVisitor, ClassVisitor>> transformers = new ArrayList<>();
private final Remapper remapper = new Remapper() {
private final Remapper remapper = new Remapper(Opcodes.ASM9) {
@Override
public String map(String internalName) {
return remappedClasses.getOrDefault(internalName, internalName);

View File

@@ -187,9 +187,9 @@ class EmulatedComputer implements ComputerEnvironment, ComputerHandle {
public void addFile(String path, JSObject contents) {
byte[] bytes;
if (JavascriptConv.isArrayBuffer(contents)) {
bytes = bytesOfBuffer(contents.cast());
bytes = bytesOfBuffer((ArrayBuffer) contents);
} else {
JSString string = contents.cast();
var string = (JSString) contents;
bytes = string.stringValue().getBytes(StandardCharsets.UTF_8);
}

View File

@@ -117,7 +117,7 @@ public class THttpRequest extends Resource<THttpRequest> {
return;
}
ArrayBuffer buffer = request.getResponse().cast();
var buffer = (ArrayBuffer) request.getResponse();
SeekableByteChannel contents = new ArrayByteChannel(JavascriptConv.asByteArray(buffer));
var reader = new ReadHandle(contents, binary);

View File

@@ -20,6 +20,7 @@ pluginManagement {
content {
includeGroup("fabric-loom")
includeGroup("net.fabricmc")
includeGroup("net.fabricmc.unpick")
}
}