mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-16 06:27:39 +00:00
Compare commits
1 Commits
v1.20.1-1.
...
feature/po
Author | SHA1 | Date | |
---|---|---|---|
![]() |
94e7d2d03b |
@@ -18,6 +18,11 @@ ij_any_if_brace_force = if_multiline
|
||||
ij_any_for_brace_force = if_multiline
|
||||
ij_any_spaces_within_array_initializer_braces = true
|
||||
|
||||
ij_kotlin_allow_trailing_comma = true
|
||||
ij_kotlin_allow_trailing_comma_on_call_site = true
|
||||
ij_kotlin_method_parameters_wrap = off
|
||||
ij_kotlin_call_parameters_wrap = off
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
@@ -26,16 +31,3 @@ indent_size = 2
|
||||
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
|
||||
[{*.kt,*.kts}]
|
||||
ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL
|
||||
ij_kotlin_continuation_indent_size = 4
|
||||
ij_kotlin_spaces_around_equality_operators = true
|
||||
|
||||
ij_kotlin_allow_trailing_comma = true
|
||||
ij_kotlin_allow_trailing_comma_on_call_site = true
|
||||
|
||||
# Prefer to handle these manually
|
||||
ij_kotlin_method_parameters_wrap = off
|
||||
ij_kotlin_call_parameters_wrap = off
|
||||
ij_kotlin_extends_list_wrap = off
|
||||
|
13
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
13
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -1,14 +1,12 @@
|
||||
name: Bug report
|
||||
description: Report some misbehaviour in the mod
|
||||
labels: [ bug ]
|
||||
type: bug
|
||||
body:
|
||||
- type: dropdown
|
||||
id: mc-version
|
||||
attributes:
|
||||
label: Minecraft Version
|
||||
description: |
|
||||
What version of Minecraft are you using? If your version is not listed, please try to reproduce on one of the supported versions.
|
||||
description: What version of Minecraft are you using?
|
||||
options:
|
||||
- 1.20.1
|
||||
- 1.21.x
|
||||
@@ -28,7 +26,8 @@ body:
|
||||
label: Details
|
||||
description: |
|
||||
Description of the bug. Please include the following:
|
||||
- Logs: These will be located in the `logs/` directory of your Minecraft instance. This is always useful, even if it doesn't include errors, so please upload this!
|
||||
- Detailed reproduction steps: sometimes I can spot a bug pretty easily, but often it's much more obscure. The more information I have to help reproduce it, the quicker it'll get fixed.
|
||||
|
||||

|
||||
- Logs: These will be located in the `logs/` directory of your Minecraft
|
||||
instance. Please upload them as a gist or directly into this editor.
|
||||
- Detailed reproduction steps: sometimes I can spot a bug pretty easily,
|
||||
but often it's much more obscure. The more information I have to help
|
||||
reproduce it, the quicker it'll get fixed.
|
||||
|
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -2,7 +2,6 @@
|
||||
name: Feature request
|
||||
about: Suggest an idea or improvement
|
||||
labels: enhancement
|
||||
type: feature
|
||||
---
|
||||
|
||||
<!--
|
||||
|
32
.github/workflows/main-ci.yml
vendored
32
.github/workflows/main-ci.yml
vendored
@@ -30,18 +30,6 @@ 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:
|
||||
@@ -62,10 +50,30 @@ jobs:
|
||||
- name: 🧪 Run integration tests
|
||||
run: ./gradlew runGametest
|
||||
|
||||
- name: 🧪 Run client tests
|
||||
run: ./gradlew runGametestClient # Not checkClient, as no point running rendering tests.
|
||||
# These are a little flaky on GH actions: its useful to run them, but don't break the build.
|
||||
continue-on-error: true
|
||||
|
||||
- name: 🧪 Parse test reports
|
||||
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
|
||||
|
||||
- name: 📤 Upload coverage
|
||||
uses: codecov/codecov-action@v4
|
||||
|
||||
build-core:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,7 +27,6 @@
|
||||
*.iml
|
||||
.idea
|
||||
.gradle
|
||||
.kotlin
|
||||
*.DS_Store
|
||||
|
||||
/.classpath
|
||||
|
@@ -27,7 +27,7 @@ repos:
|
||||
exclude: "^(.*\\.(bat)|LICENSE)$"
|
||||
|
||||
- repo: https://github.com/fsfe/reuse-tool
|
||||
rev: v5.0.2
|
||||
rev: v4.0.3
|
||||
hooks:
|
||||
- id: reuse
|
||||
|
||||
@@ -58,7 +58,6 @@ repos:
|
||||
exclude: |
|
||||
(?x)^(
|
||||
projects/[a-z]+/src/generated|
|
||||
projects/[a-z]+/src/examples/generatedResources|
|
||||
projects/core/src/test/resources/test-rom/data/json-parsing/|
|
||||
.*\.dfpwm
|
||||
)
|
||||
|
@@ -22,7 +22,8 @@ If you have a bug, suggestion, or other feedback, the best thing to do is [file
|
||||
use the issue templates - they provide a useful hint on what information to provide.
|
||||
|
||||
## Translations
|
||||
Translations are managed through [CrowdIn], an online interface for managing language strings.
|
||||
Translations are managed through [CrowdIn], an online interface for managing language strings. Translations may either
|
||||
be contributed there, or directly via a pull request.
|
||||
|
||||
## Setting up a development environment
|
||||
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
|
||||
@@ -48,12 +49,9 @@ If you want to run CC:T in a normal Minecraft instance, run `./gradlew assemble`
|
||||
`projects/forge/build/libs` (for Forge) or `projects/fabric/build/libs` (for Fabric).
|
||||
|
||||
## Developing CC: Tweaked
|
||||
Before making any major changes to CC: Tweaked, I'd recommend starting opening an issue or starting a discussion on
|
||||
GitHub first. It's often helpful to discuss features before spending time developing them!
|
||||
|
||||
Once you're ready to start programming, have a read of the [the architecture document][architecture] first. While it's
|
||||
not a comprehensive document, it gives a good hint of where you should start looking to make your changes. As always, if
|
||||
you're not sure, [do ask the community][community]!
|
||||
Before making any major changes to CC: Tweaked, I'd recommend you have a read of the [the architecture
|
||||
document][architecture] first. While it's not a comprehensive document, it gives a good hint of where you should start
|
||||
looking to make your changes. As always, if you're not sure, [do ask the community][community]!
|
||||
|
||||
### Testing
|
||||
When making larger changes, it may be useful to write a test to make sure your code works as expected.
|
||||
|
17
README.md
17
README.md
@@ -11,13 +11,14 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</picture>
|
||||
|
||||
[](https://github.com/cc-tweaked/CC-Tweaked/actions "Current build status")
|
||||
[][CurseForge]
|
||||
[][Modrinth]
|
||||
|
||||
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
|
||||
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
||||
new features.
|
||||
|
||||
CC: Tweaked can be installed from [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||
CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||
|
||||
## Contributing
|
||||
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
|
||||
@@ -61,6 +62,19 @@ dependencies {
|
||||
}
|
||||
```
|
||||
|
||||
When using ForgeGradle, you may also need to add the following:
|
||||
|
||||
```groovy
|
||||
minecraft {
|
||||
runs {
|
||||
configureEach {
|
||||
property 'mixin.env.remapRefMap', 'true'
|
||||
property 'mixin.env.refMapRemappingFile', "${buildDir}/createSrgToMcp/output.srg"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You should also be careful to only use classes within the `dan200.computercraft.api` package. Non-API classes are
|
||||
subject to change at any point. If you depend on functionality outside the API (or need to mixin to CC:T), please file
|
||||
an issue to let me know!
|
||||
@@ -69,6 +83,7 @@ We bundle the API sources with the jar, so documentation should be easily viewab
|
||||
the generated documentation [can be browsed online](https://tweaked.cc/javadoc/).
|
||||
|
||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
||||
[curseforge]: https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked from CurseForge"
|
||||
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
||||
|
32
REUSE.toml
32
REUSE.toml
@@ -8,23 +8,18 @@ SPDX-PackageSupplier = "Jonathan Coates <git@squiddev.cc>"
|
||||
SPDX-PackageDownloadLocation = "https://github.com/cc-tweaked/cc-tweaked"
|
||||
|
||||
[[annotations]]
|
||||
# Generated/data files are CC0.
|
||||
SPDX-FileCopyrightText = "The CC: Tweaked Developers"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
path = [
|
||||
# Generated/data files are CC0.
|
||||
"gradle/gradle-daemon-jvm.properties",
|
||||
"projects/common/src/main/resources/assets/computercraft/sounds.json",
|
||||
"projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg",
|
||||
"projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrades/**",
|
||||
"projects/common/src/testMod/resources/data/cctest/structures/**",
|
||||
"projects/*/src/generated/**",
|
||||
"projects/**/src/generated/**",
|
||||
"projects/web/src/htmlTransform/export/index.json",
|
||||
"projects/web/src/htmlTransform/export/items/minecraft/**",
|
||||
# GitHub build scripts are CC0. While we could add a header to each file,
|
||||
# it's unclear if it will break actions or issue templates in some way.
|
||||
".github/**",
|
||||
# Example mod is CC0.
|
||||
"projects/*/src/examples/**"
|
||||
]
|
||||
|
||||
[[annotations]]
|
||||
@@ -35,15 +30,23 @@ path = [
|
||||
"doc/images/**",
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"projects/*/src/*/resources/*.mixins.json",
|
||||
"projects/fabric/src/*/resources/fabric.mod.json",
|
||||
"projects/common/src/client/resources/computercraft-client.mixins.json",
|
||||
"projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.json",
|
||||
"projects/common/src/main/resources/computercraft.mixins.json",
|
||||
"projects/common/src/testMod/resources/computercraft-gametest.mixins.json",
|
||||
"projects/common/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json",
|
||||
"projects/common/src/testMod/resources/pack.mcmeta",
|
||||
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/command/.ignoreme",
|
||||
"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/main/resources/computercraft.fabric.mixins.json",
|
||||
"projects/fabric/src/main/resources/fabric.mod.json",
|
||||
"projects/fabric/src/testMod/resources/computercraft-gametest.fabric.mixins.json",
|
||||
"projects/fabric/src/testMod/resources/fabric.mod.json",
|
||||
"projects/forge/src/client/resources/computercraft-client.forge.mixins.json",
|
||||
"projects/web/src/frontend/mount/.settings",
|
||||
"projects/web/src/frontend/mount/example.nfp",
|
||||
"projects/web/src/frontend/mount/example.nft",
|
||||
@@ -70,7 +73,7 @@ path = [
|
||||
]
|
||||
|
||||
[[annotations]]
|
||||
# Community-contributed language files
|
||||
# Community-contributed license files
|
||||
SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
|
||||
SPDX-License-Identifier = "LicenseRef-CCPL"
|
||||
path = [
|
||||
@@ -84,11 +87,18 @@ path = [
|
||||
]
|
||||
|
||||
[[annotations]]
|
||||
# Community-contributed language files
|
||||
# Community-contributed license files
|
||||
SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
|
||||
SPDX-License-Identifier = "MPL-2.0"
|
||||
path = "projects/common/src/main/resources/assets/computercraft/lang/**"
|
||||
|
||||
[[annotations]]
|
||||
# GitHub build scripts are CC0. While we could add a header to each file,
|
||||
# it's unclear if it will break actions or issue templates in some way.
|
||||
SPDX-FileCopyrightText = "Jonathan Coates <git@squiddev.cc>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
path = ".github/**"
|
||||
|
||||
[[annotations]]
|
||||
path = ["gradle/wrapper/**"]
|
||||
SPDX-FileCopyrightText = "Gradle Inc"
|
||||
|
@@ -24,19 +24,21 @@ val mcVersion: String by extra
|
||||
|
||||
githubRelease {
|
||||
token(findProperty("githubApiKey") as String? ?: "")
|
||||
owner = "cc-tweaked"
|
||||
repo = "CC-Tweaked"
|
||||
targetCommitish = cct.gitBranch
|
||||
owner.set("cc-tweaked")
|
||||
repo.set("CC-Tweaked")
|
||||
targetCommitish.set(cct.gitBranch)
|
||||
|
||||
tagName = "v$mcVersion-$modVersion"
|
||||
releaseName = "[$mcVersion] $modVersion"
|
||||
body = provider {
|
||||
"## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
|
||||
.readLines()
|
||||
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
|
||||
.joinToString("\n").trim()
|
||||
}
|
||||
prerelease = isUnstable
|
||||
tagName.set("v$mcVersion-$modVersion")
|
||||
releaseName.set("[$mcVersion] $modVersion")
|
||||
body.set(
|
||||
provider {
|
||||
"## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
|
||||
.readLines()
|
||||
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
|
||||
.joinToString("\n").trim()
|
||||
},
|
||||
)
|
||||
prerelease.set(isUnstable)
|
||||
}
|
||||
|
||||
tasks.publish { dependsOn(tasks.githubRelease) }
|
||||
@@ -116,7 +118,7 @@ idea.project.settings.compiler.javac {
|
||||
}
|
||||
|
||||
versionCatalogUpdate {
|
||||
sortByKey = false
|
||||
sortByKey.set(false)
|
||||
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
|
||||
keep { keepUnusedLibraries = true }
|
||||
keep { keepUnusedLibraries.set(true) }
|
||||
}
|
||||
|
@@ -14,10 +14,18 @@ repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
|
||||
maven("https://maven.neoforged.net") {
|
||||
name = "NeoForge"
|
||||
maven("https://maven.minecraftforge.net") {
|
||||
name = "Forge"
|
||||
content {
|
||||
includeGroup("net.neoforged")
|
||||
includeGroup("net.minecraftforge")
|
||||
includeGroup("net.minecraftforge.gradle")
|
||||
}
|
||||
}
|
||||
|
||||
maven("https://maven.parchmentmc.org") {
|
||||
name = "Librarian"
|
||||
content {
|
||||
includeGroupByRegex("^org\\.parchmentmc.*")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,10 +49,12 @@ dependencies {
|
||||
implementation(libs.kotlin.plugin)
|
||||
implementation(libs.spotless)
|
||||
|
||||
implementation(libs.curseForgeGradle)
|
||||
implementation(libs.fabric.loom)
|
||||
implementation(libs.forgeGradle)
|
||||
implementation(libs.ideaExt)
|
||||
implementation(libs.librarian)
|
||||
implementation(libs.minotaur)
|
||||
implementation(libs.modDevGradle)
|
||||
implementation(libs.vanillaExtract)
|
||||
}
|
||||
|
||||
@@ -68,7 +78,7 @@ gradlePlugin {
|
||||
}
|
||||
|
||||
versionCatalogUpdate {
|
||||
sortByKey = false
|
||||
keep { keepUnusedLibraries = true }
|
||||
catalogFile = file("../gradle/libs.versions.toml")
|
||||
sortByKey.set(false)
|
||||
keep { keepUnusedLibraries.set(true) }
|
||||
catalogFile.set(file("../gradle/libs.versions.toml"))
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ repositories {
|
||||
|
||||
loom {
|
||||
splitEnvironmentSourceSets()
|
||||
splitModDependencies = true
|
||||
splitModDependencies.set(true)
|
||||
}
|
||||
|
||||
MinecraftConfigurations.setup(project)
|
||||
|
@@ -10,22 +10,21 @@ import cc.tweaked.gradle.IdeaRunConfigurations
|
||||
import cc.tweaked.gradle.MinecraftConfigurations
|
||||
|
||||
plugins {
|
||||
id("net.minecraftforge.gradle")
|
||||
// We must apply java-convention after Forge, as we need the fg extension to be present.
|
||||
id("cc-tweaked.java-convention")
|
||||
id("net.neoforged.moddev.legacyforge")
|
||||
id("org.parchmentmc.librarian.forgegradle")
|
||||
}
|
||||
|
||||
plugins.apply(CCTweakedPlugin::class.java)
|
||||
|
||||
val mcVersion: String by extra
|
||||
|
||||
legacyForge {
|
||||
minecraft {
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
version = "${mcVersion}-${libs.findVersion("forge").get()}"
|
||||
mappings("parchment", "${libs.findVersion("parchmentMc").get()}-${libs.findVersion("parchment").get()}-$mcVersion")
|
||||
|
||||
parchment {
|
||||
minecraftVersion = libs.findVersion("parchmentMc").get().toString()
|
||||
mappingsVersion = libs.findVersion("parchment").get().toString()
|
||||
}
|
||||
accessTransformer(project(":forge").file("src/main/resources/META-INF/accesstransformer.cfg"))
|
||||
}
|
||||
|
||||
MinecraftConfigurations.setup(project)
|
||||
@@ -33,3 +32,13 @@ MinecraftConfigurations.setup(project)
|
||||
extensions.configure(CCTweakedExtension::class.java) {
|
||||
linters(minecraft = true, loader = "forge")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
"minecraft"("net.minecraftforge:forge:$mcVersion-${libs.findVersion("forge").get()}")
|
||||
}
|
||||
|
||||
tasks.configureEach {
|
||||
// genIntellijRuns isn't registered until much later, so we need this silly hijinks.
|
||||
if (name == "genIntellijRuns") doLast { IdeaRunConfigurations(project).patch() }
|
||||
}
|
||||
|
@@ -2,34 +2,44 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import cc.tweaked.gradle.clientClasses
|
||||
import cc.tweaked.gradle.commonClasses
|
||||
|
||||
/**
|
||||
* Sets up the configurations for writing game tests.
|
||||
*
|
||||
* See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
|
||||
*/
|
||||
|
||||
import cc.tweaked.gradle.MinecraftConfigurations
|
||||
import cc.tweaked.gradle.clientClasses
|
||||
import cc.tweaked.gradle.commonClasses
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("cc-tweaked.kotlin-convention")
|
||||
id("cc-tweaked.java-convention")
|
||||
}
|
||||
|
||||
val main = sourceSets["main"]
|
||||
val client = sourceSets["client"]
|
||||
|
||||
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.DATAGEN)
|
||||
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.EXAMPLES)
|
||||
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.TEST_MOD)
|
||||
// Both testMod and testFixtures inherit from the main and client classpath, just so we have access to Minecraft classes.
|
||||
val testMod by sourceSets.creating {
|
||||
compileClasspath += main.compileClasspath + client.compileClasspath
|
||||
runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
|
||||
}
|
||||
|
||||
// Set up generated resources
|
||||
sourceSets.main { resources.srcDir("src/generated/resources") }
|
||||
sourceSets.named("examples") { resources.srcDir("src/examples/generatedResources") }
|
||||
configurations {
|
||||
named(testMod.compileClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(compileClasspath.get())
|
||||
}
|
||||
|
||||
// Make sure our examples compile.
|
||||
tasks.check { dependsOn(tasks.named("compileExamplesJava")) }
|
||||
named(testMod.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)
|
||||
}
|
||||
|
||||
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
|
||||
|
@@ -29,7 +29,7 @@ base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion= CCTweakedPlugin.JAVA_VERSION
|
||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
||||
}
|
||||
|
||||
withSourcesJar()
|
||||
@@ -44,6 +44,13 @@ repositories {
|
||||
|
||||
exclusiveContent {
|
||||
forRepositories(mainMaven)
|
||||
|
||||
// Include the ForgeGradle repository if present. This requires that ForgeGradle is already present, which we
|
||||
// enforce in our Forge overlay.
|
||||
val fg =
|
||||
project.extensions.findByType(net.minecraftforge.gradle.userdev.DependencyManagementExtension::class.java)
|
||||
if (fg != null) forRepositories(fg.repository)
|
||||
|
||||
filter {
|
||||
includeGroup("cc.tweaked")
|
||||
// Things we mirror
|
||||
@@ -92,7 +99,6 @@ sourceSets.all {
|
||||
check("OperatorPrecedence", CheckSeverity.OFF) // For now.
|
||||
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.
|
||||
|
||||
check("NullAway", CheckSeverity.ERROR)
|
||||
option(
|
||||
@@ -163,8 +169,8 @@ tasks.test {
|
||||
}
|
||||
|
||||
tasks.withType(JacocoReport::class.java).configureEach {
|
||||
reports.xml.required = true
|
||||
reports.html.required =true
|
||||
reports.xml.required.set(true)
|
||||
reports.html.required.set(true)
|
||||
}
|
||||
|
||||
project.plugins.withType(CCTweakedPlugin::class.java) {
|
||||
@@ -220,5 +226,6 @@ idea.module {
|
||||
|
||||
// Force Gradle to write to inherit the output directory from the parent, instead of writing to out/xxx/classes.
|
||||
// This is required for Loom, and we patch Forge's run configurations to work there.
|
||||
// TODO: Submit a patch to Forge to support ProjectRootManager.
|
||||
inheritOutputDirs = true
|
||||
}
|
||||
|
@@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import cc.tweaked.gradle.CCTweakedPlugin
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(KotlinCompile::class.java).configureEach {
|
||||
// So technically we shouldn't need to do this as the toolchain sets it above. However, the option only appears
|
||||
// to be set when the task executes, so doesn't get picked up by IDEs.
|
||||
kotlinOptions.jvmTarget = when {
|
||||
CCTweakedPlugin.JAVA_VERSION.asInt() > 8 -> CCTweakedPlugin.JAVA_VERSION.toString()
|
||||
else -> "1.${CCTweakedPlugin.JAVA_VERSION.asInt()}"
|
||||
}
|
||||
}
|
@@ -2,9 +2,11 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import net.darkhax.curseforgegradle.TaskPublishCurseForge
|
||||
import cc.tweaked.gradle.setProvider
|
||||
|
||||
plugins {
|
||||
id("net.darkhax.curseforgegradle")
|
||||
id("com.modrinth.minotaur")
|
||||
id("cc-tweaked.publishing")
|
||||
}
|
||||
@@ -23,17 +25,34 @@ val isUnstable = project.properties["isUnstable"] == "true"
|
||||
val modVersion: String by extra
|
||||
val mcVersion: String by extra
|
||||
|
||||
val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
|
||||
group = PublishingPlugin.PUBLISH_TASK_GROUP
|
||||
description = "Upload artifacts to CurseForge"
|
||||
|
||||
apiToken = findProperty("curseForgeApiKey") ?: ""
|
||||
enabled = apiToken != ""
|
||||
|
||||
val mainFile = upload("282001", modPublishing.output)
|
||||
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.releaseType = if (isUnstable) "alpha" else "release"
|
||||
mainFile.gameVersions.add(mcVersion)
|
||||
}
|
||||
|
||||
tasks.publish { dependsOn(publishCurseForge) }
|
||||
|
||||
modrinth {
|
||||
token = findProperty("modrinthApiKey") as String? ?: ""
|
||||
projectId = "gu7yAYhd"
|
||||
versionNumber = modVersion
|
||||
versionName = modVersion
|
||||
versionType = if (isUnstable) "alpha" else "release"
|
||||
token.set(findProperty("modrinthApiKey") as String? ?: "")
|
||||
projectId.set("gu7yAYhd")
|
||||
versionNumber.set(modVersion)
|
||||
versionName.set(modVersion)
|
||||
versionType.set(if (isUnstable) "alpha" else "release")
|
||||
uploadFile.setProvider(modPublishing.output)
|
||||
gameVersions.add(mcVersion)
|
||||
changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
|
||||
changelog.set("Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion).")
|
||||
|
||||
syncBodyFrom = provider { rootProject.file("doc/mod-page.md").readText() }
|
||||
syncBodyFrom.set(provider { rootProject.file("doc/mod-page.md").readText() })
|
||||
}
|
||||
|
||||
tasks.publish { dependsOn(tasks.modrinth) }
|
||||
|
@@ -12,26 +12,25 @@ publishing {
|
||||
register<MavenPublication>("maven") {
|
||||
artifactId = base.archivesName.get()
|
||||
from(components["java"])
|
||||
suppressAllPomMetadataWarnings()
|
||||
|
||||
pom {
|
||||
name = "CC: Tweaked"
|
||||
description = "CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft."
|
||||
url = "https://github.com/cc-tweaked/CC-Tweaked"
|
||||
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 = "https://github.com/cc-tweaked/CC-Tweaked.git"
|
||||
url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system = "github"
|
||||
url = "https://github.com/cc-tweaked/CC-Tweaked/issues"
|
||||
system.set("github")
|
||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name = "ComputerCraft Public License, Version 1.0"
|
||||
url = "https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE"
|
||||
name.set("ComputerCraft Public License, Version 1.0")
|
||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -10,9 +10,14 @@ import org.gradle.api.GradleException
|
||||
import org.gradle.api.NamedDomainObjectProvider
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.attributes.TestSuiteType
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.reporting.ReportingExtension
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
@@ -20,6 +25,7 @@ import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.gradle.process.JavaForkOptions
|
||||
import org.gradle.testing.jacoco.plugins.JacocoCoverageReport
|
||||
import org.gradle.testing.jacoco.plugins.JacocoPluginExtension
|
||||
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
|
||||
import org.gradle.testing.jacoco.tasks.JacocoReport
|
||||
@@ -30,40 +36,54 @@ import java.io.IOException
|
||||
import java.net.URI
|
||||
import java.util.regex.Pattern
|
||||
|
||||
abstract class CCTweakedExtension(private val project: Project) {
|
||||
abstract class CCTweakedExtension(
|
||||
private val project: Project,
|
||||
private val fs: FileSystemOperations,
|
||||
) {
|
||||
/** Get the hash of the latest git commit. */
|
||||
val gitHash: Provider<String> =
|
||||
gitProvider("<no git commit>", listOf("rev-parse", "HEAD")) { it.trim() }
|
||||
val gitHash: Provider<String> = gitProvider(project, "<no git hash>") {
|
||||
ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "HEAD").trim()
|
||||
}
|
||||
|
||||
/** Get the current git branch. */
|
||||
val gitBranch: Provider<String> =
|
||||
gitProvider("<no git branch>", listOf("rev-parse", "--abbrev-ref", "HEAD")) { it.trim() }
|
||||
val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") {
|
||||
ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD")
|
||||
.trim()
|
||||
}
|
||||
|
||||
/** Get a list of all contributors to the project. */
|
||||
val gitContributors: Provider<List<String>> =
|
||||
gitProvider(listOf(), listOf("shortlog", "-ns", "--group=author", "--group=trailer:co-authored-by", "HEAD")) { input ->
|
||||
input.lineSequence()
|
||||
.filter { it.isNotEmpty() }
|
||||
.map {
|
||||
val matcher = COMMIT_COUNTS.matcher(it)
|
||||
matcher.find()
|
||||
matcher.group(1)
|
||||
}
|
||||
.filter { !IGNORED_USERS.contains(it) }
|
||||
.toList()
|
||||
.sortedWith(String.CASE_INSENSITIVE_ORDER)
|
||||
}
|
||||
val gitContributors: Provider<List<String>> = gitProvider(project, listOf()) {
|
||||
ProcessHelpers.captureLines(
|
||||
"git", "-C", project.rootProject.projectDir.absolutePath, "shortlog", "-ns",
|
||||
"--group=author", "--group=trailer:co-authored-by", "HEAD",
|
||||
)
|
||||
.asSequence()
|
||||
.map {
|
||||
val matcher = COMMIT_COUNTS.matcher(it)
|
||||
matcher.find()
|
||||
matcher.group(1)
|
||||
}
|
||||
.filter { !IGNORED_USERS.contains(it) }
|
||||
.toList()
|
||||
.sortedWith(String.CASE_INSENSITIVE_ORDER)
|
||||
}
|
||||
|
||||
/**
|
||||
* References to other sources
|
||||
*/
|
||||
val sourceDirectories: SetProperty<SourceSetReference> = project.objects.setProperty(SourceSetReference::class.java)
|
||||
|
||||
/**
|
||||
* Dependencies excluded from published artifacts.
|
||||
*/
|
||||
private val excludedDeps: ListProperty<Dependency> = project.objects.listProperty(Dependency::class.java)
|
||||
|
||||
/** All source sets referenced by this project. */
|
||||
val sourceSets = sourceDirectories.map { x -> x.map { it.sourceSet } }
|
||||
|
||||
init {
|
||||
sourceDirectories.finalizeValueOnRead()
|
||||
excludedDeps.finalizeValueOnRead()
|
||||
project.afterEvaluate { sourceDirectories.disallowChanges() }
|
||||
}
|
||||
|
||||
@@ -89,13 +109,14 @@ abstract class CCTweakedExtension(private val project: Project) {
|
||||
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)
|
||||
for (sourceSet in listOf(MinecraftConfigurations.DATAGEN, MinecraftConfigurations.EXAMPLES, MinecraftConfigurations.TEST_MOD, "testFixtures")) {
|
||||
otherJava.sourceSets.findByName(sourceSet)?.let { extendSourceSet(otherProject, it) }
|
||||
}
|
||||
if (testMod != null) extendSourceSet(otherProject, testMod)
|
||||
if (testFixtures != null) extendSourceSet(otherProject, testFixtures)
|
||||
|
||||
// The extra source-processing tasks should include these files too.
|
||||
project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
|
||||
@@ -158,19 +179,23 @@ abstract class CCTweakedExtension(private val project: Project) {
|
||||
}
|
||||
|
||||
fun <T> jacoco(task: NamedDomainObjectProvider<T>) where T : Task, T : JavaForkOptions {
|
||||
val classDump = project.layout.buildDirectory.dir("jacocoClassDump/${task.name}")
|
||||
val reportTaskName = "jacoco${task.name.capitalise()}Report"
|
||||
|
||||
val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
|
||||
task.configure {
|
||||
finalizedBy(reportTaskName)
|
||||
jacoco.applyTo(this)
|
||||
|
||||
doFirst("Clean class dump directory") { fs.delete { delete(classDump) } }
|
||||
|
||||
jacoco.applyTo(this)
|
||||
extensions.configure(JacocoTaskExtension::class.java) {
|
||||
includes = listOf("dan200.computercraft.*")
|
||||
excludes = listOf(
|
||||
"dan200.computercraft.mixin.*", // Exclude mixins, as they're not executed at runtime.
|
||||
"dan200.computercraft.shared.Capabilities$*", // Exclude capability tokens, as Forge rewrites them.
|
||||
)
|
||||
classDumpDir = classDump.get().asFile
|
||||
|
||||
// Older versions of modlauncher don't include a protection domain (and thus no code
|
||||
// source). Jacoco skips such classes by default, so we need to explicitly include them.
|
||||
isIncludeNoLocationClasses = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,11 +204,15 @@ abstract class CCTweakedExtension(private val project: Project) {
|
||||
description = "Generates code coverage report for the ${task.name} task."
|
||||
|
||||
executionData(task.get())
|
||||
classDirectories.from(classDump)
|
||||
|
||||
// Don't want to use sourceSets(...) here as we don't use all class directories.
|
||||
for (ref in this@CCTweakedExtension.sourceDirectories.get()) {
|
||||
sourceDirectories.from(ref.sourceSet.allSource.sourceDirectories)
|
||||
if (ref.classes) classDirectories.from(ref.sourceSet.output)
|
||||
// Don't want to use sourceSets(...) here as we have a custom class directory.
|
||||
for (ref in sourceSets.get()) sourceDirectories.from(ref.allSource.sourceDirectories)
|
||||
}
|
||||
|
||||
project.extensions.configure(ReportingExtension::class.java) {
|
||||
reports.register("${task.name}CodeCoverageReport", JacocoCoverageReport::class.java) {
|
||||
testType.set(TestSuiteType.INTEGRATION_TEST)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,31 +252,40 @@ abstract class CCTweakedExtension(private val project: Project) {
|
||||
).resolve().single()
|
||||
}
|
||||
|
||||
private fun <T> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
|
||||
val baseResult = project.providers.exec {
|
||||
commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command
|
||||
}
|
||||
/**
|
||||
* Exclude a dependency from being published in Maven.
|
||||
*/
|
||||
fun exclude(dep: Dependency) {
|
||||
excludedDeps.add(dep)
|
||||
}
|
||||
|
||||
return project.provider {
|
||||
val res = try {
|
||||
baseResult.standardOutput.asText.get()
|
||||
} catch (e: IOException) {
|
||||
project.logger.error("Cannot read Git repository: ${e.message}", e)
|
||||
return@provider default
|
||||
} catch (e: GradleException) {
|
||||
project.logger.error("Cannot read Git repository: ${e.message}", e)
|
||||
return@provider default
|
||||
}
|
||||
process(res)
|
||||
}
|
||||
/**
|
||||
* Configure a [MavenDependencySpec].
|
||||
*/
|
||||
fun configureExcludes(spec: MavenDependencySpec) {
|
||||
for (dep in excludedDeps.get()) spec.exclude(dep)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
|
||||
private val IGNORED_USERS = setOf(
|
||||
"GitHub", "Daniel Ratcliffe", "NotSquidDev", "Weblate",
|
||||
"GitHub", "Daniel Ratcliffe", "Weblate",
|
||||
)
|
||||
|
||||
private fun <T> gitProvider(project: Project, default: T, supplier: () -> T): Provider<T> {
|
||||
return project.provider {
|
||||
try {
|
||||
supplier()
|
||||
} catch (e: IOException) {
|
||||
project.logger.error("Cannot read Git repository: ${e.message}")
|
||||
default
|
||||
} catch (e: GradleException) {
|
||||
project.logger.error("Cannot read Git repository: ${e.message}")
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val isIdeSync: Boolean
|
||||
get() = java.lang.Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"))
|
||||
}
|
||||
|
@@ -22,19 +22,19 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
|
||||
abstract class DependencyCheck : DefaultTask() {
|
||||
@get:Input
|
||||
protected abstract val dependencies: ListProperty<DependencyResult>
|
||||
abstract val configuration: ListProperty<Configuration>
|
||||
|
||||
/**
|
||||
* A mapping of module coordinates (`group:module`) to versions, overriding the requested version.
|
||||
*/
|
||||
@get:Input
|
||||
protected abstract val overrides: MapProperty<String, String>
|
||||
abstract val overrides: MapProperty<String, String>
|
||||
|
||||
init {
|
||||
description = "Check :core's dependencies are consistent with Minecraft's."
|
||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
|
||||
dependencies.finalizeValueOnRead()
|
||||
configuration.finalizeValueOnRead()
|
||||
overrides.finalizeValueOnRead()
|
||||
}
|
||||
|
||||
@@ -45,19 +45,13 @@ abstract class DependencyCheck : DefaultTask() {
|
||||
overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a configuration to check.
|
||||
*/
|
||||
fun configuration(configuration: Provider<Configuration>) {
|
||||
// We can't store the Configuration in the cache, so store the resolved dependencies instead.
|
||||
dependencies.addAll(configuration.map { it.incoming.resolutionResult.allDependencies })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
var ok = true
|
||||
for (configuration in dependencies.get()) {
|
||||
if (!check(configuration)) ok = false
|
||||
for (configuration in configuration.get()) {
|
||||
configuration.incoming.resolutionResult.allDependencies {
|
||||
if (!check(this@allDependencies)) ok = false
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
|
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import net.minecraftforge.gradle.common.util.RunConfig
|
||||
import net.minecraftforge.gradle.common.util.runs.setRunConfigInternal
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.JavaExec
|
||||
import org.gradle.jvm.toolchain.JavaToolchainService
|
||||
import java.nio.file.Files
|
||||
|
||||
/**
|
||||
* Set [JavaExec] task to run a given [RunConfig].
|
||||
*/
|
||||
fun JavaExec.setRunConfig(config: RunConfig) {
|
||||
dependsOn("prepareRuns")
|
||||
setRunConfigInternal(project, this, config)
|
||||
doFirst("Create working directory") { Files.createDirectories(workingDir.toPath()) }
|
||||
|
||||
javaLauncher.set(
|
||||
project.extensions.getByType(JavaToolchainService::class.java)
|
||||
.launcherFor(project.extensions.getByType(JavaPluginExtension::class.java).toolchain),
|
||||
)
|
||||
}
|
@@ -0,0 +1,73 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
||||
import org.gradle.api.artifacts.ProjectDependency
|
||||
import org.gradle.api.plugins.BasePluginExtension
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.specs.Spec
|
||||
|
||||
/**
|
||||
* A dependency in a POM file.
|
||||
*/
|
||||
data class MavenDependency(val groupId: String?, val artifactId: String?, val version: String?, val scope: String?)
|
||||
|
||||
/**
|
||||
* A spec specifying which dependencies to include/exclude.
|
||||
*/
|
||||
class MavenDependencySpec {
|
||||
private val excludeSpecs = mutableListOf<Spec<MavenDependency>>()
|
||||
|
||||
fun exclude(spec: Spec<MavenDependency>) {
|
||||
excludeSpecs.add(spec)
|
||||
}
|
||||
|
||||
fun exclude(dep: Dependency) {
|
||||
exclude {
|
||||
// We have to cheat a little for project dependencies, as the project name doesn't match the artifact group.
|
||||
val name = when (dep) {
|
||||
is ProjectDependency -> dep.dependencyProject.extensions.getByType(BasePluginExtension::class.java).archivesName.get()
|
||||
else -> dep.name
|
||||
}
|
||||
(dep.group.isNullOrEmpty() || dep.group == it.groupId) &&
|
||||
(name.isNullOrEmpty() || name == it.artifactId) &&
|
||||
(dep.version.isNullOrEmpty() || dep.version == it.version)
|
||||
}
|
||||
}
|
||||
|
||||
fun exclude(dep: MinimalExternalModuleDependency) {
|
||||
exclude {
|
||||
dep.module.group == it.groupId && dep.module.name == it.artifactId
|
||||
}
|
||||
}
|
||||
|
||||
fun isIncluded(dep: MavenDependency) = !excludeSpecs.any { it.isSatisfiedBy(dep) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure dependencies present in this publication's POM file.
|
||||
*
|
||||
* While this approach is very ugly, it's the easiest way to handle it!
|
||||
*/
|
||||
fun MavenPublication.mavenDependencies(action: MavenDependencySpec.() -> Unit) {
|
||||
val spec = MavenDependencySpec()
|
||||
action(spec)
|
||||
|
||||
pom.withXml {
|
||||
val dependencies = XmlUtil.findChild(asNode(), "dependencies") ?: return@withXml
|
||||
dependencies.children().map { it as groovy.util.Node }.forEach {
|
||||
val dep = MavenDependency(
|
||||
groupId = XmlUtil.findChild(it, "groupId")?.text(),
|
||||
artifactId = XmlUtil.findChild(it, "artifactId")?.text(),
|
||||
version = XmlUtil.findChild(it, "version")?.text(),
|
||||
scope = XmlUtil.findChild(it, "scope")?.text(),
|
||||
)
|
||||
|
||||
if (!spec.isIncluded(dep)) it.parent().remove(it)
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,6 +24,7 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
private val java = project.extensions.getByType(JavaPluginExtension::class.java)
|
||||
private val sourceSets = java.sourceSets
|
||||
private val configurations = project.configurations
|
||||
private val objects = project.objects
|
||||
|
||||
private val main = sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
|
||||
private val test = sourceSets[SourceSet.TEST_SOURCE_SET_NAME]
|
||||
@@ -36,7 +37,13 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
val client = sourceSets.maybeCreate("client")
|
||||
|
||||
// Ensure the client classpaths behave the same as the main ones.
|
||||
consistentWithMain(client)
|
||||
configurations.named(client.compileClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
|
||||
}
|
||||
|
||||
configurations.named(client.runtimeClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
|
||||
}
|
||||
|
||||
// Set up an API configuration for clients (to ensure it's consistent with the main source set).
|
||||
val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
|
||||
@@ -78,16 +85,6 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
setupBasic()
|
||||
}
|
||||
|
||||
private fun consistentWithMain(sourceSet: SourceSet) {
|
||||
configurations.named(sourceSet.compileClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
|
||||
}
|
||||
|
||||
configurations.named(sourceSet.runtimeClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupBasic() {
|
||||
val client = sourceSets["client"]
|
||||
|
||||
@@ -99,30 +96,13 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
val checkDependencyConsistency =
|
||||
project.tasks.register("checkDependencyConsistency", DependencyCheck::class.java) {
|
||||
// We need to check both the main and client classpath *configurations*, as the actual configuration
|
||||
configuration(configurations.named(main.runtimeClasspathConfigurationName))
|
||||
configuration(configurations.named(client.runtimeClasspathConfigurationName))
|
||||
configuration.add(configurations.named(main.runtimeClasspathConfigurationName))
|
||||
configuration.add(configurations.named(client.runtimeClasspathConfigurationName))
|
||||
}
|
||||
project.tasks.named("check") { dependsOn(checkDependencyConsistency) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new configuration that pulls in the main and client classes from the mod.
|
||||
*/
|
||||
private fun createDerivedConfiguration(name: String) {
|
||||
val client = sourceSets["client"]
|
||||
val sourceSet = sourceSets.create(name)
|
||||
sourceSet.compileClasspath += main.compileClasspath + client.compileClasspath
|
||||
sourceSet.runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
|
||||
consistentWithMain(sourceSet)
|
||||
project.dependencies.add(sourceSet.implementationConfigurationName, main.output)
|
||||
project.dependencies.add(sourceSet.implementationConfigurationName, client.output)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DATAGEN = "datagen"
|
||||
const val EXAMPLES = "examples"
|
||||
const val TEST_MOD = "testMod"
|
||||
|
||||
fun setupBasic(project: Project) {
|
||||
MinecraftConfigurations(project).setupBasic()
|
||||
}
|
||||
@@ -130,10 +110,6 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
fun setup(project: Project) {
|
||||
MinecraftConfigurations(project).setup()
|
||||
}
|
||||
|
||||
fun createDerivedConfiguration(project: Project, name: String) {
|
||||
MinecraftConfigurations(project).createDerivedConfiguration(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import net.neoforged.moddevgradle.internal.RunGameTask
|
||||
import net.minecraftforge.gradle.common.util.RunConfig
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.invocation.Gradle
|
||||
@@ -65,19 +65,11 @@ abstract class ClientJavaExec : JavaExec() {
|
||||
setTestProperties()
|
||||
}
|
||||
|
||||
fun copyFromForge(path: String) = copyFromForge(project.tasks.getByName(path, RunGameTask::class))
|
||||
|
||||
/**
|
||||
* Set this task to run a given [RunGameTask].
|
||||
* Set this task to run a given [RunConfig].
|
||||
*/
|
||||
fun copyFromForge(task: RunGameTask) {
|
||||
copyFrom(task)
|
||||
|
||||
// Eagerly evaluate the behaviour of RunGameTask.exec
|
||||
environment.putAll(task.environmentProperty.get())
|
||||
classpath(task.classpathProvider)
|
||||
workingDir = task.gameDirectory.get().asFile
|
||||
|
||||
fun setRunConfig(config: RunConfig) {
|
||||
(this as JavaExec).setRunConfig(config)
|
||||
setTestProperties() // setRunConfig may clobber some properties, ensure everything is set.
|
||||
}
|
||||
|
||||
|
@@ -11,9 +11,7 @@ import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.ExecOperations
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class NodePlugin : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
@@ -45,12 +43,9 @@ abstract class NpmInstall : DefaultTask() {
|
||||
@get:OutputDirectory
|
||||
val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
|
||||
|
||||
@get:Inject
|
||||
protected abstract val execOperations: ExecOperations
|
||||
|
||||
@TaskAction
|
||||
fun install() {
|
||||
execOperations.exec {
|
||||
project.exec {
|
||||
commandLine(ProcessHelpers.getExecutable("npm"), "ci")
|
||||
workingDir = projectRoot.get().asFile
|
||||
}
|
||||
|
@@ -4,10 +4,45 @@
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.codehaus.groovy.runtime.ProcessGroovyMethods
|
||||
import org.gradle.api.GradleException
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
internal object ProcessHelpers {
|
||||
fun startProcess(vararg command: String): Process {
|
||||
// Something randomly passes in "GIT_DIR=" as an environment variable which clobbers everything else. Don't
|
||||
// inherit the environment array!
|
||||
return ProcessBuilder()
|
||||
.command(*command)
|
||||
.redirectError(ProcessBuilder.Redirect.INHERIT)
|
||||
.also { it.environment().clear() }
|
||||
.start()
|
||||
}
|
||||
|
||||
fun captureOut(vararg command: String): String {
|
||||
val process = startProcess(*command)
|
||||
process.outputStream.close()
|
||||
|
||||
val result = ProcessGroovyMethods.getText(process)
|
||||
process.waitForOrThrow("Failed to run command")
|
||||
return result
|
||||
}
|
||||
|
||||
fun captureLines(vararg command: String): List<String> {
|
||||
val process = startProcess(*command)
|
||||
process.outputStream.close()
|
||||
|
||||
val out = BufferedReader(InputStreamReader(process.inputStream, StandardCharsets.UTF_8)).use { reader ->
|
||||
reader.lines().filter { it.isNotEmpty() }.toList()
|
||||
}
|
||||
ProcessGroovyMethods.closeStreams(process)
|
||||
process.waitForOrThrow("Failed to run command")
|
||||
return out
|
||||
}
|
||||
|
||||
fun onPath(name: String): Boolean {
|
||||
val path = System.getenv("PATH") ?: return false
|
||||
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
||||
|
@@ -0,0 +1,51 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package net.minecraftforge.gradle.common.util.runs
|
||||
|
||||
import net.minecraftforge.gradle.common.util.RunConfig
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.process.CommandLineArgumentProvider
|
||||
import org.gradle.process.JavaExecSpec
|
||||
import java.io.File
|
||||
import java.util.function.Supplier
|
||||
import java.util.stream.Collectors
|
||||
import java.util.stream.Stream
|
||||
|
||||
/**
|
||||
* Set up a [JavaExecSpec] to execute a [RunConfig].
|
||||
*
|
||||
* [MinecraftRunTask] sets up all its properties when the task is executed, rather than when configured. As such, it's
|
||||
* not possible to use [cc.tweaked.gradle.copyToFull] like we do for Fabric. Instead, we set up the task manually.
|
||||
*
|
||||
* Unfortunately most of the functionality we need is package-private, and so we have to put our code into the package.
|
||||
*/
|
||||
internal fun setRunConfigInternal(project: Project, spec: JavaExecSpec, config: RunConfig) {
|
||||
spec.workingDir = File(config.workingDirectory)
|
||||
|
||||
spec.mainClass.set(config.main)
|
||||
for (source in config.allSources) spec.classpath(source.runtimeClasspath)
|
||||
|
||||
val originalTask = project.tasks.named(config.taskName, MinecraftRunTask::class.java)
|
||||
|
||||
// Add argument and JVM argument via providers, to be as lazy as possible with fetching artifacts.
|
||||
val lazyTokens = RunConfigGenerator.configureTokensLazy(
|
||||
project, config, RunConfigGenerator.mapModClassesToGradle(project, config),
|
||||
originalTask.get().minecraftArtifacts,
|
||||
originalTask.get().runtimeClasspathArtifacts,
|
||||
)
|
||||
spec.argumentProviders.add(
|
||||
CommandLineArgumentProvider {
|
||||
RunConfigGenerator.getArgsStream(config, lazyTokens, false).toList()
|
||||
},
|
||||
)
|
||||
spec.jvmArgumentProviders.add(
|
||||
CommandLineArgumentProvider {
|
||||
(if (config.isClient) config.jvmArgs + originalTask.get().additionalClientArgs.get() else config.jvmArgs).map { config.replace(lazyTokens, it) } +
|
||||
config.properties.map { (k, v) -> "-D${k}=${config.replace(lazyTokens, v)}" }
|
||||
},
|
||||
)
|
||||
|
||||
for ((key, value) in config.environment) spec.environment(key, config.replace(lazyTokens, value))
|
||||
}
|
@@ -124,7 +124,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</module>
|
||||
<module name="MethodTypeParameterName" />
|
||||
<module name="PackageName">
|
||||
<property name="format" value="^(dan200\.computercraft|cc\.tweaked|com\.example\.examplemod)(\.[a-z][a-z0-9]*)*" />
|
||||
<property name="format" value="^(dan200\.computercraft|cc\.tweaked)(\.[a-z][a-z0-9]*)*" />
|
||||
</module>
|
||||
<module name="ParameterName" />
|
||||
<module name="StaticVariableName">
|
||||
|
@@ -1,13 +1,12 @@
|
||||
# SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
files:
|
||||
- source: projects/common/src/generated/resources/assets/computercraft/lang/en_us.json
|
||||
translation: /projects/common/src/main/resources/assets/computercraft/lang/%locale_with_underscore%.json
|
||||
languages_mapping:
|
||||
locale_with_underscore:
|
||||
cs: cs_cz # Czech
|
||||
cs: cs_cs # Czech
|
||||
da: da_dk # Danish
|
||||
de: de_de # German
|
||||
es-ES: es_es # Spanish
|
||||
|
@@ -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][`monitor`] size is changed.
|
||||
The [`monitor_resize`] event is fired when an adjacent or networked monitor's size is changed.
|
||||
|
||||
## Return Values
|
||||
1. [`string`]: The event name.
|
||||
|
@@ -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][`monitor`] is right-clicked.
|
||||
The [`monitor_touch`] event is fired when an adjacent or networked Advanced Monitor is right-clicked.
|
||||
|
||||
## Return Values
|
||||
1. [`string`]: The event name.
|
||||
|
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
The [`event!redstone`] event is fired whenever any redstone inputs on the computer or [relay][`redstone_relay`] change.
|
||||
The [`event!redstone`] event is fired whenever any redstone inputs on the computer change.
|
||||
|
||||
## Return values
|
||||
1. [`string`]: The event name.
|
||||
@@ -21,7 +21,3 @@ while true do
|
||||
print("A redstone input has changed!")
|
||||
end
|
||||
```
|
||||
|
||||
## See also
|
||||
- [The `redstone` API on computers][`module!redstone`]
|
||||
- [The `redstone_relay` peripheral][`redstone_relay`]
|
||||
|
@@ -16,7 +16,7 @@ CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles an
|
||||
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
||||
new features.
|
||||
|
||||
CC: Tweaked can be installed from [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||
CC: Tweaked can be installed from [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||
|
||||
## Features
|
||||
Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
|
||||
@@ -62,6 +62,7 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
|
||||
[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub"
|
||||
[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
|
||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
||||
[curseforge]: https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked from CurseForge"
|
||||
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
||||
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||
|
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
|
||||
|
||||
# Mod properties
|
||||
isUnstable=false
|
||||
modVersion=1.114.4
|
||||
modVersion=1.113.1
|
||||
|
||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||
mcVersion=1.20.1
|
||||
|
@@ -26,14 +26,14 @@ slf4j = "2.0.1"
|
||||
asm = "9.6"
|
||||
autoService = "1.1.1"
|
||||
checkerFramework = "3.42.0"
|
||||
cobalt = { strictly = "0.9.5" }
|
||||
cobalt = "0.9.4"
|
||||
commonsCli = "1.6.0"
|
||||
jetbrainsAnnotations = "24.1.0"
|
||||
jsr305 = "3.0.2"
|
||||
jzlib = "1.1.3"
|
||||
kotlin = "2.1.0"
|
||||
kotlin-coroutines = "1.10.1"
|
||||
nightConfig = "3.8.1"
|
||||
kotlin = "1.9.21"
|
||||
kotlin-coroutines = "1.7.3"
|
||||
nightConfig = "3.6.7"
|
||||
|
||||
# Minecraft mods
|
||||
emi = "1.0.8+1.20.1"
|
||||
@@ -52,29 +52,30 @@ create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
||||
# Testing
|
||||
hamcrest = "2.2"
|
||||
jqwik = "1.8.2"
|
||||
junit = "5.11.4"
|
||||
junitPlatform = "1.11.4"
|
||||
junit = "5.10.1"
|
||||
jmh = "1.37"
|
||||
|
||||
# Build tools
|
||||
cctJavadoc = "1.8.3"
|
||||
cctJavadoc = "1.8.2"
|
||||
checkstyle = "10.14.1"
|
||||
curseForgeGradle = "1.0.14"
|
||||
errorProne-core = "2.27.0"
|
||||
errorProne-plugin = "3.1.0"
|
||||
fabric-loom = "1.9.2"
|
||||
fabric-loom = "1.7.1"
|
||||
forgeGradle = "6.0.21"
|
||||
githubRelease = "2.5.2"
|
||||
gradleVersions = "0.50.0"
|
||||
ideaExt = "1.1.7"
|
||||
illuaminate = "0.1.0-74-gf1551d5"
|
||||
illuaminate = "0.1.0-73-g43ee16c"
|
||||
librarian = "1.+"
|
||||
lwjgl = "3.3.3"
|
||||
minotaur = "2.8.7"
|
||||
modDevGradle = "2.0.74"
|
||||
minotaur = "2.+"
|
||||
nullAway = "0.10.25"
|
||||
shadow = "8.3.1"
|
||||
spotless = "6.23.3"
|
||||
taskTree = "2.1.1"
|
||||
teavm = "0.11.0-SQUID.1"
|
||||
vanillaExtract = "0.2.0"
|
||||
vanillaExtract = "0.1.3"
|
||||
versionCatalogUpdate = "0.8.1"
|
||||
|
||||
[libraries]
|
||||
@@ -131,7 +132,6 @@ jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
|
||||
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit" }
|
||||
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit" }
|
||||
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
|
||||
junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher", version.ref = "junitPlatform" }
|
||||
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
|
||||
jmh = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
|
||||
jmh-processor = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
|
||||
@@ -145,17 +145,19 @@ lwjgl-glfw = { module = "org.lwjgl:lwjgl-glfw" }
|
||||
# Build tools
|
||||
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
|
||||
checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
|
||||
curseForgeGradle = { module = "net.darkhax.curseforgegradle:CurseForgeGradle", version.ref = "curseForgeGradle" }
|
||||
errorProne-annotations = { module = "com.google.errorprone:error_prone_annotations", version.ref = "errorProne-core" }
|
||||
errorProne-api = { module = "com.google.errorprone:error_prone_check_api", version.ref = "errorProne-core" }
|
||||
errorProne-core = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne-core" }
|
||||
errorProne-plugin = { module = "net.ltgt.gradle:gradle-errorprone-plugin", version.ref = "errorProne-plugin" }
|
||||
errorProne-testHelpers = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorProne-core" }
|
||||
fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom" }
|
||||
forgeGradle = { module = "net.minecraftforge.gradle:ForgeGradle", version.ref = "forgeGradle" }
|
||||
ideaExt = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "ideaExt" }
|
||||
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
librarian = { module = "org.parchmentmc:librarian", version.ref = "librarian" }
|
||||
minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
|
||||
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
|
||||
modDevGradle = { module = "net.neoforged:moddev-gradle", version.ref = "modDevGradle" }
|
||||
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
|
||||
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
|
||||
teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
|
||||
@@ -170,9 +172,11 @@ vanillaExtract = { module = "cc.tweaked.vanilla-extract:plugin", version.ref = "
|
||||
yarn = { module = "net.fabricmc:yarn", version.ref = "yarn" }
|
||||
|
||||
[plugins]
|
||||
forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" }
|
||||
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
|
||||
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
|
||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
librarian = { id = "org.parchmentmc.librarian.forgegradle", version.ref = "librarian" }
|
||||
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" }
|
||||
@@ -190,7 +194,7 @@ externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
|
||||
|
||||
# Testing
|
||||
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
||||
testRuntime = ["junit-jupiter-engine", "junit-platform-launcher", "jqwik-engine"]
|
||||
testRuntime = ["junit-jupiter-engine", "jqwik-engine"]
|
||||
|
||||
# Build tools
|
||||
teavm-api = ["teavm-jso", "teavm-jso-apis", "teavm-platform", "teavm-classlib", "teavm-metaprogramming-api"]
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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-8.10-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
3
gradlew
vendored
3
gradlew
vendored
@@ -86,7 +86,8 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
1275
package-lock.json
generated
1275
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,10 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||
"@rollup/plugin-typescript": "^12.0.0",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@swc/core": "^1.3.92",
|
||||
"@types/node": "^22.0.0",
|
||||
"@types/node": "^20.8.3",
|
||||
"lightningcss": "^1.22.0",
|
||||
"preact-render-to-string": "^6.2.1",
|
||||
"rehype": "^13.0.0",
|
||||
|
@@ -8,8 +8,6 @@ plugins {
|
||||
id("cc-tweaked.vanilla")
|
||||
}
|
||||
|
||||
val mcVersion: String by extra
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
}
|
||||
@@ -18,61 +16,9 @@ dependencies {
|
||||
api(project(":core-api"))
|
||||
}
|
||||
|
||||
val javadocOverview by tasks.registering(Copy::class) {
|
||||
from("src/overview.html")
|
||||
into(layout.buildDirectory.dir(name))
|
||||
|
||||
expand(
|
||||
mapOf(
|
||||
"mcVersion" to mcVersion,
|
||||
"modVersion" to version,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
tasks.javadoc {
|
||||
title = "CC: Tweaked $version for Minecraft $mcVersion"
|
||||
include("dan200/computercraft/api/**/*.java")
|
||||
|
||||
options {
|
||||
(this as StandardJavadocDocletOptions)
|
||||
|
||||
inputs.files(javadocOverview)
|
||||
overview(javadocOverview.get().destinationDir.resolve("overview.html").absolutePath)
|
||||
|
||||
groups = mapOf(
|
||||
"Common" to listOf(
|
||||
"dan200.computercraft.api",
|
||||
"dan200.computercraft.api.lua",
|
||||
"dan200.computercraft.api.peripheral",
|
||||
),
|
||||
"Upgrades" to listOf(
|
||||
"dan200.computercraft.api.client.turtle",
|
||||
"dan200.computercraft.api.pocket",
|
||||
"dan200.computercraft.api.turtle",
|
||||
"dan200.computercraft.api.upgrades",
|
||||
),
|
||||
)
|
||||
|
||||
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(),
|
||||
)
|
||||
|
||||
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 })
|
||||
}
|
||||
|
||||
// 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 })
|
||||
}
|
||||
|
@@ -22,14 +22,7 @@ import java.util.List;
|
||||
* <p>
|
||||
* Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a
|
||||
* modeller on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} to register one
|
||||
* on Forge.
|
||||
*
|
||||
* <h2>Example</h2>
|
||||
* <h3>Fabric</h3>
|
||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
||||
*
|
||||
* <h3>Forge</h3>
|
||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
||||
* on Forge
|
||||
*
|
||||
* @param <T> The type of turtle upgrade this modeller applies to.
|
||||
* @see RegisterTurtleUpgradeModeller For multi-loader registration support.
|
||||
|
@@ -171,9 +171,16 @@ public final class ComputerCraftAPI {
|
||||
* using {@link ILuaAPI#getModuleName()} to expose this library as a module instead of as a global.
|
||||
* <p>
|
||||
* This may be used with {@link IComputerSystem#getComponent(ComputerComponent)} to only attach APIs to specific
|
||||
* computers. For example, one can add a new API just to turtles with the following code:
|
||||
* computers. For example, one can add an additional API just to turtles with the following code:
|
||||
*
|
||||
* {@snippet class=com.example.examplemod.ExampleAPI region=register}
|
||||
* <pre>{@code
|
||||
* ComputerCraftAPI.registerAPIFactory(computer -> {
|
||||
* // Read the turtle component.
|
||||
* var turtle = computer.getComponent(ComputerComponents.TURTLE);
|
||||
* // If present then add our API.
|
||||
* return turtle == null ? null : new MyCustomTurtleApi(turtle);
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @param factory The factory for your API subclass.
|
||||
* @see ILuaAPIFactory
|
||||
|
@@ -14,13 +14,13 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
||||
* as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
|
||||
* for its lifespan.
|
||||
* <p>
|
||||
* Elements are generally tied to a block or block entity in world. In such as case, one should provide the
|
||||
* Elements are generally tied to a block or tile entity in world. In such as case, one should provide the
|
||||
* {@link WiredElement} capability for the appropriate sides.
|
||||
*/
|
||||
public interface WiredElement extends WiredSender {
|
||||
/**
|
||||
* Called when peripherals on the network change. This may occur when network nodes are added or removed, or when
|
||||
* peripherals are attached or detached from a modem.
|
||||
* Called when objects on the network change. This may occur when network nodes are added or removed, or when
|
||||
* peripherals change.
|
||||
*
|
||||
* @param change The change which occurred.
|
||||
* @see WiredNetworkChange
|
||||
|
@@ -14,10 +14,13 @@ import javax.annotation.Nullable;
|
||||
* A peripheral which can be equipped to the back side of a pocket computer.
|
||||
* <p>
|
||||
* Pocket upgrades are defined in two stages. First, on creates a {@link IPocketUpgrade} subclass and corresponding
|
||||
* {@link PocketUpgradeSerialiser} instance, which are then registered in a Minecraft registry.
|
||||
* {@link PocketUpgradeSerialiser} instance, which are then registered in a Forge registry.
|
||||
* <p>
|
||||
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
||||
* the upgrade registered internally.
|
||||
* the upgrade registered internally. See the documentation in {@link PocketUpgradeSerialiser} for details on this process
|
||||
* and where files should be located.
|
||||
*
|
||||
* @see PocketUpgradeSerialiser For how to register a pocket computer upgrade.
|
||||
*/
|
||||
public interface IPocketUpgrade extends UpgradeBase {
|
||||
/**
|
||||
|
@@ -8,69 +8,21 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new
|
||||
* peripheral.
|
||||
* <p>
|
||||
* Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
|
||||
* {@link TurtleUpgradeSerialiser} instance, which are then registered in a Minecraft registry.
|
||||
* {@link TurtleUpgradeSerialiser} instance, which are then registered in a Forge registry.
|
||||
* <p>
|
||||
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
||||
* the upgrade automatically registered.
|
||||
* the upgrade registered internally. See the documentation in {@link TurtleUpgradeSerialiser} for details on this process
|
||||
* and where files should be located.
|
||||
*
|
||||
* <h2>Example</h2>
|
||||
* <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
|
||||
* (e.g. {@link TurtleUpgradeSerialiser#simpleWithCustomItem(BiFunction)}), rather than defining your own implementation.
|
||||
*
|
||||
* {@snippet class=com.example.examplemod.ExampleMod region=turtle_upgrades}
|
||||
*
|
||||
* We now must register this upgrade serialiser. This is done the same way as you'd register blocks, items, or other
|
||||
* Minecraft objects. The approach to do this will depend on mod-loader.
|
||||
*
|
||||
* <h4>Fabric</h4>
|
||||
* {@snippet class=com.example.examplemod.FabricExampleMod region=turtle_upgrades}
|
||||
*
|
||||
* <h4>Forge</h4>
|
||||
* {@snippet class=com.example.examplemod.ForgeExampleMod region=turtle_upgrades}
|
||||
*
|
||||
* <h3>Rendering the upgrade</h3>
|
||||
* Next, we need to register a model for our upgrade. This is done by registering a
|
||||
* {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for your upgrade serialiser.
|
||||
*
|
||||
* <h4>Fabric</h4>
|
||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
||||
*
|
||||
*
|
||||
* <h4>Forge</h4>
|
||||
* {@snippet class=com.example.examplemod.FabricExampleModClient region=turtle_modellers}
|
||||
*
|
||||
* <h3>Registering the upgrade itself</h3>
|
||||
* Upgrades themselves are loaded from datapacks when a level is loaded. In order to register our new upgrade, we must
|
||||
* create a new JSON file at {@code data/<my_mod>/computercraft/turtle_upgrades/<my_upgrade_id>.json}.
|
||||
*
|
||||
* {@snippet file = data/examplemod/computercraft/turtle_upgrades/example_turtle_upgrade.json}
|
||||
*
|
||||
* The {@code "type"} field points to the ID of the upgrade serialiser we've just registered, while the other fields
|
||||
* are read by the serialiser itself. As our upgrade was defined with {@link TurtleUpgradeSerialiser#simpleWithCustomItem(BiFunction)}, the
|
||||
* {@code "item"} field will construct our upgrade with {@link Items#COMPASS}.
|
||||
* <p>
|
||||
* Rather than manually creating the file, it is recommended to data-generators to generate this file. This can be done
|
||||
* with {@link TurtleUpgradeDataProvider}.
|
||||
*
|
||||
* {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body}
|
||||
*
|
||||
* @see TurtleUpgradeSerialiser Registering a turtle upgrade.
|
||||
* @see TurtleUpgradeSerialiser For how to register a turtle upgrade.
|
||||
*/
|
||||
public interface ITurtleUpgrade extends UpgradeBase {
|
||||
/**
|
||||
|
@@ -29,9 +29,6 @@ import java.util.function.Consumer;
|
||||
* {@link #addUpgrades(Consumer)} function, construct each upgrade, and pass them off to the provided consumer to
|
||||
* generate them.
|
||||
*
|
||||
* <h2>Example</h2>
|
||||
* {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body}
|
||||
*
|
||||
* @see TurtleUpgradeSerialiser
|
||||
*/
|
||||
public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITurtleUpgrade, TurtleUpgradeSerialiser<?>> {
|
||||
|
@@ -27,6 +27,32 @@ import java.util.function.Function;
|
||||
* If your turtle upgrade doesn't have any associated configurable parameters (like most upgrades), you can use
|
||||
* {@link #simple(Function)} or {@link #simpleWithCustomItem(BiFunction)} to create a basic upgrade serialiser.
|
||||
*
|
||||
* <h2>Example (Forge)</h2>
|
||||
* <pre>{@code
|
||||
* static final DeferredRegister<TurtleUpgradeSerialiser<?>> SERIALISERS = DeferredRegister.create( TurtleUpgradeSerialiser.TYPE, "my_mod" );
|
||||
*
|
||||
* // Register a new upgrade serialiser called "my_upgrade".
|
||||
* public static final RegistryObject<TurtleUpgradeSerialiser<MyUpgrade>> MY_UPGRADE =
|
||||
* SERIALISERS.register( "my_upgrade", () -> TurtleUpgradeSerialiser.simple( MyUpgrade::new ) );
|
||||
*
|
||||
* // Then in your constructor
|
||||
* SERIALISERS.register( bus );
|
||||
* }</pre>
|
||||
* <p>
|
||||
* We can then define a new upgrade using JSON by placing the following in
|
||||
* {@literal data/<my_mod>/computercraft/turtle_upgrades/<my_upgrade_id>.json}}.
|
||||
*
|
||||
* <pre>{@code
|
||||
* {
|
||||
* "type": my_mod:my_upgrade",
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Finally, we need to register a model for our upgrade. The way to do this varies on mod loader, see
|
||||
* {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for more information.
|
||||
* <p>
|
||||
* {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files.
|
||||
*
|
||||
* @param <T> The type of turtle upgrade this is responsible for serialising.
|
||||
* @see ITurtleUpgrade
|
||||
* @see TurtleUpgradeDataProvider
|
||||
|
@@ -32,8 +32,6 @@ import java.util.function.Function;
|
||||
*
|
||||
* @param <T> The base class of upgrades.
|
||||
* @param <R> The upgrade serialiser to register for.
|
||||
* @see dan200.computercraft.api.turtle.TurtleUpgradeDataProvider
|
||||
* @see dan200.computercraft.api.pocket.PocketUpgradeDataProvider
|
||||
*/
|
||||
public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends UpgradeSerialiser<? extends T>> implements DataProvider {
|
||||
private final PackOutput output;
|
||||
@@ -86,9 +84,13 @@ public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends Upgra
|
||||
|
||||
/**
|
||||
* Add all turtle or pocket computer upgrades.
|
||||
*
|
||||
* <h4>Example</h4>
|
||||
* {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body}
|
||||
* <p>
|
||||
* <strong>Example usage:</strong>
|
||||
* <pre>{@code
|
||||
* protected void addUpgrades(Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> addUpgrade) {
|
||||
* simple(new ResourceLocation("mymod", "speaker"), SPEAKER_SERIALISER.get()).add(addUpgrade);
|
||||
* }
|
||||
* }</pre>
|
||||
*
|
||||
* @param addUpgrade A callback used to register an upgrade.
|
||||
*/
|
||||
|
@@ -1,68 +0,0 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<p>
|
||||
This is the documentation for CC: Tweaked $modVersion for Minecraft $mcVersion. Documentation for other versions of
|
||||
Minecraft are available on the CC: Tweaked website:
|
||||
|
||||
<ul>
|
||||
<li><a href="/mc-1.20.x/javadoc/">Minecraft 1.20.1</a>
|
||||
<li><a href="/mc-1.21.x/javadoc/">Minecraft 1.21.1</a>
|
||||
</ul>
|
||||
|
||||
<h1>Quick links</h1>
|
||||
<p>
|
||||
You probably want to start in the following places:
|
||||
|
||||
<ul>
|
||||
<li>{@linkplain dan200.computercraft.api.peripheral Registering new peripherals}</li>
|
||||
<li>
|
||||
{@link dan200.computercraft.api.lua.LuaFunction} and {@link dan200.computercraft.api.lua.IArguments} for
|
||||
adding methods to your peripheral or Lua objects.
|
||||
</li>
|
||||
<li>{@linkplain dan200.computercraft.api.turtle.ITurtleUpgrade Turtle upgrades}</li>
|
||||
<li>{@linkplain dan200.computercraft.api.pocket.IPocketUpgrade Pocket upgrades}</li>
|
||||
</ul>
|
||||
|
||||
<h1>Using</h1>
|
||||
<p>
|
||||
CC: Tweaked is hosted on my maven repo, and so is relatively simple to depend on. You may wish to add a soft (or
|
||||
hard) dependency in your <code>mods.toml</code> file, with the appropriate version bounds, to ensure that API
|
||||
functionality you depend on is present.
|
||||
|
||||
<pre class="language language-groovy"><code>repositories {
|
||||
maven {
|
||||
url "https://maven.squiddev.cc"
|
||||
content { includeGroup("cc.tweaked") }
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Vanilla (i.e. for multi-loader systems)
|
||||
compileOnly("cc.tweaked:cc-tweaked-$mcVersion-common-api:$modVersion")
|
||||
|
||||
// Forge Gradle
|
||||
compileOnly("cc.tweaked:cc-tweaked-$mcVersion-core-api:$modVersion")
|
||||
compileOnly(fg.deobf("cc.tweaked:cc-tweaked-$mcVersion-forge-api:$modVersion"))
|
||||
runtimeOnly(fg.deobf("cc.tweaked:cc-tweaked-$mcVersion-forge:$modVersion"))
|
||||
|
||||
// Fabric Loom
|
||||
modCompileOnly("cc.tweaked:cc-tweaked-$mcVersion-fabric-api:$modVersion")
|
||||
modRuntimeOnly("cc.tweaked:cc-tweaked-$mcVersion-fabric:$modVersion")
|
||||
}
|
||||
</code></pre>
|
||||
|
||||
<p>
|
||||
You should also be careful to only use classes within the <code>dan200.computercraft.api</code> package. Non-API
|
||||
classes are subject to change at any point. If you depend on functionality outside the API (or need to mixin to
|
||||
CC:T), please <a href="https://github.com/cc-tweaked/CC-Tweaked/discussions/new/choose">start a discussion</a> to
|
||||
let me know!
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -6,11 +6,17 @@ 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")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources.srcDir("src/generated/resources")
|
||||
}
|
||||
}
|
||||
|
||||
minecraft {
|
||||
accessWideners(
|
||||
"src/main/resources/computercraft.accesswidener",
|
||||
@@ -61,7 +67,7 @@ dependencies {
|
||||
}
|
||||
|
||||
illuaminate {
|
||||
version = libs.versions.illuaminate
|
||||
version.set(libs.versions.illuaminate)
|
||||
}
|
||||
|
||||
val luaJavadoc by tasks.registering(Javadoc::class) {
|
||||
@@ -82,7 +88,11 @@ 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.set(
|
||||
javaToolchains.javadocToolFor {
|
||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val lintLua by tasks.registering(IlluaminateExec::class) {
|
||||
@@ -103,31 +113,20 @@ val lintLua by tasks.registering(IlluaminateExec::class) {
|
||||
doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
|
||||
}
|
||||
|
||||
fun MergeTrees.configureForDatagen(source: SourceSet, outputFolder: String) {
|
||||
output = layout.projectDirectory.dir(outputFolder)
|
||||
val runData by tasks.registering(MergeTrees::class) {
|
||||
output = layout.projectDirectory.dir("src/generated/resources")
|
||||
|
||||
for (loader in listOf("forge", "fabric")) {
|
||||
mustRunAfter(":$loader:$name")
|
||||
mustRunAfter(":$loader:runData")
|
||||
source {
|
||||
input {
|
||||
from(project(":$loader").layout.buildDirectory.dir(source.getTaskName("generateResources", null)))
|
||||
from(project(":$loader").layout.buildDirectory.dir("generatedResources"))
|
||||
exclude(".cache")
|
||||
}
|
||||
|
||||
output = project(":$loader").layout.projectDirectory.dir(outputFolder)
|
||||
output = project(":$loader").layout.projectDirectory.dir("src/generated/resources")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val runData by tasks.registering(MergeTrees::class) {
|
||||
configureForDatagen(sourceSets.main.get(), "src/generated/resources")
|
||||
}
|
||||
|
||||
val runExampleData by tasks.registering(MergeTrees::class) {
|
||||
configureForDatagen(sourceSets.examples.get(), "src/examples/generatedResources")
|
||||
}
|
||||
|
||||
// We can't create accurate module metadata for our additional capabilities, so disable it.
|
||||
project.tasks.withType(GenerateModuleMetadata::class.java).configureEach {
|
||||
isEnabled = false
|
||||
}
|
||||
tasks.withType(GenerateModuleMetadata::class).configureEach { isEnabled = false }
|
||||
|
@@ -64,9 +64,6 @@ public final class ClientHooks {
|
||||
public static void onWorldUnload() {
|
||||
MonitorRenderState.destroyAll();
|
||||
SpeakerManager.reset();
|
||||
}
|
||||
|
||||
public static void onDisconnect() {
|
||||
ClientPocketComputers.reset();
|
||||
}
|
||||
|
||||
|
@@ -10,10 +10,10 @@ import dan200.computercraft.shared.computer.menu.ComputerMenu;
|
||||
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
|
||||
import dan200.computercraft.shared.network.server.KeyEventServerMessage;
|
||||
import dan200.computercraft.shared.network.server.MouseEventServerMessage;
|
||||
import dan200.computercraft.shared.network.server.PasteEventComputerMessage;
|
||||
import dan200.computercraft.shared.network.server.QueueEventServerMessage;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An {@link InputHandler} for use on the client.
|
||||
@@ -27,11 +27,6 @@ public final class ClientInputHandler implements InputHandler {
|
||||
this.menu = menu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void terminate() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TERMINATE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void turnOn() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
|
||||
@@ -47,6 +42,11 @@ public final class ClientInputHandler implements InputHandler {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueEvent(String event, @Nullable Object[] arguments) {
|
||||
ClientNetworking.sendToServer(new QueueEventServerMessage(menu, event, arguments));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown(int key, boolean repeat) {
|
||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.Action.REPEAT : KeyEventServerMessage.Action.DOWN, key));
|
||||
@@ -57,16 +57,6 @@ public final class ClientInputHandler implements InputHandler {
|
||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.Action.UP, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void charTyped(byte chr) {
|
||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.Action.CHAR, chr));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paste(ByteBuffer contents) {
|
||||
ClientNetworking.sendToServer(new PasteEventComputerMessage(menu, contents));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClick(int button, int x, int y) {
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.CLICK, button, x, y));
|
||||
|
@@ -6,6 +6,7 @@ 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;
|
||||
@@ -32,13 +33,10 @@ public final class GuiSprites extends TextureAtlasHolder {
|
||||
public static final ComputerTextures COMPUTER_COMMAND = computer("command", false, true);
|
||||
public static final ComputerTextures COMPUTER_COLOUR = computer("colour", true, false);
|
||||
|
||||
public static final ResourceLocation TURTLE_NORMAL_SELECTED_SLOT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/sprites/turtle_normal_selected_slot");
|
||||
public static final ResourceLocation TURTLE_ADVANCED_SELECTED_SLOT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/sprites/turtle_advanced_selected_slot");
|
||||
|
||||
private static ButtonTextures button(String name) {
|
||||
return new ButtonTextures(
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/sprites/buttons/" + name),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/sprites/buttons/" + name + "_hover")
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/buttons/" + name),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/buttons/" + name + "_hover")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -115,6 +113,7 @@ 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,
|
||||
|
@@ -54,9 +54,9 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
|
||||
if (slot >= 0) {
|
||||
var slotX = slot % 4;
|
||||
var slotY = slot / 4;
|
||||
graphics.blit(
|
||||
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, 0, 22, 22,
|
||||
GuiSprites.get(advanced ? GuiSprites.TURTLE_ADVANCED_SELECTED_SLOT : GuiSprites.TURTLE_NORMAL_SELECTED_SLOT)
|
||||
graphics.blit(texture,
|
||||
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, 0,
|
||||
0, 217, 24, 24, FULL_TEX_SIZE, FULL_TEX_SIZE
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -55,7 +55,7 @@ public final class ComputerSidebar {
|
||||
add.accept(new DynamicImageButton(
|
||||
x, y, ICON_WIDTH, ICON_HEIGHT,
|
||||
GuiSprites.TERMINATE::get,
|
||||
b -> input.terminate(),
|
||||
b -> input.queueEvent("terminate"),
|
||||
new HintedMessage(
|
||||
Component.translatable("gui.computercraft.tooltip.terminate"),
|
||||
Component.translatable("gui.computercraft.tooltip.terminate.key")
|
||||
|
@@ -71,8 +71,11 @@ public class TerminalWidget extends AbstractWidget {
|
||||
|
||||
@Override
|
||||
public boolean charTyped(char ch, int modifiers) {
|
||||
var terminalChar = StringUtil.unicodeToTerminal(ch);
|
||||
if (StringUtil.isTypableChar(terminalChar)) computer.charTyped(terminalChar);
|
||||
if (ch >= 32 && ch <= 126 || ch >= 160 && ch <= 255) {
|
||||
// Queue the char event for any printable chars in byte range
|
||||
computer.queueEvent("char", new Object[]{ Character.toString(ch) });
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -109,8 +112,8 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
private void paste() {
|
||||
var clipboard = StringUtil.getClipboardString(Minecraft.getInstance().keyboardHandler.getClipboard());
|
||||
if (clipboard.remaining() > 0) computer.paste(clipboard);
|
||||
var clipboard = StringUtil.normaliseClipboardString(Minecraft.getInstance().keyboardHandler.getClipboard());
|
||||
if (!clipboard.isEmpty()) computer.queueEvent("paste", new Object[]{ clipboard });
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -219,7 +222,7 @@ public class TerminalWidget extends AbstractWidget {
|
||||
|
||||
public void update() {
|
||||
if (terminateTimer >= 0 && terminateTimer < TERMINATE_TIME && (terminateTimer += 0.05f) > TERMINATE_TIME) {
|
||||
computer.terminate();
|
||||
computer.queueEvent("terminate");
|
||||
}
|
||||
|
||||
if (shutdownTimer >= 0 && shutdownTimer < TERMINATE_TIME && (shutdownTimer += 0.05f) > TERMINATE_TIME) {
|
||||
|
@@ -56,4 +56,8 @@ public final class ClientPocketComputers {
|
||||
var id = PocketComputerItem.getInstanceID(stack);
|
||||
return id == null ? null : instances.get(id);
|
||||
}
|
||||
|
||||
static @Nullable PocketComputerData get(UUID id) {
|
||||
return instances.get(id);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,101 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.pocket;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.gui.GuiSprites;
|
||||
import dan200.computercraft.client.render.ComputerBorderRenderer;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.client.render.SpriteRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||
import dan200.computercraft.shared.pocket.items.PocketTooltipComponent;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.UUID;
|
||||
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.BORDER;
|
||||
import static dan200.computercraft.client.render.ComputerBorderRenderer.MARGIN;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
|
||||
/**
|
||||
* Renders the pocket computer's terminal in the item's tooltip.
|
||||
* <p>
|
||||
* The rendered terminal is downscaled by a factor of {@link #SCALE}.
|
||||
*/
|
||||
public class PocketClientTooltipComponent implements ClientTooltipComponent {
|
||||
private static final float SCALE = 0.5f;
|
||||
|
||||
private final UUID id;
|
||||
private final ComputerFamily family;
|
||||
|
||||
public PocketClientTooltipComponent(PocketTooltipComponent component) {
|
||||
this.id = component.id();
|
||||
this.family = component.family();
|
||||
}
|
||||
|
||||
private @Nullable PocketComputerData computer() {
|
||||
return ClientPocketComputers.get(id);
|
||||
}
|
||||
|
||||
private @Nullable NetworkedTerminal terminal() {
|
||||
var computer = computer();
|
||||
return computer == null ? null : computer.getTerminal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
var terminal = terminal();
|
||||
if (terminal == null) return 0;
|
||||
|
||||
return (int) Math.ceil(
|
||||
(terminal.getHeight() * FixedWidthFontRenderer.FONT_HEIGHT + ComputerBorderRenderer.BORDER * 2 + ComputerBorderRenderer.MARGIN * 2) * SCALE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth(Font font) {
|
||||
var terminal = terminal();
|
||||
if (terminal == null) return 0;
|
||||
|
||||
return (int) Math.ceil(
|
||||
(terminal.getWidth() * FixedWidthFontRenderer.FONT_WIDTH + ComputerBorderRenderer.BORDER * 2 + ComputerBorderRenderer.MARGIN * 2) * SCALE
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderImage(Font font, int x, int y, GuiGraphics guiGraphics) {
|
||||
var terminal = terminal();
|
||||
if (terminal == null) return;
|
||||
|
||||
var pose = guiGraphics.pose();
|
||||
pose.pushPose();
|
||||
pose.translate(x, y, 0);
|
||||
pose.scale(SCALE, SCALE, 1);
|
||||
|
||||
|
||||
render(pose, guiGraphics.bufferSource(), terminal);
|
||||
|
||||
pose.popPose();
|
||||
}
|
||||
|
||||
private void render(PoseStack stack, MultiBufferSource buffers, Terminal terminal) {
|
||||
var width = terminal.getWidth() * FONT_WIDTH + MARGIN * 2;
|
||||
var height = terminal.getHeight() * FONT_HEIGHT + MARGIN * 2;
|
||||
|
||||
var renderer = SpriteRenderer.createForGui(stack.last().pose(), buffers.getBuffer(RenderTypes.GUI_SPRITES));
|
||||
ComputerBorderRenderer.render(renderer, GuiSprites.getComputerTextures(family), BORDER, BORDER, width, height, false);
|
||||
|
||||
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(stack, buffers.getBuffer(RenderTypes.TERMINAL));
|
||||
FixedWidthFontRenderer.drawTerminal(quadEmitter, BORDER + MARGIN, BORDER + MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
||||
}
|
||||
}
|
@@ -38,8 +38,8 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
||||
|
||||
int termWidth, termHeight;
|
||||
if (terminal == null) {
|
||||
termWidth = Config.DEFAULT_POCKET_TERM_WIDTH;
|
||||
termHeight = Config.DEFAULT_POCKET_TERM_HEIGHT;
|
||||
termWidth = Config.pocketTermWidth;
|
||||
termHeight = Config.pocketTermHeight;
|
||||
} else {
|
||||
termWidth = terminal.getWidth();
|
||||
termHeight = terminal.getHeight();
|
||||
|
@@ -34,11 +34,12 @@ public class SpriteRenderer {
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public static SpriteRenderer createForGui(Matrix4f transform, VertexConsumer builder) {
|
||||
return new SpriteRenderer(transform, builder, 0, RenderTypes.FULL_BRIGHT_LIGHTMAP, 255, 255, 255);
|
||||
}
|
||||
|
||||
public static SpriteRenderer createForGui(GuiGraphics graphics, RenderType renderType) {
|
||||
return new SpriteRenderer(
|
||||
graphics.pose().last().pose(), graphics.bufferSource().getBuffer(renderType),
|
||||
0, RenderTypes.FULL_BRIGHT_LIGHTMAP, 255, 255, 255
|
||||
);
|
||||
return createForGui(graphics.pose().last().pose(), graphics.bufferSource().getBuffer(renderType));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -176,7 +176,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
var size = DirectFixedWidthFontRenderer.getVertexCount(terminal);
|
||||
|
||||
// In an ideal world we could upload these both into one buffer. However, we can't render VBOs with
|
||||
// a starting and ending offset, and so need to use two buffers instead.
|
||||
// and starting and ending offset, and so need to use two buffers instead.
|
||||
|
||||
renderToBuffer(backgroundBuffer, size, sink ->
|
||||
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
|
||||
@@ -208,10 +208,10 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
foregroundBuffer.bind();
|
||||
foregroundBuffer.drawWithShader(
|
||||
matrix, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(),
|
||||
// Skip the cursor quad if it is not visible this frame.
|
||||
FixedWidthFontRenderer.isCursorVisible(terminal) && !FrameInfo.getGlobalCursorBlink()
|
||||
? foregroundBuffer.getIndexCount() - RenderTypes.TERMINAL.mode().indexCount(4)
|
||||
: foregroundBuffer.getIndexCount()
|
||||
// As mentioned in the above comment, render the extra cursor quad if it is visible this frame. Each
|
||||
// // quad has an index count of 6.
|
||||
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
|
||||
? foregroundBuffer.getIndexCount() + 6 : foregroundBuffer.getIndexCount()
|
||||
);
|
||||
|
||||
// Clear state
|
||||
|
@@ -0,0 +1,50 @@
|
||||
// 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.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.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A version of {@link DataProviders} which relies on client-side classes.
|
||||
* <p>
|
||||
* This is called from {@link DataProviders#add(DataProviders.GeneratorSink)}.
|
||||
*/
|
||||
public final class ClientDataProviders {
|
||||
private ClientDataProviders() {
|
||||
}
|
||||
|
||||
public static void add(DataProviders.GeneratorSink generator) {
|
||||
generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
|
||||
out.accept(new ResourceLocation("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).<SpriteSource>map(x -> new SingleFile(x, Optional.empty())).toList());
|
||||
});
|
||||
}
|
||||
}
|
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"type": "examplemod:example_turtle_upgrade",
|
||||
"item": "minecraft:compass"
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
package com.example.examplemod;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.component.ComputerComponents;
|
||||
import dan200.computercraft.api.lua.Coerced;
|
||||
import dan200.computercraft.api.lua.ILuaAPI;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An example API that will be available on every turtle. This demonstrates both registering an API, and how to write
|
||||
* Lua-facing functions.
|
||||
* <p>
|
||||
* This API is not available as a global (as {@link #getNames() returns nothing}), but is instead accessible via
|
||||
* {@code require} (see {@link #getModuleName()}).
|
||||
*
|
||||
* <h2>Example</h2>
|
||||
* <pre class="language language-lua">{@code
|
||||
* local my_api = require("example.my_api")
|
||||
* print("Turtle is facing " .. my_api.getDirection())
|
||||
* }</pre>
|
||||
*/
|
||||
public class ExampleAPI implements ILuaAPI {
|
||||
private final ITurtleAccess turtle;
|
||||
|
||||
public ExampleAPI(ITurtleAccess turtle) {
|
||||
this.turtle = turtle;
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
// @start region=register
|
||||
ComputerCraftAPI.registerAPIFactory(computer -> {
|
||||
// Read the turtle component.
|
||||
var turtle = computer.getComponent(ComputerComponents.TURTLE);
|
||||
// If present then add our API.
|
||||
return turtle == null ? null : new ExampleAPI(turtle);
|
||||
});
|
||||
// @end region=register
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getNames() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String getModuleName() {
|
||||
return "example.my_api";
|
||||
}
|
||||
|
||||
/**
|
||||
* A Lua-facing function function that returns the direction the turtle is facing.
|
||||
*
|
||||
* @return The turtle's direction.
|
||||
*/
|
||||
@LuaFunction
|
||||
public final String getDirection() {
|
||||
return turtle.getDirection().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* A Lua-facing function using {@link Coerced}. Unlike a {@link LuaFunction} taking a raw {@link String}, this will
|
||||
* accept any value, and convert it to a string.
|
||||
*
|
||||
* @param myString The value to write.
|
||||
*/
|
||||
// @start region=coerced
|
||||
@LuaFunction
|
||||
public final void writeString(Coerced<String> myString) {
|
||||
String contents = myString.value();
|
||||
System.out.println("Got " + contents);
|
||||
}
|
||||
// @end region=coerced
|
||||
}
|
@@ -1,39 +0,0 @@
|
||||
package com.example.examplemod;
|
||||
|
||||
import com.example.examplemod.data.TurtleDataProvider;
|
||||
import com.example.examplemod.peripheral.FurnacePeripheral;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||
|
||||
/**
|
||||
* Our example mod, containing the various things we register.
|
||||
* <p>
|
||||
* This isn't an especially good template to follow! It's convenient for our example mod (as we need to be multi-loader
|
||||
* compatible), but there's a good chance there's a better pattern to follow. For example, on Forge you'd use
|
||||
* {@code DeferredRegister} to register things), and multi-loader mods probably have their own abstractions.
|
||||
* <p>
|
||||
* See {@code FabricExampleMod} and {@code ForgeExampleMod} for the actual mod entrypoints.
|
||||
*/
|
||||
public final class ExampleMod {
|
||||
public static final String MOD_ID = "examplemod";
|
||||
|
||||
/**
|
||||
* The upgrade serialiser for our example turtle upgrade. See the documentation for {@link TurtleUpgradeSerialiser}
|
||||
* or {@code FabricExampleMod}/{@code ForgeExampleMod} for how this is registered.
|
||||
* <p>
|
||||
* This only defines the upgrade type. See {@link TurtleDataProvider} for defining the actual upgrade.
|
||||
*/
|
||||
// @start region=turtle_upgrades
|
||||
public static final TurtleUpgradeSerialiser<ExampleTurtleUpgrade> EXAMPLE_TURTLE_UPGRADE = TurtleUpgradeSerialiser.simpleWithCustomItem(
|
||||
ExampleTurtleUpgrade::new
|
||||
);
|
||||
// @end region=turtle_upgrades
|
||||
|
||||
public static void registerComputerCraft() {
|
||||
// @start region=generic_source
|
||||
ComputerCraftAPI.registerGenericSource(new FurnacePeripheral());
|
||||
// @end region=generic_source
|
||||
|
||||
ExampleAPI.register();
|
||||
}
|
||||
}
|
@@ -1,17 +0,0 @@
|
||||
package com.example.examplemod;
|
||||
|
||||
import dan200.computercraft.api.turtle.AbstractTurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
/**
|
||||
* An example turtle upgrade.
|
||||
*/
|
||||
// @start region=body
|
||||
public class ExampleTurtleUpgrade extends AbstractTurtleUpgrade {
|
||||
public ExampleTurtleUpgrade(ResourceLocation id, ItemStack stack) {
|
||||
super(id, TurtleUpgradeType.PERIPHERAL, stack);
|
||||
}
|
||||
}
|
||||
// @end region=body
|
@@ -1,17 +0,0 @@
|
||||
package com.example.examplemod.data;
|
||||
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.DataProvider;
|
||||
|
||||
/**
|
||||
* The entry point to example mod's data-generators.
|
||||
* <p>
|
||||
* This is called by our platform-specific entry-point (see {@code FabricExampleModDataGenerator} and
|
||||
* {@code ForgeExampleModDataGenerator}. That said, the exact setup isn't relevant (it will vary depending on
|
||||
* mod-loader), what's interesting is the contents of the {@link #run(DataGenerator.PackGenerator)} method!
|
||||
*/
|
||||
public final class ExampleModDataGenerators {
|
||||
public static void run(DataGenerator.PackGenerator pack) {
|
||||
pack.addProvider((DataProvider.Factory<?>) TurtleDataProvider::new);
|
||||
}
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
package com.example.examplemod.data;
|
||||
|
||||
import com.example.examplemod.ExampleMod;
|
||||
import com.example.examplemod.ExampleTurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeDataProvider;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A {@link TurtleUpgradeDataProvider} that generates the JSON for our {@linkplain ExampleTurtleUpgrade example
|
||||
* upgrade}.
|
||||
*
|
||||
* @see ExampleModDataGenerators
|
||||
*/
|
||||
// @start region=body
|
||||
public class TurtleDataProvider extends TurtleUpgradeDataProvider {
|
||||
public TurtleDataProvider(PackOutput output) {
|
||||
super(output);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addUpgrades(Consumer<Upgrade<TurtleUpgradeSerialiser<?>>> addUpgrade) {
|
||||
simpleWithCustomItem(
|
||||
new ResourceLocation(ExampleMod.MOD_ID, "example_turtle_upgrade"),
|
||||
ExampleMod.EXAMPLE_TURTLE_UPGRADE,
|
||||
Items.COMPASS
|
||||
).add(addUpgrade);
|
||||
}
|
||||
}
|
||||
// @end region=body
|
@@ -1,12 +0,0 @@
|
||||
@ApiStatus.Internal
|
||||
@DefaultQualifier(value = NonNull.class, locations = {
|
||||
TypeUseLocation.RETURN,
|
||||
TypeUseLocation.PARAMETER,
|
||||
TypeUseLocation.FIELD,
|
||||
})
|
||||
package com.example.examplemod;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
import org.checkerframework.framework.qual.TypeUseLocation;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
@@ -1,39 +0,0 @@
|
||||
package com.example.examplemod.peripheral;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A peripheral that adds a {@code getFuel()} method to brewing stands. This demonstrates the usage of
|
||||
* {@link IPeripheral}.
|
||||
*
|
||||
* @see dan200.computercraft.api.peripheral
|
||||
* @see FurnacePeripheral Using {@code GenericPeripheral}.
|
||||
*/
|
||||
// @start region=body
|
||||
public class BrewingStandPeripheral implements IPeripheral {
|
||||
private final BrewingStandBlockEntity brewingStand;
|
||||
|
||||
public BrewingStandPeripheral(BrewingStandBlockEntity brewingStand) {
|
||||
this.brewingStand = brewingStand;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "brewing_stand";
|
||||
}
|
||||
|
||||
@LuaFunction
|
||||
public final int getFuel() {
|
||||
// Don't do it this way! Use an access widener/transformer to access the "fuel" field instead.
|
||||
return brewingStand.saveWithoutMetadata().getInt("Fuel");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable IPeripheral other) {
|
||||
return other instanceof BrewingStandPeripheral o && brewingStand == o.brewingStand;
|
||||
}
|
||||
}
|
||||
// @end region=body
|
@@ -1,44 +0,0 @@
|
||||
package com.example.examplemod.peripheral;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.AttachedComputerSet;
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A peripheral that tracks what computers it is attached to.
|
||||
*
|
||||
* @see AttachedComputerSet
|
||||
*/
|
||||
// @start region=body
|
||||
public class ComputerTrackingPeripheral implements IPeripheral {
|
||||
private final AttachedComputerSet computers = new AttachedComputerSet();
|
||||
|
||||
@Override
|
||||
public void attach(IComputerAccess computer) {
|
||||
computers.add(computer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach(IComputerAccess computer) {
|
||||
computers.remove(computer);
|
||||
}
|
||||
|
||||
@LuaFunction
|
||||
public final void sayHello() {
|
||||
// Queue a "hello" event on each computer.
|
||||
computers.forEach(x -> x.queueEvent("hello", x.getAttachmentName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return "my_peripheral";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable IPeripheral other) {
|
||||
return this == other;
|
||||
}
|
||||
}
|
||||
// @end region=body
|
@@ -1,29 +0,0 @@
|
||||
package com.example.examplemod.peripheral;
|
||||
|
||||
import com.example.examplemod.ExampleMod;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import dan200.computercraft.api.peripheral.GenericPeripheral;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
|
||||
|
||||
/**
|
||||
* A peripheral that adds a {@code getBurnTime} method to furnaces. This is used to demonstrate the usage of
|
||||
* {@link GenericPeripheral}.
|
||||
*
|
||||
* @see dan200.computercraft.api.peripheral
|
||||
* @see BrewingStandPeripheral Using {@code IPeripheral}.
|
||||
*/
|
||||
// @start region=body
|
||||
public class FurnacePeripheral implements GenericPeripheral {
|
||||
@Override
|
||||
public String id() {
|
||||
return new ResourceLocation(ExampleMod.MOD_ID, "furnace").toString();
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public int getBurnTime(AbstractFurnaceBlockEntity furnace) {
|
||||
// Don't do it this way! Use an access widener/transformer to access the "litTime" field instead.
|
||||
return furnace.saveWithoutMetadata().getInt("BurnTime");
|
||||
}
|
||||
}
|
||||
// @end region=body
|
@@ -1,13 +1,11 @@
|
||||
{
|
||||
"sources": [
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/turtle_normal_selected_slot"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/turtle_advanced_selected_slot"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/buttons/turned_off"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/buttons/turned_off_hover"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/buttons/turned_on"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/buttons/turned_on_hover"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/buttons/terminate"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sprites/buttons/terminate_hover"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_off"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_off_hover"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_on"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/turned_on_hover"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/terminate"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/buttons/terminate_hover"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/border_normal"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/pocket_bottom_normal"},
|
||||
{"type": "minecraft:single", "resource": "computercraft:gui/sidebar_normal"},
|
||||
|
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"variants": {
|
||||
"facing=east": {"model": "computercraft:block/redstone_relay", "y": 90},
|
||||
"facing=north": {"model": "computercraft:block/redstone_relay", "y": 0},
|
||||
"facing=south": {"model": "computercraft:block/redstone_relay", "y": 180},
|
||||
"facing=west": {"model": "computercraft:block/redstone_relay", "y": 270}
|
||||
}
|
||||
}
|
@@ -17,7 +17,6 @@
|
||||
"block.computercraft.monitor_advanced": "Advanced Monitor",
|
||||
"block.computercraft.monitor_normal": "Monitor",
|
||||
"block.computercraft.printer": "Printer",
|
||||
"block.computercraft.redstone_relay": "Redstone Relay",
|
||||
"block.computercraft.speaker": "Speaker",
|
||||
"block.computercraft.turtle_advanced": "Advanced Turtle",
|
||||
"block.computercraft.turtle_advanced.upgraded": "Advanced %s Turtle",
|
||||
@@ -83,35 +82,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.",
|
||||
"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.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.",
|
||||
"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_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.",
|
||||
"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.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).",
|
||||
"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_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).",
|
||||
"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.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.",
|
||||
"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_websockets": "Maximum concurrent websockets",
|
||||
"gui.computercraft.config.http.max_websockets.tooltip": "The number of websockets a computer can have open at one time.",
|
||||
"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.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.",
|
||||
"gui.computercraft.config.http.proxy.port.tooltip": "The port of the proxy server.\nRange: 1 ~ 65536",
|
||||
"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.",
|
||||
"gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5",
|
||||
"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 +119,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.",
|
||||
"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.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.",
|
||||
"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_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.",
|
||||
"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.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.",
|
||||
"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.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.",
|
||||
"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_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.",
|
||||
"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_range": "Modem range (default)",
|
||||
"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.tooltip": "The range of Wireless Modems at low altitude in clear weather, in meters.\nRange: 0 ~ 100000",
|
||||
"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.",
|
||||
"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.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.",
|
||||
"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.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": "Height of computer terminal",
|
||||
"gui.computercraft.config.term_sizes.computer.height.tooltip": "Range: 1 ~ 255",
|
||||
"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": "Width of computer terminal",
|
||||
"gui.computercraft.config.term_sizes.computer.width.tooltip": "Range: 1 ~ 255",
|
||||
"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": "Maximum height of monitors",
|
||||
"gui.computercraft.config.term_sizes.monitor.height.tooltip": "Range: 1 ~ 32",
|
||||
"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": "Maximum width of monitors",
|
||||
"gui.computercraft.config.term_sizes.monitor.width.tooltip": "Range: 1 ~ 32",
|
||||
"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": "Height of pocket computer terminal",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "Range: 1 ~ 255",
|
||||
"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": "Width of pocket computer terminal",
|
||||
"gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "Range: 1 ~ 255",
|
||||
"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.",
|
||||
"gui.computercraft.config.turtle.advanced_fuel_limit.tooltip": "The fuel limit for Advanced Turtles.\nRange: > 0",
|
||||
"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.",
|
||||
"gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "The fuel limit for Turtles.\nRange: > 0",
|
||||
"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!",
|
||||
"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_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.",
|
||||
"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.pocket_computer_overlay": "Pocket computer open. Press ESC to close.",
|
||||
"gui.computercraft.terminal": "Computer terminal",
|
||||
"gui.computercraft.tooltip.computer_id": "Computer ID: %s",
|
||||
|
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"parent": "minecraft:block/orientable_with_bottom",
|
||||
"textures": {
|
||||
"bottom": "computercraft:block/redstone_relay_bottom",
|
||||
"front": "computercraft:block/redstone_relay_front",
|
||||
"side": "computercraft:block/redstone_relay_side",
|
||||
"top": "computercraft:block/redstone_relay_top"
|
||||
}
|
||||
}
|
@@ -1 +0,0 @@
|
||||
{"parent": "computercraft:block/redstone_relay"}
|
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"parent": "minecraft:recipes/root",
|
||||
"criteria": {
|
||||
"has_cable": {
|
||||
"conditions": {"items": [{"items": ["computercraft:wired_modem"]}]},
|
||||
"trigger": "minecraft:inventory_changed"
|
||||
},
|
||||
"has_the_recipe": {
|
||||
"conditions": {"recipe": "computercraft:redstone_relay"},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
}
|
||||
},
|
||||
"requirements": [["has_cable", "has_the_recipe"]],
|
||||
"rewards": {"recipes": ["computercraft:redstone_relay"]},
|
||||
"sends_telemetry_event": false
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"type": "minecraft:block",
|
||||
"pools": [
|
||||
{
|
||||
"bonus_rolls": 0.0,
|
||||
"conditions": [{"condition": "minecraft:survives_explosion"}],
|
||||
"entries": [{"type": "minecraft:item", "name": "computercraft:redstone_relay"}],
|
||||
"rolls": 1.0
|
||||
}
|
||||
],
|
||||
"random_sequence": "computercraft:blocks/redstone_relay"
|
||||
}
|
@@ -97,8 +97,6 @@ class BlockModelProvider {
|
||||
|
||||
registerCable(generators);
|
||||
|
||||
registerRedstoneControl(generators);
|
||||
|
||||
registerTurtleUpgrade(generators, "block/turtle_crafting_table", "block/turtle_crafty_face");
|
||||
registerTurtleUpgrade(generators, "block/turtle_speaker", "block/turtle_speaker_face");
|
||||
registerTurtleModem(generators, "block/turtle_modem_normal", "block/wireless_modem_normal_face");
|
||||
@@ -357,18 +355,6 @@ class BlockModelProvider {
|
||||
generators.blockStateOutput.accept(generator);
|
||||
}
|
||||
|
||||
private static void registerRedstoneControl(BlockModelGenerators generators) {
|
||||
var redstoneControl = ModRegistry.Blocks.REDSTONE_RELAY.get();
|
||||
var model = ModelTemplates.CUBE_ORIENTABLE_TOP_BOTTOM.create(
|
||||
redstoneControl, TextureMapping.orientableCube(redstoneControl), generators.modelOutput
|
||||
);
|
||||
generators.blockStateOutput.accept(
|
||||
MultiVariantGenerator.multiVariant(redstoneControl, Variant.variant().with(VariantProperties.MODEL, model))
|
||||
.with(createHorizontalFacingDispatch())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static final BooleanProperty[] CABLE_DIRECTIONS = { CableBlock.DOWN, CableBlock.UP, CableBlock.NORTH, CableBlock.SOUTH, CableBlock.WEST, CableBlock.EAST };
|
||||
private static final boolean[] BOOLEANS = new boolean[]{ false, true };
|
||||
|
@@ -5,12 +5,6 @@
|
||||
package dan200.computercraft.data;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import dan200.computercraft.client.gui.GuiSprites;
|
||||
import dan200.computercraft.client.model.LecternPrintoutModel;
|
||||
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.data.DataProvider;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.tags.TagsProvider;
|
||||
@@ -19,14 +13,9 @@ 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.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
|
||||
@@ -50,31 +39,14 @@ public final class DataProviders {
|
||||
|
||||
generator.add(out -> new LanguageProvider(out, turtleUpgrades, pocketUpgrades));
|
||||
|
||||
generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
|
||||
out.accept(new ResourceLocation("blocks"), makeSprites(Stream.of(
|
||||
UpgradeSlot.LEFT_UPGRADE,
|
||||
UpgradeSlot.RIGHT_UPGRADE,
|
||||
LecternPrintoutModel.TEXTURE
|
||||
)));
|
||||
out.accept(GuiSprites.SPRITE_SHEET, makeSprites(
|
||||
Stream.of(GuiSprites.TURTLE_NORMAL_SELECTED_SLOT, GuiSprites.TURTLE_ADVANCED_SELECTED_SLOT),
|
||||
// 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()
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
private static List<SpriteSource> makeSprites(final Stream<ResourceLocation>... files) {
|
||||
return Arrays.stream(files).flatMap(Function.identity()).<SpriteSource>map(x -> new SingleFile(x, Optional.empty())).toList();
|
||||
// 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).invoke(null, generator);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public interface GeneratorSink {
|
@@ -80,7 +80,6 @@ public final class LanguageProvider implements DataProvider {
|
||||
add(ModRegistry.Items.WIRED_MODEM.get(), "Wired Modem");
|
||||
add(ModRegistry.Items.CABLE.get(), "Networking Cable");
|
||||
add(ModRegistry.Items.WIRED_MODEM_FULL.get(), "Wired Modem");
|
||||
add(ModRegistry.Items.REDSTONE_RELAY.get(), "Redstone Relay");
|
||||
|
||||
add(ModRegistry.Items.TURTLE_NORMAL.get(), "Turtle");
|
||||
add(ModRegistry.Blocks.TURTLE_NORMAL.get().getDescriptionId() + ".upgraded", "%s Turtle");
|
@@ -51,7 +51,6 @@ class LootTableProvider {
|
||||
selfDrop(add, ModRegistry.Blocks.WIRED_MODEM_FULL);
|
||||
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_NORMAL);
|
||||
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED);
|
||||
selfDrop(add, ModRegistry.Blocks.REDSTONE_RELAY);
|
||||
|
||||
computerDrop(add, ModRegistry.Blocks.COMPUTER_NORMAL);
|
||||
computerDrop(add, ModRegistry.Blocks.COMPUTER_ADVANCED);
|
@@ -7,7 +7,6 @@ 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;
|
||||
|
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.util;
|
||||
package dan200.computercraft.data;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@@ -23,7 +23,7 @@ import java.util.List;
|
||||
/**
|
||||
* Alternative version of {@link JsonWriter} which attempts to lay out the JSON in a more compact format.
|
||||
*
|
||||
* @see dan200.computercraft.data.PrettyDataProvider
|
||||
* @see PrettyDataProvider
|
||||
*/
|
||||
public class PrettyJsonWriter extends JsonWriter {
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
@@ -461,17 +461,6 @@ class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.requires(ingredients.string())
|
||||
.unlockedBy("has_printer", inventoryChange(ModRegistry.Blocks.PRINTER.get()))
|
||||
.save(RecipeWrapper.wrap(ModRegistry.RecipeSerializers.IMPOSTOR_SHAPELESS.get(), add));
|
||||
|
||||
ShapedRecipeBuilder
|
||||
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.REDSTONE_RELAY.get())
|
||||
.pattern("SRS")
|
||||
.pattern("RCR")
|
||||
.pattern("SRS")
|
||||
.define('S', Items.STONE)
|
||||
.define('R', ingredients.redstone())
|
||||
.define('C', ModRegistry.Blocks.CABLE.get())
|
||||
.unlockedBy("has_cable", inventoryChange(ModRegistry.Blocks.CABLE.get()))
|
||||
.save(add);
|
||||
}
|
||||
|
||||
private static DyeColor ofColour(Colour colour) {
|
@@ -78,12 +78,9 @@ class TagProvider {
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get(),
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get(),
|
||||
ModRegistry.Blocks.WIRED_MODEM_FULL.get(),
|
||||
ModRegistry.Blocks.CABLE.get(),
|
||||
ModRegistry.Blocks.REDSTONE_RELAY.get()
|
||||
ModRegistry.Blocks.CABLE.get()
|
||||
);
|
||||
|
||||
tags.tag(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.Blocks.LECTERN.get());
|
||||
|
||||
tags.tag(BlockTags.WITHER_IMMUNE).add(ModRegistry.Blocks.COMPUTER_COMMAND.get());
|
||||
|
||||
tags.tag(ExternalModTags.Blocks.CREATE_BRITTLE).add(
|
||||
@@ -148,7 +145,7 @@ class TagProvider {
|
||||
/**
|
||||
* A wrapper over {@link ItemTagsProvider}.
|
||||
*/
|
||||
public interface ItemTagConsumer extends TagConsumer<Item> {
|
||||
interface ItemTagConsumer extends TagConsumer<Item> {
|
||||
void copy(TagKey<Block> block, TagKey<Item> item);
|
||||
}
|
||||
}
|
@@ -28,7 +28,6 @@ import dan200.computercraft.shared.computer.blocks.CommandComputerBlock;
|
||||
import dan200.computercraft.shared.computer.blocks.ComputerBlock;
|
||||
import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
|
||||
import dan200.computercraft.shared.computer.items.CommandComputerItem;
|
||||
import dan200.computercraft.shared.computer.items.ComputerItem;
|
||||
@@ -63,8 +62,6 @@ import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.printer.PrinterBlock;
|
||||
import dan200.computercraft.shared.peripheral.printer.PrinterBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.printer.PrinterMenu;
|
||||
import dan200.computercraft.shared.peripheral.redstone.RedstoneRelayBlock;
|
||||
import dan200.computercraft.shared.peripheral.redstone.RedstoneRelayBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlock;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
@@ -90,6 +87,7 @@ import dan200.computercraft.shared.turtle.recipes.TurtleOverlayRecipe;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleRecipe;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||
import dan200.computercraft.shared.turtle.upgrades.*;
|
||||
import dan200.computercraft.shared.util.ComponentMap;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||
import net.minecraft.commands.synchronization.SingletonArgumentInfo;
|
||||
@@ -134,7 +132,7 @@ public final class ModRegistry {
|
||||
return BlockBehaviour.Properties.of().strength(2);
|
||||
}
|
||||
|
||||
private static BlockBehaviour.Properties redstoneConductor() {
|
||||
private static BlockBehaviour.Properties computerProperties() {
|
||||
// Computers shouldn't conduct redstone through them, so set isRedstoneConductor to false. This still allows
|
||||
// redstone to connect to computers though as it's a signal source.
|
||||
return properties().isRedstoneConductor((block, level, blockPos) -> false);
|
||||
@@ -149,11 +147,11 @@ public final class ModRegistry {
|
||||
}
|
||||
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_NORMAL = REGISTRY.register("computer_normal",
|
||||
() -> new ComputerBlock<>(redstoneConductor().mapColor(MapColor.STONE), BlockEntities.COMPUTER_NORMAL));
|
||||
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.STONE), BlockEntities.COMPUTER_NORMAL));
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = REGISTRY.register("computer_advanced",
|
||||
() -> new ComputerBlock<>(redstoneConductor().mapColor(MapColor.GOLD), BlockEntities.COMPUTER_ADVANCED));
|
||||
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.GOLD), BlockEntities.COMPUTER_ADVANCED));
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command",
|
||||
() -> new CommandComputerBlock<>(redstoneConductor().strength(-1, 6000000.0F), BlockEntities.COMPUTER_COMMAND));
|
||||
() -> new CommandComputerBlock<>(computerProperties().strength(-1, 6000000.0F), BlockEntities.COMPUTER_COMMAND));
|
||||
|
||||
public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = REGISTRY.register("turtle_normal",
|
||||
() -> new TurtleBlock(turtleProperties().mapColor(MapColor.STONE), BlockEntities.TURTLE_NORMAL));
|
||||
@@ -181,9 +179,6 @@ public final class ModRegistry {
|
||||
public static final RegistryEntry<CustomLecternBlock> LECTERN = REGISTRY.register("lectern", () -> new CustomLecternBlock(
|
||||
BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.5F).sound(SoundType.WOOD).ignitedByLava()
|
||||
));
|
||||
|
||||
public static final RegistryEntry<RedstoneRelayBlock> REDSTONE_RELAY = REGISTRY.register("redstone_relay",
|
||||
() -> new RedstoneRelayBlock(redstoneConductor().mapColor(MapColor.STONE)));
|
||||
}
|
||||
|
||||
public static class BlockEntities {
|
||||
@@ -227,8 +222,6 @@ public final class ModRegistry {
|
||||
ofBlock(Blocks.WIRELESS_MODEM_ADVANCED, (p, s) -> new WirelessModemBlockEntity(BlockEntities.WIRELESS_MODEM_ADVANCED.get(), p, s, true));
|
||||
|
||||
public static final RegistryEntry<BlockEntityType<CustomLecternBlockEntity>> LECTERN = ofBlock(Blocks.LECTERN, CustomLecternBlockEntity::new);
|
||||
|
||||
public static final RegistryEntry<BlockEntityType<RedstoneRelayBlockEntity>> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, RedstoneRelayBlockEntity::new);
|
||||
}
|
||||
|
||||
public static final class Items {
|
||||
@@ -274,7 +267,6 @@ public final class ModRegistry {
|
||||
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_NORMAL = ofBlock(Blocks.WIRELESS_MODEM_NORMAL, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> WIRELESS_MODEM_ADVANCED = ofBlock(Blocks.WIRELESS_MODEM_ADVANCED, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> WIRED_MODEM_FULL = ofBlock(Blocks.WIRED_MODEM_FULL, BlockItem::new);
|
||||
public static final RegistryEntry<BlockItem> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, BlockItem::new);
|
||||
|
||||
public static final RegistryEntry<CableBlockItem.Cable> CABLE = REGISTRY.register("cable",
|
||||
() -> new CableBlockItem.Cable(Blocks.CABLE.get(), properties()));
|
||||
@@ -423,7 +415,6 @@ public final class ModRegistry {
|
||||
out.accept(Items.CABLE.get());
|
||||
out.accept(Items.WIRED_MODEM.get());
|
||||
out.accept(Items.WIRED_MODEM_FULL.get());
|
||||
out.accept(Items.REDSTONE_RELAY.get());
|
||||
|
||||
out.accept(Items.MONITOR_NORMAL.get());
|
||||
out.accept(Items.MONITOR_ADVANCED.get());
|
||||
@@ -471,7 +462,7 @@ public final class ModRegistry {
|
||||
|
||||
ComputerCraftAPI.registerAPIFactory(computer -> {
|
||||
var turtle = computer.getComponent(ComputerComponents.TURTLE);
|
||||
var metrics = Objects.requireNonNull(computer.getComponent(ServerComputer.METRICS));
|
||||
var metrics = Objects.requireNonNull(computer.getComponent(ComponentMap.METRICS));
|
||||
return turtle == null ? null : new TurtleAPI(metrics, (TurtleAccessInternal) turtle);
|
||||
});
|
||||
|
||||
|
@@ -24,13 +24,15 @@ import dan200.computercraft.shared.computer.metrics.basic.AggregatedMetric;
|
||||
import dan200.computercraft.shared.computer.metrics.basic.BasicComputerMetricsObserver;
|
||||
import dan200.computercraft.shared.computer.metrics.basic.ComputerMetrics;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.entity.RelativeMovement;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@@ -258,11 +260,18 @@ public final class CommandComputerCraft {
|
||||
* @return The constant {@code 1}.
|
||||
*/
|
||||
private static int view(CommandSourceStack source, ServerComputer computer) throws CommandSyntaxException {
|
||||
PlatformHelper.get().openMenu(
|
||||
source.getPlayerOrException(), Component.translatable("gui.computercraft.view_computer"),
|
||||
(id, player, entity) -> new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, player, p -> true, computer),
|
||||
new ComputerContainerData(computer, ItemStack.EMPTY)
|
||||
);
|
||||
var player = source.getPlayerOrException();
|
||||
new ComputerContainerData(computer, ItemStack.EMPTY).open(player, new MenuProvider() {
|
||||
@Override
|
||||
public Component getDisplayName() {
|
||||
return Component.translatable("gui.computercraft.view_computer");
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int id, Inventory player, Player entity) {
|
||||
return new ComputerMenuWithoutInventory(ModRegistry.Menus.COMPUTER.get(), id, player, p -> true, computer);
|
||||
}
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@@ -248,7 +248,7 @@ public class CommandAPI implements ILuaAPI {
|
||||
* Get some basic information about a block.
|
||||
* <p>
|
||||
* The returned table contains the current name, metadata and block state (as
|
||||
* with [`turtle.inspect`]). If there is a block entity for that block, its NBT
|
||||
* with [`turtle.inspect`]). If there is a tile entity for that block, its NBT
|
||||
* will also be returned.
|
||||
*
|
||||
* @param x The x position of the block to query.
|
||||
|
@@ -9,7 +9,6 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -162,7 +161,7 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
||||
var serverComputer = computer.createServerComputer();
|
||||
serverComputer.turnOn();
|
||||
|
||||
PlatformHelper.get().openMenu(player, computer.getName(), computer, new ComputerContainerData(serverComputer, getItem(computer)));
|
||||
new ComputerContainerData(serverComputer, getItem(computer)).open(player, computer);
|
||||
}
|
||||
return InteractionResult.sidedSuccess(level.isClientSide);
|
||||
}
|
||||
|
@@ -26,10 +26,9 @@ import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.LockCode;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.Nameable;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.MenuConstructor;
|
||||
import net.minecraft.world.level.block.GameMasterBlock;
|
||||
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
@@ -39,7 +38,7 @@ import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public abstract class AbstractComputerBlockEntity extends BlockEntity implements Nameable, MenuConstructor {
|
||||
public abstract class AbstractComputerBlockEntity extends BlockEntity implements Nameable, MenuProvider {
|
||||
private static final String NBT_ID = "ComputerId";
|
||||
private static final String NBT_LABEL = "Label";
|
||||
private static final String NBT_ON = "On";
|
||||
@@ -128,7 +127,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
// Update the block state if needed.
|
||||
updateBlockState(computer.getState());
|
||||
|
||||
var changes = computer.pollRedstoneChanges();
|
||||
var changes = computer.pollAndResetChanges();
|
||||
if (changes != 0) {
|
||||
for (var direction : DirectionUtil.FACINGS) {
|
||||
if ((changes & (1 << remapToLocalSide(direction).ordinal())) != 0) updateRedstoneTo(direction);
|
||||
@@ -196,10 +195,8 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
var offsetSide = dir.getOpposite();
|
||||
var localDir = remapToLocalSide(dir);
|
||||
|
||||
computer.setRedstoneInput(localDir,
|
||||
RedstoneUtil.getRedstoneInput(getLevel(), targetPos, dir),
|
||||
BundledRedstone.getOutput(getLevel(), targetPos, offsetSide)
|
||||
);
|
||||
computer.setRedstoneInput(localDir, RedstoneUtil.getRedstoneInput(getLevel(), targetPos, dir));
|
||||
computer.setBundledRedstoneInput(localDir, BundledRedstone.getOutput(getLevel(), targetPos, offsetSide));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,10 +308,6 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
return label;
|
||||
}
|
||||
|
||||
public final boolean isAdminOnly() {
|
||||
return getBlockState().getBlock() instanceof GameMasterBlock;
|
||||
}
|
||||
|
||||
public final void setComputerID(int id) {
|
||||
if (getLevel().isClientSide || computerID == id) return;
|
||||
|
||||
@@ -422,9 +415,4 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
||||
public Component getDisplayName() {
|
||||
return Nameable.super.getDisplayName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onlyOpCanSetNbt() {
|
||||
return isAdminOnly();
|
||||
}
|
||||
}
|
||||
|
@@ -11,7 +11,8 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
|
||||
import dan200.computercraft.shared.config.ConfigSpec;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.util.ComponentMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -32,9 +33,10 @@ public class ComputerBlockEntity extends AbstractComputerBlockEntity {
|
||||
|
||||
@Override
|
||||
protected ServerComputer createComputer(int id) {
|
||||
return new ServerComputer((ServerLevel) getLevel(), getBlockPos(), ServerComputer.properties(id, getFamily())
|
||||
.label(getLabel())
|
||||
.terminalSize(ConfigSpec.computerTermWidth.get(), ConfigSpec.computerTermHeight.get())
|
||||
return new ServerComputer(
|
||||
(ServerLevel) getLevel(), getBlockPos(), id, label,
|
||||
getFamily(), Config.computerTermWidth, Config.computerTermHeight,
|
||||
ComponentMap.empty()
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.apis.ComputerAccess;
|
||||
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||
import dan200.computercraft.core.computer.ApiLifecycle;
|
||||
import dan200.computercraft.shared.util.ComponentMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
||||
@@ -25,11 +26,11 @@ import java.util.Map;
|
||||
final class ComputerSystem extends ComputerAccess implements IComputerSystem, ApiLifecycle {
|
||||
private final ServerComputer computer;
|
||||
private final IAPIEnvironment environment;
|
||||
private final Map<ComputerComponent<?>, Object> components;
|
||||
private final ComponentMap components;
|
||||
|
||||
private boolean active;
|
||||
|
||||
ComputerSystem(ServerComputer computer, IAPIEnvironment environment, Map<ComputerComponent<?>, Object> components) {
|
||||
ComputerSystem(ServerComputer computer, IAPIEnvironment environment, ComponentMap components) {
|
||||
super(environment);
|
||||
this.computer = computer;
|
||||
this.environment = environment;
|
||||
@@ -94,8 +95,7 @@ final class ComputerSystem extends ComputerAccess implements IComputerSystem, Ap
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> @Nullable T getComponent(ComputerComponent<T> component) {
|
||||
return (T) components.get(component);
|
||||
return components.get(component);
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user