1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2024-12-14 04:00:30 +00:00

Move the core API into a separate module

It should be possible to consume the ComputerCraft's core (i.e.
non-Minecraft code) in other projects, such as emulators.  While this
has been possible for years, it's somewhat tricky from a maintenance
perspective - it's very easy to accidentally add an MC dependency
somewhere!

By publishing a separate "core" jar, we can better distinguish the
boundaries between our Lua runtime and the Minecraft-specific code.

Ideally we could have one core project (rather than separate core and
core-api modules), and publish a separate "api" jar, like we do for the
main mod. However, this isn't really possible to express using Maven
dependencies, and so we must resort to this system.

Of course, this is kinda what the Java module system is meant to solve,
but unfortunately getting that working with Minecraft is infeasible.
This commit is contained in:
Jonathan Coates 2022-11-04 21:41:59 +00:00
parent e4e528e5bf
commit a17b001950
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
47 changed files with 307 additions and 127 deletions

3
.gitignore vendored
View File

@ -2,11 +2,12 @@
/classes /classes
/logs /logs
/build /build
/projects/*/build
/buildSrc/build /buildSrc/build
/out /out
/doc/out/ /doc/out/
/node_modules /node_modules
/.jqwik-database .jqwik-database
# Runtime directories # Runtime directories
/run /run

View File

@ -9,7 +9,6 @@ plugins {
alias(libs.plugins.librarian) alias(libs.plugins.librarian)
alias(libs.plugins.shadow) alias(libs.plugins.shadow)
// Publishing // Publishing
`maven-publish`
alias(libs.plugins.curseForgeGradle) alias(libs.plugins.curseForgeGradle)
alias(libs.plugins.githubRelease) alias(libs.plugins.githubRelease)
alias(libs.plugins.minotaur) alias(libs.plugins.minotaur)
@ -19,6 +18,7 @@ plugins {
id("cc-tweaked.illuaminate") id("cc-tweaked.illuaminate")
id("cc-tweaked.node") id("cc-tweaked.node")
id("cc-tweaked.gametest") id("cc-tweaked.gametest")
id("cc-tweaked.publishing")
id("cc-tweaked") id("cc-tweaked")
} }
@ -26,9 +26,10 @@ val isStable = true
val modVersion: String by extra val modVersion: String by extra
val mcVersion: String by extra val mcVersion: String by extra
group = "org.squiddev" val allProjects = listOf(":core-api").map { evaluationDependsOn(it) }
version = modVersion cct {
base.archivesName.set("cc-tweaked-$mcVersion") allProjects.forEach { externalSources(it) }
}
java.registerFeature("extraMods") { usingSourceSet(sourceSets.main.get()) } java.registerFeature("extraMods") { usingSourceSet(sourceSets.main.get()) }
@ -52,7 +53,11 @@ minecraft {
forceExit = false forceExit = false
mods.register("computercraft") { source(sourceSets.main.get()) } mods.register("computercraft") {
cct.sourceDirectories.get().forEach {
if (it.classes) sources(it.sourceSet)
}
}
} }
val client by registering { val client by registering {
@ -149,6 +154,7 @@ dependencies {
"extraModsRuntimeOnly"(fg.deobf("mezz.jei:jei-1.19.2-forge:11.3.0.262")) "extraModsRuntimeOnly"(fg.deobf("mezz.jei:jei-1.19.2-forge:11.3.0.262"))
"extraModsCompileOnly"(fg.deobf("maven.modrinth:oculus:1.2.5")) "extraModsCompileOnly"(fg.deobf("maven.modrinth:oculus:1.2.5"))
implementation(project(":core-api"))
"shade"(libs.cobalt) "shade"(libs.cobalt)
"shade"("io.netty:netty-codec-http:4.1.76.Final") "shade"("io.netty:netty-codec-http:4.1.76.Final")
@ -170,7 +176,6 @@ illuaminate {
tasks.javadoc { tasks.javadoc {
include("dan200/computercraft/api/**/*.java") include("dan200/computercraft/api/**/*.java")
(options as StandardJavadocDocletOptions).links("https://docs.oracle.com/en/java/javase/17/docs/api/")
} }
val apiJar by tasks.registering(Jar::class) { val apiJar by tasks.registering(Jar::class) {
@ -216,21 +221,10 @@ tasks.processResources {
} }
tasks.jar { tasks.jar {
isReproducibleFileOrder = true
isPreserveFileTimestamps = false
finalizedBy("reobfJar") finalizedBy("reobfJar")
archiveClassifier.set("slim") archiveClassifier.set("slim")
manifest { from(allProjects.map { zipTree(it.tasks.jar.get().archiveFile) })
attributes(
"Specification-Title" to "computercraft",
"Specification-Vendor" to "SquidDev",
"Specification-Version" to "1",
"Implementation-Title" to "cctweaked",
"Implementation-Version" to modVersion,
"Implementation-Vendor" to "SquidDev",
)
}
} }
tasks.shadowJar { tasks.shadowJar {
@ -374,7 +368,8 @@ val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
val mainFile = upload("282001", tasks.shadowJar.get().archiveFile) val mainFile = upload("282001", tasks.shadowJar.get().archiveFile)
dependsOn(tasks.shadowJar) // Ughr. dependsOn(tasks.shadowJar) // Ughr.
mainFile.changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)." mainFile.changelog =
"Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
mainFile.changelogType = "markdown" mainFile.changelogType = "markdown"
mainFile.releaseType = if (isStable) "release" else "alpha" mainFile.releaseType = if (isStable) "release" else "alpha"
mainFile.gameVersions.add(mcVersion) mainFile.gameVersions.add(mcVersion)
@ -420,41 +415,9 @@ tasks.publish { dependsOn(tasks.githubRelease) }
publishing { publishing {
publications { publications {
register<MavenPublication>("maven") { named("maven", MavenPublication::class) {
artifactId = base.archivesName.get()
from(components["java"])
artifact(apiJar) artifact(apiJar)
fg.component(this) fg.component(this)
pom {
name.set("CC: Tweaked")
description.set("CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.")
url.set("https://github.com/cc-tweaked/CC-Tweaked")
scm {
url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
}
issueManagement {
system.set("github")
url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
}
licenses {
license {
name.set("ComputerCraft Public License, Version 1.0")
url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
}
}
}
}
}
repositories {
maven("https://squiddev.cc/maven") {
name = "SquidDev"
credentials(PasswordCredentials::class)
} }
} }
} }

View File

@ -11,6 +11,17 @@ plugins {
id("com.diffplug.spotless") id("com.diffplug.spotless")
} }
val modVersion: String by extra
val mcVersion: String by extra
group = "cc.tweaked"
version = modVersion
base.archivesName.convention(
// TODO: Remove this (and the one below) once we've no longer got a root project!
if (project.path == rootProject.path) "cc-tweaked-$mcVersion" else "cc-tweaked-$mcVersion-${project.name}",
)
java { java {
toolchain { toolchain {
languageVersion.set(CCTweakedPlugin.JAVA_VERSION) languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
@ -53,6 +64,31 @@ tasks.withType(JavaCompile::class.java).configureEach {
options.encoding = "UTF-8" options.encoding = "UTF-8"
} }
tasks.jar {
isReproducibleFileOrder = true
isPreserveFileTimestamps = false
archiveClassifier.set("slim")
manifest {
attributes(
"Specification-Title" to "computercraft",
"Specification-Vendor" to "SquidDev",
"Specification-Version" to "1",
"Implementation-Title" to (if (project.path == rootProject.path) "cctweaked" else "cctweaked-${project.name}"),
"Implementation-Version" to modVersion,
"Implementation-Vendor" to "SquidDev",
)
}
}
tasks.javadoc {
options {
val stdOptions = this as StandardJavadocDocletOptions
stdOptions.addBooleanOption("Xdoclint:all,-missing", true)
stdOptions.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
}
}
tasks.test { tasks.test {
finalizedBy("jacocoTestReport") finalizedBy("jacocoTestReport")
@ -78,8 +114,8 @@ spotless {
} }
val licenser = LicenseHeader.create( val licenser = LicenseHeader.create(
api = file("config/license/api.txt"), api = rootProject.file("config/license/api.txt"),
main = file("config/license/main.txt"), main = rootProject.file("config/license/main.txt"),
) )
java { java {

View File

@ -0,0 +1,45 @@
import org.gradle.kotlin.dsl.`maven-publish`
plugins {
`java-library`
`maven-publish`
}
publishing {
publications {
register<MavenPublication>("maven") {
artifactId = base.archivesName.get()
from(components["java"])
pom {
name.set("CC: Tweaked")
description.set("CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.")
url.set("https://github.com/cc-tweaked/CC-Tweaked")
scm {
url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
}
issueManagement {
system.set("github")
url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
}
licenses {
license {
name.set("ComputerCraft Public License, Version 1.0")
url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
}
}
}
}
}
repositories {
maven("https://squiddev.cc/maven") {
name = "SquidDev"
credentials(PasswordCredentials::class)
}
}
}

View File

@ -5,6 +5,7 @@ import org.gradle.api.Project
import org.gradle.api.attributes.TestSuiteType import org.gradle.api.attributes.TestSuiteType
import org.gradle.api.file.FileSystemOperations import org.gradle.api.file.FileSystemOperations
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.provider.SetProperty
import org.gradle.api.reporting.ReportingExtension import org.gradle.api.reporting.ReportingExtension
import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.JavaExec
import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.SourceSetContainer
@ -31,7 +32,8 @@ abstract class CCTweakedExtension(
/** Get the current git branch. */ /** Get the current git branch. */
val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") { val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") {
ProcessHelpers.captureOut("git", "-C", project.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD").trim() ProcessHelpers.captureOut("git", "-C", project.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD")
.trim()
} }
/** Get a list of all contributors to the project. */ /** Get a list of all contributors to the project. */
@ -64,6 +66,30 @@ abstract class CCTweakedExtension(
contributors.sortedWith(String.CASE_INSENSITIVE_ORDER) contributors.sortedWith(String.CASE_INSENSITIVE_ORDER)
} }
/**
* References to other sources
*/
val sourceDirectories: SetProperty<SourceSetReference> =
project.objects.setProperty(SourceSetReference::class.java)
/** All source sets referenced by this project. */
val sourceSets = sourceDirectories.map { x -> x.map { it.sourceSet } }
init {
sourceDirectories.finalizeValueOnRead()
}
/**
* Mark this project as consuming another project. Its [sourceDirectories] are added, ensuring tasks are set up
* correctly.
*/
fun externalSources(project: Project) {
val otherCct = project.extensions.getByType(CCTweakedExtension::class.java)
for (sourceSet in otherCct.sourceSets.get()) {
sourceDirectories.add(SourceSetReference.external(sourceSet))
}
}
fun jacoco(task: NamedDomainObjectProvider<JavaExec>) { fun jacoco(task: NamedDomainObjectProvider<JavaExec>) {
val classDump = project.buildDir.resolve("jacocoClassDump/${task.name}") val classDump = project.buildDir.resolve("jacocoClassDump/${task.name}")
val reportTaskName = "jacoco${task.name.capitalized()}Report" val reportTaskName = "jacoco${task.name.capitalized()}Report"

View File

@ -2,14 +2,28 @@ package cc.tweaked.gradle
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.testing.jacoco.tasks.JacocoReport
/** /**
* Configures projects to match a shared configuration. * Configures projects to match a shared configuration.
*/ */
class CCTweakedPlugin : Plugin<Project> { class CCTweakedPlugin : Plugin<Project> {
override fun apply(project: Project) { override fun apply(project: Project) {
project.extensions.create("cct", CCTweakedExtension::class.java) val sourceSets = project.extensions.getByType(SourceSetContainer::class.java)
val cct = project.extensions.create("cct", CCTweakedExtension::class.java)
cct.sourceDirectories.add(SourceSetReference.internal(sourceSets.getByName("main")))
project.afterEvaluate {
cct.sourceDirectories.disallowChanges()
}
// Set up jacoco to read from /all/ our source directories.
project.tasks.named("jacocoTestReport", JacocoReport::class.java) {
for (ref in cct.sourceSets.get()) sourceDirectories.from(ref.allSource.sourceDirectories)
}
} }
companion object { companion object {

View File

@ -0,0 +1,20 @@
package cc.tweaked.gradle
import org.gradle.api.tasks.SourceSet
data class SourceSetReference(
val sourceSet: SourceSet,
val classes: Boolean,
val external: Boolean,
) {
companion object {
/** A source set in the current project. */
fun internal(sourceSet: SourceSet) = SourceSetReference(sourceSet, classes = true, external = false)
/** A source set from another project. */
fun external(sourceSet: SourceSet) = SourceSetReference(sourceSet, classes = true, external = true)
/** A source set which is inlined into the current project. */
fun inline(sourceSet: SourceSet) = SourceSetReference(sourceSet, classes = false, external = false)
}
}

View File

@ -6,11 +6,20 @@ forge = "43.1.1"
parchment = "2022.10.16" parchment = "2022.10.16"
parchmentMc = "1.19.2" parchmentMc = "1.19.2"
asm = "9.3"
autoService = "1.0.1" autoService = "1.0.1"
checkerFramework = "3.12.0"
cobalt = { strictly = "[0.5.8,0.6.0)", prefer = "0.5.8" } cobalt = { strictly = "[0.5.8,0.6.0)", prefer = "0.5.8" }
fastutil = "8.5.6"
guava = "31.0.1-jre"
jetbrainsAnnotations = "23.0.0" jetbrainsAnnotations = "23.0.0"
jsr305 = "3.0.2"
kotlin = "1.7.10" kotlin = "1.7.10"
kotlin-coroutines = "1.6.0" kotlin-coroutines = "1.6.0"
logback = "1.2.11"
netty = { strictly = "[4.1.77.Final,5.0)", prefer = "4.1.77.Final" }
nightConfig = "3.6.5"
slf4j = "1.7.36"
# Testing # Testing
hamcrest = "2.2" hamcrest = "2.2"
@ -32,11 +41,18 @@ spotless = "6.8.0"
taskTree = "2.1.0" taskTree = "2.1.0"
[libraries] [libraries]
asm = { module = "org.ow2.asm:asm", version.ref = "asm" }
autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" } autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" }
checkerFramework = { module = "org.checkerframework:checker-qual", version.ref = "checkerFramework" }
cobalt = { module = "org.squiddev:Cobalt", version.ref = "cobalt" } cobalt = { module = "org.squiddev:Cobalt", version.ref = "cobalt" }
fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
guava = { module = "com.google.guava:guava", version.ref = "guava" }
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" } jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" }
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" } kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib-jdk8", version.ref = "kotlin" }
netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
# Testing # Testing
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" } hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }

View File

@ -0,0 +1,27 @@
plugins {
id("cc-tweaked.java-convention")
id("cc-tweaked.publishing")
id("cc-tweaked")
}
java {
withJavadocJar()
}
// Due to the slightly circular nature of our API, add the main API jars to the javadoc classpath.
val docApi by configurations.registering {
isTransitive = false
}
dependencies {
compileOnly(project(":mc-stubs"))
compileOnlyApi(libs.jsr305)
compileOnlyApi(libs.checkerFramework)
"docApi"(project(":"))
}
tasks.javadoc {
// Depend on
classpath += docApi
}

View File

@ -8,6 +8,7 @@ package dan200.computercraft.api.filesystem;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException; import java.io.IOException;
import java.io.Serial;
import java.util.Objects; import java.util.Objects;
/** /**
@ -16,6 +17,7 @@ import java.util.Objects;
* This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure. * This may be thrown from a {@link IMount} or {@link IWritableMount} to give more information about a failure.
*/ */
public class FileOperationException extends IOException { public class FileOperationException extends IOException {
@Serial
private static final long serialVersionUID = -8809108200853029849L; private static final long serialVersionUID = -8809108200853029849L;
private final String filename; private final String filename;

View File

@ -5,9 +5,7 @@
*/ */
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.level.Level;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
@ -19,12 +17,9 @@ import java.util.List;
* Represents a read only part of a virtual filesystem that can be mounted onto a computer using * Represents a read only part of a virtual filesystem that can be mounted onto a computer using
* {@link IComputerAccess#mount(String, IMount)}. * {@link IComputerAccess#mount(String, IMount)}.
* <p> * <p>
* Ready made implementations of this interface can be created using * Typically you will not need to implement this interface yourself, and can use the factory methods from the
* {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)} or * {@linkplain dan200.computercraft.api.ComputerCraftAPI the main ComputerCraft API}.
* {@link ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves!
* *
* @see ComputerCraftAPI#createSaveDirMount(Level, String, long)
* @see ComputerCraftAPI#createResourceMount(String, String)
* @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mount(String, IMount)
* @see IWritableMount * @see IWritableMount
*/ */

View File

@ -5,9 +5,7 @@
*/ */
package dan200.computercraft.api.filesystem; package dan200.computercraft.api.filesystem;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IComputerAccess;
import net.minecraft.world.level.Level;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
@ -19,10 +17,9 @@ import java.util.OptionalLong;
* Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)}
* or {@link IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to. * or {@link IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to.
* <p> * <p>
* Ready made implementations of this interface can be created using * Typically you will not need to implement this interface yourself, and can use the factory methods from the
* {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)}, or you're free to implement it yourselves! * {@linkplain dan200.computercraft.api.ComputerCraftAPI the main ComputerCraft API}.
* *
* @see ComputerCraftAPI#createSaveDirMount(Level, String, long)
* @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mount(String, IMount)
* @see IComputerAccess#mountWritable(String, IWritableMount) * @see IComputerAccess#mountWritable(String, IWritableMount)
* @see IMount * @see IMount

View File

@ -5,31 +5,26 @@
*/ */
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.api.peripheral.GenericPeripheral;
import dan200.computercraft.api.ForgeComputerCraftAPI;
import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;
import dan200.computercraft.core.asm.LuaMethod;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
/** /**
* A generic source of {@link LuaMethod} functions. * A generic source of {@link LuaFunction} functions.
* <p> * <p>
* Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but * Unlike normal objects ({@link IDynamicLuaObject} or {@link IPeripheral}), methods do not target this object but
* instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject * instead are defined as {@code static} and accept their target as the first parameter. This allows you to inject
* methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a * methods onto objects you do not own, as well as declaring methods for a specific "trait" (for instance, a Forge
* {@link Capability}). * capability or Fabric block lookup interface).
* <p> * <p>
* Currently the "generic peripheral" system is incompatible with normal peripherals. Normal {@link IPeripheralProvider} * Currently the "generic peripheral" system is incompatible with normal peripherals. Peripherals explicitly provided
* or {@link IPeripheral} implementations take priority. Tile entities which use this system are given a peripheral name * by capabilities/the block lookup API take priority. Block entities which use this system are given a peripheral name
* determined by their id, rather than any peripheral provider. This will hopefully change in the future, once a suitable * determined by their id, rather than any peripheral provider, though additional types may be provided by overriding
* design has been established. * {@link GenericPeripheral#getType()}.
* <p> * <p>
* For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@link IItemHandler}s: * For example, the main CC: Tweaked mod defines a generic source for inventories, which works on {@code IItemHandler}s:
* *
* <pre>{@code * <pre>{@code
* public class InventoryMethods implements GenericSource { * public class InventoryMethods implements GenericSource {
@ -42,9 +37,10 @@ import javax.annotation.Nonnull;
* } * }
* }</pre> * }</pre>
* *
* @see ComputerCraftAPI#registerGenericSource(GenericSource) * @see dan200.computercraft.api.ComputerCraftAPI#registerGenericSource(GenericSource)
* @see ForgeComputerCraftAPI#registerGenericCapability(Capability) New capabilities (those not built into Forge) must be * @see dan200.computercraft.api.ForgeComputerCraftAPI#registerGenericCapability New capabilities (those not
* explicitly given to the generic peripheral system, as there is no way to enumerate all capabilities. * built into Forge) must be explicitly given to the generic peripheral system, as there is no way to enumerate all
* capabilities.
*/ */
public interface GenericSource { public interface GenericSource {
/** /**

View File

@ -11,8 +11,6 @@ import java.nio.ByteBuffer;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
import static dan200.computercraft.api.lua.LuaValues.checkFinite;
/** /**
* The arguments passed to a function. * The arguments passed to a function.
*/ */
@ -102,7 +100,7 @@ public interface IArguments {
* @throws LuaException If the value is not finite. * @throws LuaException If the value is not finite.
*/ */
default double getFiniteDouble(int index) throws LuaException { default double getFiniteDouble(int index) throws LuaException {
return checkFinite(index, getDouble(index)); return LuaValues.checkFinite(index, getDouble(index));
} }
/** /**

View File

@ -5,8 +5,6 @@
*/ */
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import dan200.computercraft.api.ComputerCraftAPI;
/** /**
* Represents a Lua object which is stored as a global variable on computer startup. This must either provide * Represents a Lua object which is stored as a global variable on computer startup. This must either provide
* {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}. * {@link LuaFunction} annotated functions or implement {@link IDynamicLuaObject}.
@ -14,8 +12,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
* Before implementing this interface, consider alternative methods of providing methods. It is generally preferred * Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
* to use peripherals to provide functionality to users. * to use peripherals to provide functionality to users.
* *
* @see ILuaAPIFactory * @see ILuaAPIFactory For providing custom APIs to computers.
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
*/ */
public interface ILuaAPI { public interface ILuaAPI {
/** /**

View File

@ -5,8 +5,6 @@
*/ */
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import dan200.computercraft.api.ComputerCraftAPI;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -14,7 +12,7 @@ import javax.annotation.Nullable;
* Construct an {@link ILuaAPI} for a specific computer. * Construct an {@link ILuaAPI} for a specific computer.
* *
* @see ILuaAPI * @see ILuaAPI
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) * @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
*/ */
@FunctionalInterface @FunctionalInterface
public interface ILuaAPIFactory { public interface ILuaAPIFactory {

View File

@ -6,11 +6,13 @@
package dan200.computercraft.api.lua; package dan200.computercraft.api.lua;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.Serial;
/** /**
* An exception representing an error in Lua, like that raised by the {@code error()} function. * An exception representing an error in Lua, like that raised by the {@code error()} function.
*/ */
public class LuaException extends Exception { public class LuaException extends Exception {
@Serial
private static final long serialVersionUID = -6136063076818512651L; private static final long serialVersionUID = -6136063076818512651L;
private final boolean hasLevel; private final boolean hasLevel;
private final int level; private final int level;

View File

@ -11,6 +11,13 @@ import java.util.Map;
import static dan200.computercraft.api.lua.LuaValues.*; import static dan200.computercraft.api.lua.LuaValues.*;
/**
* A view of a Lua table, which may be able to access table elements in a more optimised manner than
* {@link IArguments#getTable(int)}.
*
* @param <K> The type of keys in a table, will typically be a wildcard.
* @param <V> The type of values in a table, will typically be a wildcard.
*/
public interface LuaTable<K, V> extends Map<K, V> { public interface LuaTable<K, V> extends Map<K, V> {
/** /**
* Compute the length of the array part of this table. * Compute the length of the array part of this table.
@ -77,7 +84,6 @@ public interface LuaTable<K, V> extends Map<K, V> {
return (int) getLong(key); return (int) getLong(key);
} }
@Nullable @Nullable
@Override @Override
default V put(K o, V o2) { default V put(K o, V o2) {

View File

@ -11,6 +11,9 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
/**
* An implementation of {@link LuaTable} based on a standard Java {@link Map}.
*/
public class ObjectLuaTable implements LuaTable<Object, Object> { public class ObjectLuaTable implements LuaTable<Object, Object> {
private final Map<Object, Object> map; private final Map<Object, Object> map;

View File

@ -6,8 +6,6 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.GenericSource;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.items.IItemHandler;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -15,14 +13,14 @@ import javax.annotation.Nonnull;
* A {@link GenericSource} which provides methods for a peripheral. * A {@link GenericSource} which provides methods for a peripheral.
* <p> * <p>
* Unlike a {@link GenericSource}, all methods <strong>should</strong> target the same type, for instance a * Unlike a {@link GenericSource}, all methods <strong>should</strong> target the same type, for instance a
* {@link BlockEntity} subclass or a capability interface. This is not currently enforced. * block entity subclass. This is not currently enforced.
*/ */
public interface GenericPeripheral extends GenericSource { public interface GenericPeripheral extends GenericSource {
/** /**
* Get the type of the exposed peripheral. * Get the type of the exposed peripheral.
* <p> * <p>
* Unlike normal {@link IPeripheral}s, {@link GenericPeripheral} do not have to have a type. By default, the * Unlike normal {@link IPeripheral}s, {@link GenericPeripheral} do not have to have a type. By default, the
* resulting peripheral uses the resource name of the wrapped {@link BlockEntity} (for instance {@code minecraft:chest}). * resulting peripheral uses the resource name of the wrapped block entity (for instance {@code minecraft:chest}).
* <p> * <p>
* However, in some cases it may be more appropriate to specify a more readable name. Overriding this method allows * However, in some cases it may be more appropriate to specify a more readable name. Overriding this method allows
* you to do so. * you to do so.
@ -31,7 +29,7 @@ public interface GenericPeripheral extends GenericSource {
* lexicographically smallest will be chosen. In order to avoid this conflict, this method should only be * lexicographically smallest will be chosen. In order to avoid this conflict, this method should only be
* implemented when your peripheral targets a single tile entity <strong>AND</strong> it's likely that you're the * implemented when your peripheral targets a single tile entity <strong>AND</strong> it's likely that you're the
* only mod to do so. Similarly this should <strong>NOT</strong> be implemented when your methods target a * only mod to do so. Similarly this should <strong>NOT</strong> be implemented when your methods target a
* capability or other interface (i.e. {@link IItemHandler}). * capability or other interface (such as Forge's {@code IItemHandler}).
* *
* @return The type of this peripheral or {@link PeripheralType#untyped()}. * @return The type of this peripheral or {@link PeripheralType#untyped()}.
* @see IPeripheral#getType() * @see IPeripheral#getType()

View File

@ -5,14 +5,12 @@
*/ */
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IMount;
import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.filesystem.IWritableMount;
import dan200.computercraft.api.lua.ILuaCallback; import dan200.computercraft.api.lua.ILuaCallback;
import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaContext;
import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.ILuaTask;
import dan200.computercraft.api.lua.MethodResult; import dan200.computercraft.api.lua.MethodResult;
import net.minecraft.world.level.Level;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -32,8 +30,6 @@ public interface IComputerAccess {
* @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws NotAttachedException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(Level, String, long)
* @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount, String) * @see #mount(String, IMount, String)
* @see #mountWritable(String, IWritableMount) * @see #mountWritable(String, IWritableMount)
* @see #unmount(String) * @see #unmount(String)
@ -53,8 +49,6 @@ public interface IComputerAccess {
* @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a * @return The location on the computer's file system where you the mount mounted, or {@code null} if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws NotAttachedException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(Level, String, long)
* @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount) * @see #mount(String, IMount)
* @see #mountWritable(String, IWritableMount) * @see #mountWritable(String, IWritableMount)
* @see #unmount(String) * @see #unmount(String)
@ -71,8 +65,6 @@ public interface IComputerAccess {
* @return The location on the computer's file system where you the mount mounted, or null if there was already a * @return The location on the computer's file system where you the mount mounted, or null if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws NotAttachedException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(Level, String, long)
* @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount) * @see #mount(String, IMount)
* @see #unmount(String) * @see #unmount(String)
* @see IMount * @see IMount
@ -91,8 +83,6 @@ public interface IComputerAccess {
* @return The location on the computer's file system where you the mount mounted, or null if there was already a * @return The location on the computer's file system where you the mount mounted, or null if there was already a
* file in the desired location. Store this value if you wish to unmount the mount later. * file in the desired location. Store this value if you wish to unmount the mount later.
* @throws NotAttachedException If the peripheral has been detached. * @throws NotAttachedException If the peripheral has been detached.
* @see ComputerCraftAPI#createSaveDirMount(Level, String, long)
* @see ComputerCraftAPI#createResourceMount(String, String)
* @see #mount(String, IMount) * @see #mount(String, IMount)
* @see #unmount(String) * @see #unmount(String)
* @see IMount * @see IMount

View File

@ -6,7 +6,6 @@
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.lua.LuaFunction;
import net.minecraftforge.common.capabilities.Capability;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -16,8 +15,8 @@ import java.util.Set;
/** /**
* The interface that defines a peripheral. * The interface that defines a peripheral.
* <p> * <p>
* In order to expose a peripheral for your block or tile entity, you may either attach a {@link Capability}, or * In order to expose a peripheral for your block or block entity, you should either attach a capability (Forge) or
* register a {@link IPeripheralProvider}. This <em>cannot</em> be implemented {@link IPeripheral} directly on the tile. * use the block lookup API (Fabric). This interface <em>cannot</em> be implemented directly on the block entity.
* <p> * <p>
* Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing
* {@link IDynamicPeripheral}. * {@link IDynamicPeripheral}.

View File

@ -5,11 +5,14 @@
*/ */
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import java.io.Serial;
/** /**
* Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to * Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to
* the computer. * the computer.
*/ */
public class NotAttachedException extends IllegalStateException { public class NotAttachedException extends IllegalStateException {
@Serial
private static final long serialVersionUID = 1221244785535553536L; private static final long serialVersionUID = 1221244785535553536L;
public NotAttachedException() { public NotAttachedException() {

View File

@ -5,9 +5,6 @@
*/ */
package dan200.computercraft.api.peripheral; package dan200.computercraft.api.peripheral;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.util.Collection; import java.util.Collection;
@ -29,8 +26,8 @@ public final class PeripheralType {
public PeripheralType(String type, Set<String> additionalTypes) { public PeripheralType(String type, Set<String> additionalTypes) {
this.type = type; this.type = type;
this.additionalTypes = additionalTypes; this.additionalTypes = additionalTypes;
if (additionalTypes.contains(null)) { for (var item : additionalTypes) {
throw new IllegalArgumentException("All additional types must be non-null"); if (item == null) throw new NullPointerException("All additional types must be non-null");
} }
} }
@ -50,7 +47,7 @@ public final class PeripheralType {
* @return The constructed peripheral type. * @return The constructed peripheral type.
*/ */
public static PeripheralType ofType(@Nonnull String type) { public static PeripheralType ofType(@Nonnull String type) {
if (Strings.isNullOrEmpty(type)) throw new IllegalArgumentException("type cannot be null or empty"); checkTypeName("type cannot be null or empty");
return new PeripheralType(type, Collections.emptySet()); return new PeripheralType(type, Collections.emptySet());
} }
@ -62,8 +59,8 @@ public final class PeripheralType {
* @return The constructed peripheral type. * @return The constructed peripheral type.
*/ */
public static PeripheralType ofType(@Nonnull String type, Collection<String> additionalTypes) { public static PeripheralType ofType(@Nonnull String type, Collection<String> additionalTypes) {
if (Strings.isNullOrEmpty(type)) throw new IllegalArgumentException("type cannot be null or empty"); checkTypeName("type cannot be null or empty");
return new PeripheralType(type, ImmutableSet.copyOf(additionalTypes)); return new PeripheralType(type, getTypes(additionalTypes));
} }
/** /**
@ -74,8 +71,8 @@ public final class PeripheralType {
* @return The constructed peripheral type. * @return The constructed peripheral type.
*/ */
public static PeripheralType ofType(@Nonnull String type, @Nonnull String... additionalTypes) { public static PeripheralType ofType(@Nonnull String type, @Nonnull String... additionalTypes) {
if (Strings.isNullOrEmpty(type)) throw new IllegalArgumentException("type cannot be null or empty"); checkTypeName(type);
return new PeripheralType(type, ImmutableSet.copyOf(additionalTypes)); return new PeripheralType(type, Set.of(additionalTypes));
} }
/** /**
@ -85,7 +82,7 @@ public final class PeripheralType {
* @return The constructed peripheral type. * @return The constructed peripheral type.
*/ */
public static PeripheralType ofAdditional(Collection<String> additionalTypes) { public static PeripheralType ofAdditional(Collection<String> additionalTypes) {
return new PeripheralType(null, ImmutableSet.copyOf(additionalTypes)); return new PeripheralType(null, getTypes(additionalTypes));
} }
/** /**
@ -95,7 +92,7 @@ public final class PeripheralType {
* @return The constructed peripheral type. * @return The constructed peripheral type.
*/ */
public static PeripheralType ofAdditional(@Nonnull String... additionalTypes) { public static PeripheralType ofAdditional(@Nonnull String... additionalTypes) {
return new PeripheralType(null, ImmutableSet.copyOf(additionalTypes)); return new PeripheralType(null, Set.of(additionalTypes));
} }
/** /**
@ -117,4 +114,14 @@ public final class PeripheralType {
public Set<String> getAdditionalTypes() { public Set<String> getAdditionalTypes() {
return additionalTypes; return additionalTypes;
} }
private static void checkTypeName(@Nullable String type) {
if (type == null || type.isEmpty()) throw new IllegalArgumentException("type cannot be null or empty");
}
private static Set<String> getTypes(Collection<String> types) {
if (types.isEmpty()) return Collections.emptySet();
if (types.size() == 1) return Collections.singleton(types.iterator().next());
return Set.copyOf(types);
}
} }

View File

@ -0,0 +1,8 @@
plugins {
id("cc-tweaked.java-convention")
}
// Skip checkstyle here, it's going to be deleted soon anyway!
tasks.checkstyleMain {
enabled = false
}

View File

@ -0,0 +1,14 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package net.minecraft.resources;
/**
* Placeholder class so we can preserve API compatibility for this release.
*/
public final class ResourceLocation {
private ResourceLocation() {
}
}

View File

@ -15,3 +15,10 @@ pluginManagement {
val mcVersion: String by settings val mcVersion: String by settings
rootProject.name = "cc-tweaked-$mcVersion" rootProject.name = "cc-tweaked-$mcVersion"
include(":mc-stubs")
include(":core-api")
for (project in rootProject.children) {
project.projectDir = file("projects/${project.name}")
}

View File

@ -8,11 +8,13 @@ package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.lua.LuaException;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.Serial;
/** /**
* A Lua exception which does not contain its stack trace. * A Lua exception which does not contain its stack trace.
*/ */
public class FastLuaException extends LuaException { public class FastLuaException extends LuaException {
@Serial
private static final long serialVersionUID = 5957864899303561143L; private static final long serialVersionUID = 5957864899303561143L;
public FastLuaException(@Nullable String message) { public FastLuaException(@Nullable String message) {

View File

@ -5,7 +5,10 @@
*/ */
package dan200.computercraft.core.apis.http; package dan200.computercraft.core.apis.http;
import java.io.Serial;
public class HTTPRequestException extends Exception { public class HTTPRequestException extends Exception {
@Serial
private static final long serialVersionUID = 7591208619422744652L; private static final long serialVersionUID = 7591208619422744652L;
public HTTPRequestException(String s) { public HTTPRequestException(String s) {

View File

@ -5,7 +5,10 @@
*/ */
package dan200.computercraft.core.filesystem; package dan200.computercraft.core.filesystem;
import java.io.Serial;
public class FileSystemException extends Exception { public class FileSystemException extends Exception {
@Serial
private static final long serialVersionUID = -2500631644868104029L; private static final long serialVersionUID = -2500631644868104029L;
FileSystemException(String s) { FileSystemException(String s) {

View File

@ -30,6 +30,7 @@ import org.squiddev.cobalt.lib.platform.VoidResourceManipulator;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.InputStream; import java.io.InputStream;
import java.io.Serial;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.*; import java.util.*;
import java.util.concurrent.SynchronousQueue; import java.util.concurrent.SynchronousQueue;
@ -444,6 +445,7 @@ public class CobaltLuaMachine implements ILuaMachine {
} }
private static final class HardAbortError extends Error { private static final class HardAbortError extends Error {
@Serial
private static final long serialVersionUID = 7954092008586367501L; private static final long serialVersionUID = 7954092008586367501L;
static final HardAbortError INSTANCE = new HardAbortError(); static final HardAbortError INSTANCE = new HardAbortError();

View File

@ -8,6 +8,7 @@ package dan200.computercraft.impl;
import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.ApiStatus;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.Serial;
/** /**
* A ComputerCraft-related service failed to load. * A ComputerCraft-related service failed to load.
@ -16,6 +17,7 @@ import javax.annotation.Nullable;
*/ */
@ApiStatus.Internal @ApiStatus.Internal
class ServiceException extends RuntimeException { class ServiceException extends RuntimeException {
@Serial
private static final long serialVersionUID = -8392300691666423882L; private static final long serialVersionUID = -8392300691666423882L;
ServiceException(String message, @Nullable Throwable cause) { ServiceException(String message, @Nullable Throwable cause) {