mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2026-04-16 12:01:23 +00:00
Compare commits
187 Commits
feature/po
...
v1.20.1-1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57a6add81a | ||
|
|
4bc04f1416 | ||
|
|
a0571e444c | ||
|
|
7292e3298f | ||
|
|
46f5dc485e | ||
|
|
f25f391b41 | ||
|
|
d5e45b65bf | ||
|
|
4a6ec54813 | ||
|
|
c98b99863d | ||
|
|
419441164d | ||
|
|
b7d1d9d012 | ||
|
|
2105c5c13f | ||
|
|
06d1abfeca | ||
|
|
d5e0b0ad2a | ||
|
|
24fd27d2a3 | ||
|
|
90e7307fb4 | ||
|
|
1520bebb6c | ||
|
|
419d823d3b | ||
|
|
f820cd8b43 | ||
|
|
4b1541154b | ||
|
|
8a1a545ab1 | ||
|
|
7659c608a6 | ||
|
|
778805a8d8 | ||
|
|
f31d8febbf | ||
|
|
60bcb9d4d3 | ||
|
|
1ea84fe7d7 | ||
|
|
a2ed5c385c | ||
|
|
9ad3b03946 | ||
|
|
5f704b2c58 | ||
|
|
53509b0d82 | ||
|
|
013f2e500f | ||
|
|
6702ab8f9d | ||
|
|
16d934265a | ||
|
|
ff9f038275 | ||
|
|
1f5339c86e | ||
|
|
28e569f2b4 | ||
|
|
28682aa468 | ||
|
|
2a35d17906 | ||
|
|
d39c91b25a | ||
|
|
61e9626302 | ||
|
|
307bebd5d2 | ||
|
|
6334a9df15 | ||
|
|
08d12f2b0e | ||
|
|
fbdf0d677f | ||
|
|
18f3426f1d | ||
|
|
0ec46fe38e | ||
|
|
569de7fafb | ||
|
|
157ce4fa55 | ||
|
|
b9ed66983d | ||
|
|
d0fbec6c6b | ||
|
|
a683697e8c | ||
|
|
9e233a916f | ||
|
|
5a9e21ccc3 | ||
|
|
5f16909d4b | ||
|
|
00475b9bb0 | ||
|
|
018ce7c8a5 | ||
|
|
44726827b4 | ||
|
|
3cf914cb4c | ||
|
|
180156ff1c | ||
|
|
c6ba753568 | ||
|
|
9f45c91925 | ||
|
|
8344c0a5c2 | ||
|
|
a292d33830 | ||
|
|
341d1c7bc2 | ||
|
|
531eacfac7 | ||
|
|
1f3da5205c | ||
|
|
798ceefafe | ||
|
|
7c0f79fc3c | ||
|
|
b35cefc5dd | ||
|
|
69353a4fcf | ||
|
|
ff363dca5a | ||
|
|
1c51282426 | ||
|
|
4a3a1c9275 | ||
|
|
2557dd0af9 | ||
|
|
b5c0c6e104 | ||
|
|
876fd8ddb8 | ||
|
|
ee3b1343b5 | ||
|
|
b440b964b7 | ||
|
|
5dfc401b45 | ||
|
|
4344c3072f | ||
|
|
947001104d | ||
|
|
8711512769 | ||
|
|
9c0ce27ce6 | ||
|
|
c458360b18 | ||
|
|
09ad6c1905 | ||
|
|
0e1e8a72d3 | ||
|
|
7c1e8e1951 | ||
|
|
b03546a158 | ||
|
|
582713467f | ||
|
|
b6f41a0df5 | ||
|
|
594738a022 | ||
|
|
27f2ab364c | ||
|
|
5a43273757 | ||
|
|
97e28516fb | ||
|
|
676fb5fb53 | ||
|
|
63ba3fe274 | ||
|
|
749b3df227 | ||
|
|
b97634b717 | ||
|
|
1b8344d0a3 | ||
|
|
b42bc0a01a | ||
|
|
0cff73e2fc | ||
|
|
a892739f8e | ||
|
|
f8785a092f | ||
|
|
dd7e8fcefc | ||
|
|
29c8f96912 | ||
|
|
b9267ecbfc | ||
|
|
9d2c2db22b | ||
|
|
6660966320 | ||
|
|
16324e1eac | ||
|
|
32f5c38485 | ||
|
|
01fe949b3e | ||
|
|
c03fce275e | ||
|
|
0998acaa82 | ||
|
|
12a44fed6f | ||
|
|
0a8d505323 | ||
|
|
237a0ac3bb | ||
|
|
b185d088b3 | ||
|
|
051c70a731 | ||
|
|
2e2f308ff3 | ||
|
|
0f123b5efd | ||
|
|
88cb03be6b | ||
|
|
4360485880 | ||
|
|
b69a44a927 | ||
|
|
7d8f609c49 | ||
|
|
e7f56c4d25 | ||
|
|
fa2140d00b | ||
|
|
03388149b1 | ||
|
|
f212861370 | ||
|
|
55edced9de | ||
|
|
dc969c5a78 | ||
|
|
94ad6dab0e | ||
|
|
938eb38ad5 | ||
|
|
6739c4c6c0 | ||
|
|
d6749f8461 | ||
|
|
5ba7f99326 | ||
|
|
62c9e5b08f | ||
|
|
2ca5850060 | ||
|
|
ed631b05e7 | ||
|
|
a2b9490d5c | ||
|
|
8204944b5f | ||
|
|
ef0af67e96 | ||
|
|
9a914e75c4 | ||
|
|
546577041b | ||
|
|
f881c0ced0 | ||
|
|
0b389e04b0 | ||
|
|
d3a3ab3c21 | ||
|
|
22e6c06e59 | ||
|
|
3c46b8acd7 | ||
|
|
d9fc1c3a80 | ||
|
|
479aabdd09 | ||
|
|
ad74893058 | ||
|
|
2ba6d5815b | ||
|
|
7e2f490626 | ||
|
|
4dc649d5e5 | ||
|
|
5bab415790 | ||
|
|
9bbf3f3e1d | ||
|
|
7c02979c22 | ||
|
|
fdb65c9368 | ||
|
|
ea670cc358 | ||
|
|
1963e0160f | ||
|
|
9a06904634 | ||
|
|
5e24ad17d7 | ||
|
|
8b1cb09ddf | ||
|
|
d1a6b043c2 | ||
|
|
cddb8fec11 | ||
|
|
1d7d8006d4 | ||
|
|
63bdc2537c | ||
|
|
f776b17150 | ||
|
|
31da2555cb | ||
|
|
9b19a93ab9 | ||
|
|
ad52117f0f | ||
|
|
bdffabc08e | ||
|
|
87ce41f251 | ||
|
|
e7c7919cad | ||
|
|
4f66ac79d3 | ||
|
|
ba6da3bc6c | ||
|
|
b742745854 | ||
|
|
3293639adf | ||
|
|
064ff31830 | ||
|
|
5d473725d5 | ||
|
|
97a2f2dbdd | ||
|
|
37c4789fa4 | ||
|
|
0aaeeeee24 | ||
|
|
2155ec3d63 | ||
|
|
0da906fc93 | ||
|
|
9e5e6a1b60 | ||
|
|
dcc74e15c7 |
@@ -18,11 +18,6 @@ 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
|
||||
|
||||
@@ -31,3 +26,27 @@ 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
|
||||
|
||||
ktlint_code_style = intellij_idea
|
||||
ktlint_standard_class-naming = disabled
|
||||
ktlint_standard_class-signature = disabled
|
||||
ktlint_standard_function-naming = disabled
|
||||
ktlint_standard_no-wildcard-imports = disabled
|
||||
|
||||
# FIXME: These two are disable right now as they're over-eager in putting things
|
||||
# on the same line. We should set max_line_length and handle this properly.
|
||||
ktlint_standard_function-signature = disabled
|
||||
ktlint_standard_function-expression-body = disabled
|
||||
|
||||
16
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
16
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -1,15 +1,18 @@
|
||||
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?
|
||||
description: |
|
||||
What version of Minecraft are you using? If your version is not listed, please try to reproduce on one of the supported versions.
|
||||
options:
|
||||
- 1.20.1
|
||||
- 1.21.x
|
||||
- 1.21.1
|
||||
- 1.21.7
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
@@ -26,8 +29,7 @@ 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. 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.
|
||||
- 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.
|
||||
|
||||

|
||||
|
||||
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
1
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -2,6 +2,7 @@
|
||||
name: Feature request
|
||||
about: Suggest an idea or improvement
|
||||
labels: enhancement
|
||||
type: feature
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
36
.github/workflows/main-ci.yml
vendored
36
.github/workflows/main-ci.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: 📥 Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
java-version: 25
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: 📥 Setup Gradle
|
||||
@@ -30,6 +30,18 @@ jobs:
|
||||
- name: ⚒️ Build
|
||||
run: ./gradlew assemble || ./gradlew assemble
|
||||
|
||||
- name: 📦 Prepare Jars
|
||||
run: |
|
||||
# Find the main jar and append the git hash onto it.
|
||||
mkdir -p jars
|
||||
find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
|
||||
|
||||
- name: 📤 Upload Jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: CC-Tweaked
|
||||
path: ./jars
|
||||
|
||||
- name: Cache pre-commit
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@@ -50,30 +62,10 @@ 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
|
||||
@@ -95,7 +87,7 @@ jobs:
|
||||
- name: 📥 Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
java-version: 25
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: 📥 Setup Gradle
|
||||
|
||||
2
.github/workflows/make-doc.yml
vendored
2
.github/workflows/make-doc.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
- name: 📥 Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
java-version: 25
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: 📥 Setup Gradle
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,6 +27,7 @@
|
||||
*.iml
|
||||
.idea
|
||||
.gradle
|
||||
.kotlin
|
||||
*.DS_Store
|
||||
|
||||
/.classpath
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
rev: v6.0.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
@@ -20,14 +20,14 @@ repos:
|
||||
exclude: "tsconfig\\.json$"
|
||||
|
||||
- repo: https://github.com/editorconfig-checker/editorconfig-checker.python
|
||||
rev: 2.7.2
|
||||
rev: 3.6.0
|
||||
hooks:
|
||||
- id: editorconfig-checker
|
||||
args: ['-disable-indentation']
|
||||
exclude: "^(.*\\.(bat)|LICENSE)$"
|
||||
|
||||
- repo: https://github.com/fsfe/reuse-tool
|
||||
rev: v4.0.3
|
||||
rev: v6.2.0
|
||||
hooks:
|
||||
- id: reuse
|
||||
|
||||
@@ -58,6 +58,7 @@ 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,14 +22,13 @@ 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 may either
|
||||
be contributed there, or directly via a pull request.
|
||||
Translations are managed through [CrowdIn], an online interface for managing language strings.
|
||||
|
||||
## Setting up a development environment
|
||||
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
|
||||
|
||||
- Make sure you've got the following software installed:
|
||||
- Java Development Kit 17 (JDK). This can be downloaded from [Adoptium].
|
||||
- Java Development Kit 25 (JDK). This can be downloaded from [Adoptium].
|
||||
- [Git](https://git-scm.com/).
|
||||
- [NodeJS 20 or later][node].
|
||||
|
||||
@@ -49,9 +48,12 @@ 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 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]!
|
||||
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]!
|
||||
|
||||
### Testing
|
||||
When making larger changes, it may be useful to write a test to make sure your code works as expected.
|
||||
@@ -86,8 +88,8 @@ You'll first need to [set up a development environment as above](#setting-up-a-d
|
||||
|
||||
Once this is set up, you can now run `./gradlew docWebsite`. This generates documentation from our Lua and Java code,
|
||||
writing the resulting HTML into `./projects/web/build/site`, which can then be opened in a browser. When iterating on
|
||||
documentation, you can instead run `./gradlew docWebsite -t`, which will rebuild documentation every time you change a
|
||||
file.
|
||||
documentation, you can instead run `./gradlew :web:assemble -x :web:compileTeaVM -t`, which will rebuild documentation
|
||||
every time you change a file.
|
||||
|
||||
Documentation is built using [illuaminate] which, while not currently documented (somewhat ironic), is largely the same
|
||||
as [ldoc][ldoc]. Documentation comments are written in Markdown, though note that we do not support many GitHub-specific
|
||||
@@ -99,7 +101,7 @@ about how you can build on that until you've covered everything!
|
||||
|
||||
[new-issue]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose "Create a new issue"
|
||||
[community]: README.md#community "Get in touch with the community."
|
||||
[Adoptium]: https://adoptium.net/temurin/releases?version=17 "Download OpenJDK 17"
|
||||
[Adoptium]: https://adoptium.net/temurin/releases?version=25 "Download OpenJDK 25"
|
||||
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
|
||||
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
|
||||
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
|
||||
|
||||
17
README.md
17
README.md
@@ -11,14 +11,13 @@ 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 [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||
CC: Tweaked can be installed from [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
|
||||
@@ -62,19 +61,6 @@ 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!
|
||||
@@ -83,7 +69,6 @@ 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,18 +8,23 @@ 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]]
|
||||
@@ -30,23 +35,15 @@ path = [
|
||||
"doc/images/**",
|
||||
"package.json",
|
||||
"package-lock.json",
|
||||
"projects/common/src/client/resources/computercraft-client.mixins.json",
|
||||
"projects/*/src/*/resources/*.mixins.json",
|
||||
"projects/fabric/src/*/resources/fabric.mod.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",
|
||||
@@ -73,7 +70,7 @@ path = [
|
||||
]
|
||||
|
||||
[[annotations]]
|
||||
# Community-contributed license files
|
||||
# Community-contributed language files
|
||||
SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
|
||||
SPDX-License-Identifier = "LicenseRef-CCPL"
|
||||
path = [
|
||||
@@ -87,18 +84,11 @@ path = [
|
||||
]
|
||||
|
||||
[[annotations]]
|
||||
# Community-contributed license files
|
||||
# Community-contributed language 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"
|
||||
|
||||
@@ -4,13 +4,11 @@
|
||||
|
||||
import cc.tweaked.gradle.JUnitExt
|
||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper
|
||||
import org.jetbrains.gradle.ext.*
|
||||
import org.jetbrains.gradle.ext.Application
|
||||
|
||||
plugins {
|
||||
publishing
|
||||
alias(libs.plugins.taskTree)
|
||||
alias(libs.plugins.githubRelease)
|
||||
alias(libs.plugins.gradleVersions)
|
||||
alias(libs.plugins.versionCatalogUpdate)
|
||||
@@ -24,21 +22,19 @@ val mcVersion: String by extra
|
||||
|
||||
githubRelease {
|
||||
token(findProperty("githubApiKey") as String? ?: "")
|
||||
owner.set("cc-tweaked")
|
||||
repo.set("CC-Tweaked")
|
||||
targetCommitish.set(cct.gitBranch)
|
||||
owner = "cc-tweaked"
|
||||
repo = "CC-Tweaked"
|
||||
targetCommitish = cct.gitBranch
|
||||
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
tasks.publish { dependsOn(tasks.githubRelease) }
|
||||
@@ -72,7 +68,7 @@ idea.project.settings.runConfigurations {
|
||||
val fabricProject = evaluationDependsOn(":fabric")
|
||||
val classPathGroup = fabricProject.extensions.getByType<LoomGradleExtensionAPI>().mods
|
||||
.joinToString(File.pathSeparator + File.pathSeparator) { modSettings ->
|
||||
SourceSetHelper.getClasspath(modSettings, project).joinToString(File.pathSeparator) { it.absolutePath }
|
||||
modSettings.modFiles.joinToString(File.pathSeparator) { it.absolutePath }
|
||||
}
|
||||
|
||||
vmParameters = "-ea -Dfabric.classPathGroups=$classPathGroup"
|
||||
@@ -117,8 +113,12 @@ idea.project.settings.compiler.javac {
|
||||
.toMap()
|
||||
}
|
||||
|
||||
versionCatalogUpdate {
|
||||
sortByKey.set(false)
|
||||
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
|
||||
keep { keepUnusedLibraries.set(true) }
|
||||
repositories() {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
versionCatalogUpdate {
|
||||
sortByKey = false
|
||||
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
|
||||
keep { keepUnusedVersions = true }
|
||||
}
|
||||
|
||||
@@ -14,18 +14,10 @@ repositories {
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
|
||||
maven("https://maven.minecraftforge.net") {
|
||||
name = "Forge"
|
||||
maven("https://maven.neoforged.net") {
|
||||
name = "NeoForge"
|
||||
content {
|
||||
includeGroup("net.minecraftforge")
|
||||
includeGroup("net.minecraftforge.gradle")
|
||||
}
|
||||
}
|
||||
|
||||
maven("https://maven.parchmentmc.org") {
|
||||
name = "Librarian"
|
||||
content {
|
||||
includeGroupByRegex("^org\\.parchmentmc.*")
|
||||
includeGroup("net.neoforged")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +25,7 @@ repositories {
|
||||
name = "Fabric"
|
||||
content {
|
||||
includeGroup("net.fabricmc")
|
||||
includeGroup("net.fabricmc.unpick")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,12 +42,10 @@ 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)
|
||||
}
|
||||
|
||||
@@ -78,7 +69,7 @@ gradlePlugin {
|
||||
}
|
||||
|
||||
versionCatalogUpdate {
|
||||
sortByKey.set(false)
|
||||
keep { keepUnusedLibraries.set(true) }
|
||||
catalogFile.set(file("../gradle/libs.versions.toml"))
|
||||
sortByKey = false
|
||||
keep { keepUnusedVersions = true }
|
||||
catalogFile = file("../gradle/libs.versions.toml")
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@
|
||||
|
||||
import cc.tweaked.gradle.CCTweakedExtension
|
||||
import cc.tweaked.gradle.CCTweakedPlugin
|
||||
import cc.tweaked.gradle.IdeaRunConfigurations
|
||||
import cc.tweaked.gradle.DependencyCheck
|
||||
import cc.tweaked.gradle.MinecraftConfigurations
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
id("fabric-loom")
|
||||
id("net.fabricmc.fabric-loom-remap")
|
||||
id("cc-tweaked.java-convention")
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ repositories {
|
||||
|
||||
loom {
|
||||
splitEnvironmentSourceSets()
|
||||
splitModDependencies.set(true)
|
||||
splitModDependencies = true
|
||||
}
|
||||
|
||||
MinecraftConfigurations.setup(project)
|
||||
@@ -47,11 +47,12 @@ dependencies {
|
||||
loom.layered {
|
||||
officialMojangMappings()
|
||||
parchment(
|
||||
project.dependencies.create(
|
||||
group = "org.parchmentmc.data",
|
||||
name = "parchment-${libs.findVersion("parchmentMc").get()}",
|
||||
version = libs.findVersion("parchment").get().toString(),
|
||||
ext = "zip",
|
||||
dependencyFactory.create(
|
||||
"org.parchmentmc.data",
|
||||
"parchment-${libs.findVersion("parchmentMc").get()}",
|
||||
libs.findVersion("parchment").get().toString(),
|
||||
null,
|
||||
"zip",
|
||||
),
|
||||
)
|
||||
},
|
||||
@@ -64,6 +65,18 @@ dependencies {
|
||||
compileOnlyApi(libs.findLibrary("errorProne.annotations").get())
|
||||
}
|
||||
|
||||
tasks.ideaSyncTask {
|
||||
doLast { IdeaRunConfigurations(project).patch() }
|
||||
tasks.named("checkDependencyConsistency", DependencyCheck::class.java) {
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
// Minecraft depends on lwjgl, but Fabric forces it to a more recent version
|
||||
for (lwjgl in listOf(
|
||||
"lwjgl",
|
||||
"lwjgl-glfw",
|
||||
"lwjgl-jemalloc",
|
||||
"lwjgl-openal",
|
||||
"lwjgl-opengl",
|
||||
"lwjgl-stb",
|
||||
"lwjgl-tinyfd",
|
||||
)) {
|
||||
override("org.lwjgl", lwjgl, "3.3.2")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,25 +6,30 @@
|
||||
|
||||
import cc.tweaked.gradle.CCTweakedExtension
|
||||
import cc.tweaked.gradle.CCTweakedPlugin
|
||||
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("org.parchmentmc.librarian.forgegradle")
|
||||
id("net.neoforged.moddev.legacyforge")
|
||||
}
|
||||
|
||||
plugins.apply(CCTweakedPlugin::class.java)
|
||||
|
||||
val mcVersion: String by extra
|
||||
|
||||
minecraft {
|
||||
legacyForge {
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
mappings("parchment", "${libs.findVersion("parchmentMc").get()}-${libs.findVersion("parchment").get()}-$mcVersion")
|
||||
enable {
|
||||
forgeVersion = "$mcVersion-${libs.findVersion("forge").get()}"
|
||||
// This causes parameters to not be renamed, which causes issues with ErrorProne.
|
||||
// See https://github.com/google/error-prone/issues/5398.
|
||||
isDisableRecompilation = false
|
||||
}
|
||||
|
||||
accessTransformer(project(":forge").file("src/main/resources/META-INF/accesstransformer.cfg"))
|
||||
parchment {
|
||||
minecraftVersion = libs.findVersion("parchmentMc").get().toString()
|
||||
mappingsVersion = libs.findVersion("parchment").get().toString()
|
||||
}
|
||||
}
|
||||
|
||||
MinecraftConfigurations.setup(project)
|
||||
@@ -32,13 +37,3 @@ 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() }
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ plugins {
|
||||
checkstyle
|
||||
id("com.diffplug.spotless")
|
||||
id("net.ltgt.errorprone")
|
||||
// Required for cross-project dependencies in Fabric
|
||||
id("net.fabricmc.fabric-loom-companion")
|
||||
}
|
||||
|
||||
val modVersion: String by extra
|
||||
@@ -28,9 +30,9 @@ version = modVersion
|
||||
base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
||||
}
|
||||
toolchain { languageVersion = CCTweakedPlugin.JDK_VERSION }
|
||||
sourceCompatibility = CCTweakedPlugin.JAVA_VERSION
|
||||
targetCompatibility = CCTweakedPlugin.JAVA_VERSION
|
||||
|
||||
withSourcesJar()
|
||||
}
|
||||
@@ -44,13 +46,6 @@ 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
|
||||
@@ -86,19 +81,31 @@ dependencies {
|
||||
// Configure default JavaCompile tasks with our arguments.
|
||||
sourceSets.all {
|
||||
tasks.named(compileJavaTaskName, JavaCompile::class.java) {
|
||||
// Processing just gives us "No processor claimed any of these annotations", so skip that!
|
||||
options.compilerArgs.addAll(listOf("-Xlint", "-Xlint:-processing"))
|
||||
// Explicitly set release, as that limits the APIs we can use to the right version of Java.
|
||||
options.release = CCTweakedPlugin.JAVA_TARGET.asInt()
|
||||
|
||||
options.compilerArgs.addAll(
|
||||
listOf(
|
||||
"-Xlint",
|
||||
// Processing just gives us "No processor claimed any of these annotations", so skip that!
|
||||
"-Xlint:-processing",
|
||||
// We violate this pattern too often for it to be a helpful warning. Something to improve one day!
|
||||
"-Xlint:-this-escape",
|
||||
),
|
||||
)
|
||||
|
||||
options.errorprone {
|
||||
check("InvalidBlockTag", CheckSeverity.OFF) // Broken by @cc.xyz
|
||||
check("InvalidParam", CheckSeverity.OFF) // Broken by records.
|
||||
check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
|
||||
// Too many false positives right now. Maybe we need an indirection for it later on.
|
||||
check("AssignmentExpression", CheckSeverity.OFF) // I'm a bad person.
|
||||
check("ReferenceEquality", CheckSeverity.OFF)
|
||||
check("EnumOrdinal", CheckSeverity.OFF) // For now. We could replace most of these with EnumMap.
|
||||
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.
|
||||
option("UnusedMethod:ExemptingMethodAnnotations", "dan200.computercraft.api.lua.LuaFunction")
|
||||
|
||||
check("NullAway", CheckSeverity.ERROR)
|
||||
option(
|
||||
@@ -121,7 +128,6 @@ tasks.compileTestJava {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tasks.withType(JavaCompile::class.java).configureEach {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
@@ -155,7 +161,7 @@ tasks.javadoc {
|
||||
options {
|
||||
val stdOptions = this as StandardJavadocDocletOptions
|
||||
stdOptions.addBooleanOption("Xdoclint:all,-missing", true)
|
||||
stdOptions.links("https://docs.oracle.com/en/java/javase/17/docs/api/")
|
||||
stdOptions.links("https://docs.oracle.com/en/java/javase/${CCTweakedPlugin.JAVA_TARGET.asInt()}/docs/api/")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +175,8 @@ tasks.test {
|
||||
}
|
||||
|
||||
tasks.withType(JacocoReport::class.java).configureEach {
|
||||
reports.xml.required.set(true)
|
||||
reports.html.required.set(true)
|
||||
reports.xml.required = true
|
||||
reports.html.required = true
|
||||
}
|
||||
|
||||
project.plugins.withType(CCTweakedPlugin::class.java) {
|
||||
@@ -194,30 +200,23 @@ spotless {
|
||||
fun FormatExtension.defaults() {
|
||||
endWithNewline()
|
||||
trimTrailingWhitespace()
|
||||
indentWithSpaces(4)
|
||||
leadingTabsToSpaces(4)
|
||||
}
|
||||
|
||||
java {
|
||||
defaults()
|
||||
importOrder("", "javax|java", "\\#")
|
||||
removeUnusedImports()
|
||||
}
|
||||
|
||||
val ktlintConfig = mapOf(
|
||||
"ktlint_standard_no-wildcard-imports" to "disabled",
|
||||
"ktlint_standard_class-naming" to "disabled",
|
||||
"ktlint_standard_function-naming" to "disabled",
|
||||
"ij_kotlin_allow_trailing_comma" to "true",
|
||||
"ij_kotlin_allow_trailing_comma_on_call_site" to "true",
|
||||
)
|
||||
|
||||
kotlinGradle {
|
||||
defaults()
|
||||
ktlint().editorConfigOverride(ktlintConfig)
|
||||
ktlint()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
defaults()
|
||||
ktlint().editorConfigOverride(ktlintConfig)
|
||||
ktlint()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,6 +225,5 @@ 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
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
// 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,11 +2,9 @@
|
||||
//
|
||||
// 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")
|
||||
}
|
||||
@@ -25,34 +23,17 @@ 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.set(findProperty("modrinthApiKey") as String? ?: "")
|
||||
projectId.set("gu7yAYhd")
|
||||
versionNumber.set(modVersion)
|
||||
versionName.set(modVersion)
|
||||
versionType.set(if (isUnstable) "alpha" else "release")
|
||||
token = findProperty("modrinthApiKey") as String? ?: ""
|
||||
projectId = "gu7yAYhd"
|
||||
versionNumber = modVersion
|
||||
versionName = modVersion
|
||||
versionType = if (isUnstable) "alpha" else "release"
|
||||
uploadFile.setProvider(modPublishing.output)
|
||||
gameVersions.add(mcVersion)
|
||||
changelog.set("Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion).")
|
||||
changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
|
||||
|
||||
syncBodyFrom.set(provider { rootProject.file("doc/mod-page.md").readText() })
|
||||
syncBodyFrom = provider { rootProject.file("doc/mod-page.md").readText() }
|
||||
}
|
||||
|
||||
tasks.publish { dependsOn(tasks.modrinth) }
|
||||
|
||||
@@ -2,44 +2,35 @@
|
||||
//
|
||||
// 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.CCTweakedPlugin
|
||||
import cc.tweaked.gradle.MinecraftConfigurations
|
||||
import cc.tweaked.gradle.clientClasses
|
||||
import cc.tweaked.gradle.commonClasses
|
||||
|
||||
plugins {
|
||||
id("cc-tweaked.kotlin-convention")
|
||||
kotlin("jvm")
|
||||
id("cc-tweaked.java-convention")
|
||||
}
|
||||
|
||||
val main = sourceSets["main"]
|
||||
val client = sourceSets["client"]
|
||||
|
||||
// Both testMod and testFixtures inherit from the main and client classpath, just so we have access to Minecraft classes.
|
||||
val testMod by sourceSets.creating {
|
||||
compileClasspath += main.compileClasspath + client.compileClasspath
|
||||
runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
|
||||
}
|
||||
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.DATAGEN)
|
||||
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.EXAMPLES)
|
||||
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.TEST_MOD)
|
||||
|
||||
configurations {
|
||||
named(testMod.compileClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(compileClasspath.get())
|
||||
}
|
||||
// Set up generated resources
|
||||
sourceSets.main { resources.srcDir("src/generated/resources") }
|
||||
sourceSets.named("examples") { resources.srcDir("src/examples/generatedResources") }
|
||||
|
||||
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)
|
||||
}
|
||||
// Make sure our examples compile.
|
||||
tasks.check { dependsOn(tasks.named("compileExamplesJava")) }
|
||||
|
||||
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
|
||||
|
||||
@@ -62,3 +53,5 @@ dependencies {
|
||||
|
||||
testImplementation(testFixtures(project))
|
||||
}
|
||||
|
||||
kotlin.compilerOptions.jvmTarget = CCTweakedPlugin.KOTLIN_TARGET
|
||||
@@ -12,25 +12,26 @@ publishing {
|
||||
register<MavenPublication>("maven") {
|
||||
artifactId = base.archivesName.get()
|
||||
from(components["java"])
|
||||
suppressAllPomMetadataWarnings()
|
||||
|
||||
pom {
|
||||
name.set("CC: Tweaked")
|
||||
description.set("CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.")
|
||||
url.set("https://github.com/cc-tweaked/CC-Tweaked")
|
||||
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"
|
||||
|
||||
scm {
|
||||
url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
|
||||
url = "https://github.com/cc-tweaked/CC-Tweaked.git"
|
||||
}
|
||||
|
||||
issueManagement {
|
||||
system.set("github")
|
||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
|
||||
system = "github"
|
||||
url = "https://github.com/cc-tweaked/CC-Tweaked/issues"
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name.set("ComputerCraft Public License, Version 1.0")
|
||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
|
||||
name = "ComputerCraft Public License, Version 1.0"
|
||||
url = "https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,9 @@ 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
|
||||
@@ -25,7 +20,6 @@ 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
|
||||
@@ -36,54 +30,40 @@ import java.io.IOException
|
||||
import java.net.URI
|
||||
import java.util.regex.Pattern
|
||||
|
||||
abstract class CCTweakedExtension(
|
||||
private val project: Project,
|
||||
private val fs: FileSystemOperations,
|
||||
) {
|
||||
abstract class CCTweakedExtension(private val project: Project) {
|
||||
/** Get the hash of the latest git commit. */
|
||||
val gitHash: Provider<String> = gitProvider(project, "<no git hash>") {
|
||||
ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "HEAD").trim()
|
||||
}
|
||||
val gitHash: Provider<String> =
|
||||
gitProvider("<no git commit>", listOf("rev-parse", "HEAD")) { it.trim() }
|
||||
|
||||
/** Get the current git branch. */
|
||||
val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") {
|
||||
ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD")
|
||||
.trim()
|
||||
}
|
||||
val gitBranch: Provider<String> =
|
||||
gitProvider("<no git branch>", listOf("rev-parse", "--abbrev-ref", "HEAD")) { it.trim() }
|
||||
|
||||
/** Get a list of all contributors to the project. */
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() }
|
||||
}
|
||||
|
||||
@@ -109,14 +89,13 @@ abstract class CCTweakedExtension(
|
||||
val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
|
||||
val main = otherJava.sourceSets.getByName("main")
|
||||
val client = otherJava.sourceSets.getByName("client")
|
||||
val testMod = otherJava.sourceSets.findByName("testMod")
|
||||
val testFixtures = otherJava.sourceSets.findByName("testFixtures")
|
||||
|
||||
// Pull in sources from the other project.
|
||||
extendSourceSet(otherProject, main)
|
||||
extendSourceSet(otherProject, client)
|
||||
if (testMod != null) extendSourceSet(otherProject, testMod)
|
||||
if (testFixtures != null) extendSourceSet(otherProject, testFixtures)
|
||||
for (sourceSet in listOf(MinecraftConfigurations.DATAGEN, MinecraftConfigurations.EXAMPLES, MinecraftConfigurations.TEST_MOD, "testFixtures")) {
|
||||
otherJava.sourceSets.findByName(sourceSet)?.let { extendSourceSet(otherProject, it) }
|
||||
}
|
||||
|
||||
// The extra source-processing tasks should include these files too.
|
||||
project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
|
||||
@@ -179,23 +158,19 @@ abstract class CCTweakedExtension(
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
doFirst("Clean class dump directory") { fs.delete { delete(classDump) } }
|
||||
|
||||
jacoco.applyTo(this)
|
||||
|
||||
extensions.configure(JacocoTaskExtension::class.java) {
|
||||
includes = listOf("dan200.computercraft.*")
|
||||
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
|
||||
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.
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,15 +179,11 @@ abstract class CCTweakedExtension(
|
||||
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 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)
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,40 +223,31 @@ abstract class CCTweakedExtension(
|
||||
).resolve().single()
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude a dependency from being published in Maven.
|
||||
*/
|
||||
fun exclude(dep: Dependency) {
|
||||
excludedDeps.add(dep)
|
||||
}
|
||||
private fun <T: Any> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
|
||||
val baseResult = project.providers.exec {
|
||||
commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a [MavenDependencySpec].
|
||||
*/
|
||||
fun configureExcludes(spec: MavenDependencySpec) {
|
||||
for (dep in excludedDeps.get()) spec.exclude(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)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
|
||||
private val IGNORED_USERS = setOf(
|
||||
"GitHub", "Daniel Ratcliffe", "Weblate",
|
||||
"GitHub", "Daniel Ratcliffe", "NotSquidDev", "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"))
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
@@ -13,6 +14,7 @@ import org.gradle.plugins.ide.idea.model.IdeaModel
|
||||
import org.jetbrains.gradle.ext.IdeaExtPlugin
|
||||
import org.jetbrains.gradle.ext.runConfigurations
|
||||
import org.jetbrains.gradle.ext.settings
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
/**
|
||||
* Configures projects to match a shared configuration.
|
||||
@@ -42,6 +44,17 @@ class CCTweakedPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val JAVA_VERSION = JavaLanguageVersion.of(17)
|
||||
/**
|
||||
* The version we run with. We use Java 25 here, as our Gradle build requires that.
|
||||
*/
|
||||
val JDK_VERSION = JavaLanguageVersion.of(25)
|
||||
|
||||
/**
|
||||
* The Java version we target. Should be the same as what Minecraft uses.
|
||||
*/
|
||||
val JAVA_TARGET = JavaLanguageVersion.of(17)
|
||||
|
||||
val JAVA_VERSION = JavaVersion.toVersion(JAVA_TARGET.asInt())
|
||||
val KOTLIN_TARGET = JvmTarget.fromTarget(JAVA_TARGET.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,19 +22,19 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
|
||||
abstract class DependencyCheck : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val configuration: ListProperty<Configuration>
|
||||
protected abstract val dependencies: ListProperty<DependencyResult>
|
||||
|
||||
/**
|
||||
* A mapping of module coordinates (`group:module`) to versions, overriding the requested version.
|
||||
*/
|
||||
@get:Input
|
||||
abstract val overrides: MapProperty<String, String>
|
||||
protected abstract val overrides: MapProperty<String, String>
|
||||
|
||||
init {
|
||||
description = "Check :core's dependencies are consistent with Minecraft's."
|
||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
|
||||
configuration.finalizeValueOnRead()
|
||||
dependencies.finalizeValueOnRead()
|
||||
overrides.finalizeValueOnRead()
|
||||
}
|
||||
|
||||
@@ -45,13 +45,23 @@ abstract class DependencyCheck : DefaultTask() {
|
||||
overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
|
||||
}
|
||||
|
||||
fun override(group: String, module: String, version: String) {
|
||||
overrides.put("$group:$module", version)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a configuration to check.
|
||||
*/
|
||||
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 configuration.get()) {
|
||||
configuration.incoming.resolutionResult.allDependencies {
|
||||
if (!check(this@allDependencies)) ok = false
|
||||
}
|
||||
for (configuration in dependencies.get()) {
|
||||
if (!check(configuration)) ok = false
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.AbstractExecTask
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import java.io.File
|
||||
|
||||
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
|
||||
@get:OutputDirectory
|
||||
|
||||
@@ -124,7 +124,7 @@ class CloseScope : AutoCloseable {
|
||||
}
|
||||
|
||||
/** Proxy method to avoid overload ambiguity. */
|
||||
fun <T> Property<T>.setProvider(provider: Provider<out T>) = set(provider)
|
||||
fun <T: Any> Property<T >.setProvider(provider: Provider<out T>) = set(provider)
|
||||
|
||||
/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */
|
||||
fun Provider<out FileSystemLocation>.getAbsolutePath(): String = get().asFile.absolutePath
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
// 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),
|
||||
)
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.w3c.dom.Attr
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Node
|
||||
import org.xml.sax.InputSource
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.dom.DOMSource
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
import javax.xml.xpath.XPathConstants
|
||||
import javax.xml.xpath.XPathFactory
|
||||
|
||||
/**
|
||||
* Patches up run configurations from ForgeGradle and Loom.
|
||||
*
|
||||
* Would be good to PR some (or all) of these changes upstream at some point.
|
||||
*
|
||||
* @see net.fabricmc.loom.configuration.ide.idea.IdeaSyncTask
|
||||
* @see net.minecraftforge.gradle.common.util.runs.IntellijRunGenerator
|
||||
*/
|
||||
internal class IdeaRunConfigurations(project: Project) {
|
||||
private val rootProject = project.rootProject
|
||||
|
||||
private val documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
private val xpath = XPathFactory.newInstance().newXPath()
|
||||
private val writer = TransformerFactory.newInstance().newTransformer()
|
||||
|
||||
private val ideaDir = rootProject.file(".idea/")
|
||||
private val buildDir: Lazy<String?> = lazy {
|
||||
val ideaMisc = ideaDir.resolve("misc.xml")
|
||||
|
||||
try {
|
||||
val doc = Files.newBufferedReader(ideaMisc.toPath()).use {
|
||||
documentBuilder.parse(InputSource(it))
|
||||
}
|
||||
val node =
|
||||
xpath.evaluate("//component[@name=\"ProjectRootManager\"]/output", doc, XPathConstants.NODE) as Node
|
||||
val attr = node.attributes.getNamedItem("url") as Attr
|
||||
attr.value.removePrefix("file://")
|
||||
} catch (e: Exception) {
|
||||
LOGGER.error("Failed to find root directory", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun patch() = synchronized(LOCK) {
|
||||
val runConfigDir = ideaDir.resolve("runConfigurations")
|
||||
if (!runConfigDir.isDirectory) return
|
||||
|
||||
Files.list(runConfigDir.toPath()).use {
|
||||
for (configuration in it) {
|
||||
val filename = configuration.fileName.toString();
|
||||
when {
|
||||
filename.endsWith("_fabric.xml") -> patchFabric(configuration)
|
||||
filename.startsWith("forge_") && filename.endsWith(".xml") -> patchForge(configuration)
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun patchFabric(path: Path) = withXml(path) {
|
||||
setXml("//configuration", "folderName") { "Fabric" }
|
||||
}
|
||||
|
||||
private fun patchForge(path: Path) = withXml(path) {
|
||||
val configId = path.fileName.toString().removePrefix("forge_").removeSuffix(".xml")
|
||||
val sourceSet = forgeConfigs[configId]
|
||||
if (sourceSet == null) {
|
||||
LOGGER.error("[{}] Cannot map run configuration to a known source set", path)
|
||||
return@withXml
|
||||
}
|
||||
|
||||
setXml("//configuration", "folderName") { "Forge" }
|
||||
setXml("//configuration/module", "name") { "${rootProject.name}.forge.$sourceSet" }
|
||||
|
||||
if (buildDir.value == null) return@withXml
|
||||
setXml("//configuration/envs/env[@name=\"MOD_CLASSES\"]", "value") { classpath ->
|
||||
val classes = classpath!!.split(':')
|
||||
val newClasses = mutableListOf<String>()
|
||||
fun appendUnique(x: String) {
|
||||
if (!newClasses.contains(x)) newClasses.add(x)
|
||||
}
|
||||
|
||||
for (entry in classes) {
|
||||
if (!entry.contains("/out/")) {
|
||||
appendUnique(entry)
|
||||
continue
|
||||
}
|
||||
|
||||
val match = CLASSPATH_ENTRY.matchEntire(entry)
|
||||
if (match != null) {
|
||||
val modId = match.groups["modId"]!!.value
|
||||
val proj = match.groups["proj"]!!.value
|
||||
var component = match.groups["component"]!!.value
|
||||
if (component == "production") component = "main"
|
||||
|
||||
appendUnique(forgeModEntry(modId, proj, component))
|
||||
} else {
|
||||
LOGGER.warn("[{}] Unknown classpath entry {}", path, entry)
|
||||
appendUnique(entry)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure common code is on the classpath
|
||||
for (proj in listOf("common", "common-api")) {
|
||||
for (component in listOf("main", "client")) {
|
||||
appendUnique(forgeModEntry("computercraft", proj, component))
|
||||
}
|
||||
}
|
||||
|
||||
if (newClasses.any { it.startsWith("cctest%%") }) {
|
||||
appendUnique(forgeModEntry("cctest", "core", "testFixtures"))
|
||||
appendUnique(forgeModEntry("cctest", "common", "testFixtures"))
|
||||
appendUnique(forgeModEntry("cctest", "common", "testMod"))
|
||||
}
|
||||
|
||||
newClasses.joinToString(":")
|
||||
}
|
||||
}
|
||||
|
||||
private fun forgeModEntry(mod: String, project: String, component: String) =
|
||||
"$mod%%${buildDir.value}/production/${rootProject.name}.$project.$component"
|
||||
|
||||
private fun LocatedDocument.setXml(xpath: String, attribute: String, value: (String?) -> String) {
|
||||
val node = this@IdeaRunConfigurations.xpath.evaluate(xpath, document, XPathConstants.NODE) as Node?
|
||||
if (node == null) {
|
||||
LOGGER.error("[{}] Cannot find {}", path.fileName, xpath)
|
||||
return
|
||||
}
|
||||
|
||||
val attr = node.attributes.getNamedItem(attribute) as Attr? ?: document.createAttribute(attribute)
|
||||
val oldValue = attr.value
|
||||
attr.value = value(attr.value)
|
||||
node.attributes.setNamedItem(attr)
|
||||
|
||||
if (oldValue != attr.value) {
|
||||
LOGGER.info("[{}] Setting {}@{}:\n Old: {}\n New: {}", path.fileName, xpath, attribute, oldValue, attr.value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun withXml(path: Path, run: LocatedDocument.() -> Unit) {
|
||||
val doc = Files.newBufferedReader(path).use { documentBuilder.parse(InputSource(it)) }
|
||||
run(LocatedDocument(path, doc))
|
||||
Files.newBufferedWriter(path).use { writer.transform(DOMSource(doc), StreamResult(it)) }
|
||||
}
|
||||
|
||||
private class LocatedDocument(val path: Path, val document: Document)
|
||||
|
||||
companion object {
|
||||
private val LOGGER = Logging.getLogger(IdeaRunConfigurations::class.java)
|
||||
private val LOCK = Any()
|
||||
|
||||
private val CLASSPATH_ENTRY =
|
||||
Regex("(?<modId>[a-z]+)%%\\\$PROJECT_DIR\\\$/projects/(?<proj>[a-z-]+)/out/(?<component>\\w+)/(?<type>[a-z]+)\$")
|
||||
|
||||
private val forgeConfigs = mapOf(
|
||||
"runClient" to "client",
|
||||
"runData" to "main",
|
||||
"runGameTestServer" to "testMod",
|
||||
"runServer" to "main",
|
||||
"runTestClient" to "testMod",
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -77,13 +77,8 @@ class IlluaminatePlugin : Plugin<Project> {
|
||||
else -> error("Unsupported architecture '$osArch' for illuaminate")
|
||||
}
|
||||
|
||||
return project.dependencies.create(
|
||||
mapOf(
|
||||
"group" to "cc.squiddev",
|
||||
"name" to "illuaminate",
|
||||
"version" to version,
|
||||
"ext" to "$os-$arch$suffix",
|
||||
),
|
||||
return project.dependencyFactory.create(
|
||||
"cc.squiddev", "illuaminate", version, null, "$os-$arch$suffix",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
// 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,7 +24,6 @@ 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]
|
||||
@@ -37,17 +36,10 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
val client = sourceSets.maybeCreate("client")
|
||||
|
||||
// Ensure the client classpaths behave the same as the main ones.
|
||||
configurations.named(client.compileClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
|
||||
}
|
||||
|
||||
configurations.named(client.runtimeClasspathConfigurationName) {
|
||||
shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
|
||||
}
|
||||
consistentWithMain(client)
|
||||
|
||||
// Set up an API configuration for clients (to ensure it's consistent with the main source set).
|
||||
val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = false
|
||||
}
|
||||
@@ -85,6 +77,16 @@ 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"]
|
||||
|
||||
@@ -96,13 +98,30 @@ 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.add(configurations.named(main.runtimeClasspathConfigurationName))
|
||||
configuration.add(configurations.named(client.runtimeClasspathConfigurationName))
|
||||
configuration(configurations.named(main.runtimeClasspathConfigurationName))
|
||||
configuration(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()
|
||||
}
|
||||
@@ -110,6 +129,10 @@ 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.minecraftforge.gradle.common.util.RunConfig
|
||||
import net.neoforged.moddevgradle.internal.RunGameTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.invocation.Gradle
|
||||
@@ -65,11 +65,19 @@ abstract class ClientJavaExec : JavaExec() {
|
||||
setTestProperties()
|
||||
}
|
||||
|
||||
fun copyFromForge(path: String) = copyFromForge(project.tasks.getByName(path, RunGameTask::class))
|
||||
|
||||
/**
|
||||
* Set this task to run a given [RunConfig].
|
||||
* Set this task to run a given [RunGameTask].
|
||||
*/
|
||||
fun setRunConfig(config: RunConfig) {
|
||||
(this as JavaExec).setRunConfig(config)
|
||||
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
|
||||
|
||||
setTestProperties() // setRunConfig may clobber some properties, ensure everything is set.
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ 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) {
|
||||
@@ -43,9 +45,12 @@ abstract class NpmInstall : DefaultTask() {
|
||||
@get:OutputDirectory
|
||||
val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
|
||||
|
||||
@get:Inject
|
||||
protected abstract val execOperations: ExecOperations
|
||||
|
||||
@TaskAction
|
||||
fun install() {
|
||||
project.exec {
|
||||
execOperations.exec {
|
||||
commandLine(ProcessHelpers.getExecutable("npm"), "ci")
|
||||
workingDir = projectRoot.get().asFile
|
||||
}
|
||||
|
||||
@@ -4,45 +4,10 @@
|
||||
|
||||
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() }
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import groovy.util.Node
|
||||
import groovy.util.NodeList
|
||||
|
||||
object XmlUtil {
|
||||
fun findChild(node: Node, name: String): Node? = when (val child = node.get(name)) {
|
||||
is Node -> child
|
||||
is NodeList -> child.singleOrNull() as Node?
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// 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))
|
||||
}
|
||||
@@ -92,7 +92,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<module name="InvalidJavadocPosition" />
|
||||
<module name="JavadocBlockTagLocation" />
|
||||
<module name="JavadocMethod"/>
|
||||
<module name="JavadocType"/>
|
||||
<module name="JavadocType">
|
||||
<!-- Seems to complain about @hidden!? -->
|
||||
<property name="allowUnknownTags" value="true" />
|
||||
</module>
|
||||
<module name="JavadocStyle">
|
||||
<property name="checkHtml" value="false" />
|
||||
</module>
|
||||
@@ -124,7 +127,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</module>
|
||||
<module name="MethodTypeParameterName" />
|
||||
<module name="PackageName">
|
||||
<property name="format" value="^(dan200\.computercraft|cc\.tweaked)(\.[a-z][a-z0-9]*)*" />
|
||||
<property name="format" value="^(dan200\.computercraft|cc\.tweaked|com\.example\.examplemod)(\.[a-z][a-z0-9]*)*" />
|
||||
</module>
|
||||
<module name="ParameterName" />
|
||||
<module name="StaticVariableName">
|
||||
@@ -143,7 +146,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="tokens" value="AT,INC,DEC,UNARY_MINUS,UNARY_PLUS,BNOT,LNOT,DOT,ARRAY_DECLARATOR,INDEX_OP,METHOD_REF" />
|
||||
</module>
|
||||
<module name="NoWhitespaceBefore" />
|
||||
<module name="NoWhitespaceBefore">
|
||||
<!-- Allow whitespace before "..." for @Nullable annotations -->
|
||||
<property name="tokens" value="COMMA,SEMI,POST_INC,POST_DEC,LABELED_STAT" />
|
||||
</module>
|
||||
<!-- TODO: Decide on an OperatorWrap style. -->
|
||||
<module name="ParenPad" />
|
||||
<module name="SeparatorWrap">
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
# 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_cs # Czech
|
||||
cs: cs_cz # Czech
|
||||
da: da_dk # Danish
|
||||
de: de_de # German
|
||||
es-ES: es_es # Spanish
|
||||
fr: fr_fr # French
|
||||
hu: hu_hu # Hungarian
|
||||
it: it_it # Italian
|
||||
ja: ja_jp # Japanese
|
||||
ko: ko_kr # Korean
|
||||
|
||||
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
The [`monitor_resize`] event is fired when an adjacent or networked monitor's size is changed.
|
||||
The [`monitor_resize`] event is fired when an adjacent or networked [monitor's][`monitor`] size is changed.
|
||||
|
||||
## Return Values
|
||||
1. [`string`]: The event name.
|
||||
|
||||
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
The [`monitor_touch`] event is fired when an adjacent or networked Advanced Monitor is right-clicked.
|
||||
The [`monitor_touch`] event is fired when an adjacent or networked [Advanced Monitor][`monitor`] is right-clicked.
|
||||
|
||||
## Return Values
|
||||
1. [`string`]: The event name.
|
||||
|
||||
@@ -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 change.
|
||||
The [`event!redstone`] event is fired whenever any redstone inputs on the computer or [relay][`redstone_relay`] change.
|
||||
|
||||
## Return values
|
||||
1. [`string`]: The event name.
|
||||
@@ -21,3 +21,7 @@ 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`]
|
||||
|
||||
@@ -9,85 +9,68 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
# Setting up GPS
|
||||
The [`gps`] API allows computers and turtles to find their current position using wireless modems.
|
||||
The [`gps`] API allows a computer to find its current position using a [wireless modem][`modem`]. This works by
|
||||
communicating with other computers (called *GPS hosts*) that already know their position, finding the distance to those
|
||||
computers (with [`modem_message`]), and using that to derive its position from theirs (with a process known as
|
||||
[trilateration](https://en.wikipedia.org/wiki/Trilateration).
|
||||
|
||||
In order to use GPS, you'll need to set up multiple *GPS hosts*. These are computers running the special `gps host`
|
||||
program, which tell other computers the host's position. Several hosts running together are known as a *GPS
|
||||
constellation*.
|
||||
In order for this to work, we need our GPS hosts set up in a specific pattern, each one differing in position on at
|
||||
least one axis. This guide takes you through the process of setting up a *constellation* of GPS hosts, and using them to
|
||||
determine a computer's position.
|
||||
|
||||
In order to give the best results, a GPS constellation needs at least four computers. More than four GPS hosts per
|
||||
constellation is redundant, but it does not cause problems.
|
||||
## Prerequisites
|
||||
You will need:
|
||||
|
||||
## Building a GPS constellation
|
||||
<img alt="An example GPS constellation." src="../images/gps-constellation-example.png" class="big-image" />
|
||||
- Four computers.
|
||||
- Four Ender Modems. Normal Wireless Modems maybe be used, but the range of the GPS constellation will be severely
|
||||
limited.
|
||||
|
||||
We are going to build our GPS constellation as shown in the image above. You will need 4 computers and either 4 wireless
|
||||
modems or 4 ender modems. Try not to mix ender and wireless modems together as you might get some odd behavior when your
|
||||
requesting computers are out of range.
|
||||
Additionally, you will need another computer and a wireless modem, in order to test GPS works!
|
||||
|
||||
> [Ender modems vs wireless modems][!TIP]
|
||||
> Ender modems have a very large range, which makes them very useful for setting up GPS hosts. If you do this then you
|
||||
> will likely only need one GPS constellation for the whole dimension (such as the Overworld or Nether).
|
||||
>
|
||||
> If you do use wireless modems then you may find that you need multiple GPS constellations to cover your needs.
|
||||
>
|
||||
> A computer needs a wireless or ender modem and to be in range of a GPS constellation that is in the same dimension as
|
||||
> it to use the GPS API. The reason for this is that ComputerCraft mimics real-life GPS by making use of the distance
|
||||
> parameter of [modem messages][`modem_message`] and some maths.
|
||||
## Picking an area
|
||||
First, choose a place to build your GPS constellation. This should be a 10x10x10 cube, though you can make this smaller
|
||||
if needed. The larger a constellation is, the more accurate it is over large distances, but even a 5x5x5 constellation
|
||||
should serve a several thousand block radius.
|
||||
|
||||
Locate where you want to place your GPS constellation. You will need an area at least 6 blocks high, 6 blocks wide, and
|
||||
6 blocks deep (6x6x6). If you are using wireless modems then you may want to build your constellation as high as you can
|
||||
because high altitude boosts modem message range and thus the radius that your constellation covers.
|
||||
Every computer must be loaded in order for other computers to use GPS, so it is recommended to build your GPS
|
||||
constellation in a single chunk that will always be loaded. You may want to choose an area in an already chunk-loaded
|
||||
part of your base, or in the [spawn chunks][spawn chunks]. You can use <kbd>F3+G</kbd> to view the chunk boundaries if
|
||||
needed.
|
||||
|
||||
The GPS constellation will only work when it is in a loaded chunk. If you want your constellation to always be
|
||||
accessible, you may want to permanently load the chunk using a vanilla or modded chunk loader. Make sure that your 6x6x6
|
||||
area fits in a single chunk to reduce the number of chunks that need to be kept loaded.
|
||||
[spawn chunks]: https://minecraft.wiki/w/Spawn_chunk "Spawn Chunk — Minecraft Wiki"
|
||||
|
||||
Let's get started building the constellation! Place your first computer in one of the corners of your 6x6x6. Remember
|
||||
which computer this is as other computers need to be placed relative to it. Place the second computer 4 blocks above the
|
||||
first. Go back to your first computer and place your third computer 5 blocks in front of your first computer, leaving 4
|
||||
blocks of air between them. Finally for the fourth computer, go back to your first computer and place it 5 blocks right
|
||||
of your first computer, leaving 4 blocks of air between them.
|
||||
This is the example area we will be building our constellation in:
|
||||
|
||||
With all four computers placed within the 6x6x6, place one modem on top of each computer. You should have 4 modems and 4
|
||||
computers all within your 6x6x6 where each modem is attached to a computer and each computer has a modem.
|
||||
<img alt="An empty 10x10x10 area, with the axis marked with smooth stone." src="../images/gps-constellation-area.png" class="big-image" />
|
||||
|
||||
Currently your GPS constellation will not work, that's because each host is not aware that it's a GPS host. We will fix
|
||||
this in the next section.
|
||||
## Building the constellation
|
||||
|
||||
1. Place down your first computer in a corner of your area, and put a modem on top.
|
||||
2. Head to the two adjacent corners of your area, place down another two computers and put a modem on top of each.
|
||||
3. Pillar up above the first computer to the top of your cube, and place the final computer. Place a modem on the
|
||||
computer.
|
||||
|
||||
You should now have something like this:
|
||||
|
||||
<img alt="The same area as before, but with a computer in each corner." src="../images/gps-constellation-built.png" class="big-image" />
|
||||
|
||||
## Configuring the constellation
|
||||
Now that the structure of your constellation is built, we need to configure each host in it.
|
||||
|
||||
Go back to the first computer that you placed and create a startup file, by running `edit startup`.
|
||||
1. Press <kbd>F3</kbd> to open Minecraft's debug screen.
|
||||
2. Go back to the first computer and look at it. On the right of the screen about halfway down you should see an entry
|
||||
labelled `Targeted Block`, the numbers correspond to the position of the block that you are looking at. Write these
|
||||
numbers down.
|
||||
3. Open the computer's UI, and run `edit startup.lua`.
|
||||
4. Type the following code into the file, replacing `x`, `y`, and `z` with the coordinates you just wrote down.
|
||||
|
||||
Type the following code into the file:
|
||||
```lua
|
||||
shell.run("gps", "host", x, y, z)
|
||||
```
|
||||
```lua
|
||||
shell.run("gps", "host", x, y, z)
|
||||
```
|
||||
5. Save the file, and then reboot the computer (hold <kbd>Ctrl+R</kbd> or run the `reboot` program) to run the startup
|
||||
program.
|
||||
|
||||
Escape from the computer GUI and then press <kbd>F3</kbd> to open Minecraft's debug screen and then look at the computer
|
||||
(without opening the GUI). On the right of the screen about halfway down you should see an entry labeled `Targeted
|
||||
Block`, the numbers correspond to the position of the block that you are looking at. Replace `x` with the first number,
|
||||
`y` with the second number, and `z` with the third number.
|
||||
|
||||
For example, if I had a computer at x = 59, y = 5, z = -150, then my <kbd>F3</kbd> debug screen entry would be `Target
|
||||
Block: 59, 5, -150` and I would change my startup file to this `shell.run("gps", "host", 59, 5, -150)`.
|
||||
|
||||
To hide Minecraft's debug screen, press <kbd>F3</kbd> again.
|
||||
|
||||
Create similar startup files for the other computers in your constellation, making sure to input the each computer's own
|
||||
coordinates.
|
||||
|
||||
> [Modem messages come from the computer's position, not the modem's][!WARNING]
|
||||
> Wireless modems transmit from the block that they are attached to *not* the block space that they occupy, the
|
||||
> coordinates that you input into your GPS host should be the position of the computer and not the position of the modem.
|
||||
Repeat this process for the other three computers.
|
||||
|
||||
Congratulations, your constellation is now fully set up! You can test it by placing another computer close by, placing a
|
||||
wireless modem on it, and running the `gps locate` program (or calling the [`gps.locate`] function).
|
||||
|
||||
> [Why use Minecraft's coordinates?][!INFO]
|
||||
> CC doesn't care if you use Minecraft's coordinate system, so long as all of the GPS hosts with overlapping ranges use
|
||||
> the same reference point (requesting computers will get confused if hosts have different reference points). However,
|
||||
> using MC's coordinate system does provide a nice standard to adopt server-wide. It also is consistent with how command
|
||||
> computers get their location, they use MC's command system to get their block which returns that in MC's coordinate
|
||||
> system.
|
||||
|
||||
BIN
doc/images/gps-constellation-area.png
Normal file
BIN
doc/images/gps-constellation-area.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 346 KiB |
BIN
doc/images/gps-constellation-built.png
Normal file
BIN
doc/images/gps-constellation-built.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 335 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 331 KiB |
@@ -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 [CurseForge] or [Modrinth]. It runs on both [Minecraft Forge] and [Fabric].
|
||||
CC: Tweaked can be installed from [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,7 +62,6 @@ 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."
|
||||
|
||||
99
doc/reference/block_details.md
Normal file
99
doc/reference/block_details.md
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
module: [kind=reference] block_details
|
||||
since: 1.64
|
||||
changed: 1.76 Added block state.
|
||||
changed: 1.117.0 Added map colour.
|
||||
---
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
# Block details
|
||||
Several functions in CC: Tweaked, such as [`turtle.inspect`] and [`commands.getBlockInfo`] provide a way to get
|
||||
information about a block in the world. This page details information about blocks that CC: Tweaked may return.
|
||||
|
||||
## Basic information
|
||||
Block information will *always* contain:
|
||||
- `name: string`: The namespaced ID for this block, e.g. `minecraft:dirt`. See [the Minecraft wiki][block ids] for a
|
||||
list of vanilla block IDs.
|
||||
- `state: { [string] = any}`: A table containing the block state of the block.
|
||||
|
||||
### Example
|
||||
A fully hydrated block of farmland:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:farmland",
|
||||
state = {
|
||||
moisture = 7
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
An extended piston, facing upwards:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:piston",
|
||||
state = {
|
||||
facing = "up",
|
||||
extended = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Block tags
|
||||
The [tags][block tags] a block has.
|
||||
|
||||
- `tags: { [string] = boolean }`: The set of tags for this block. This is a mapping of tag name to `true`.
|
||||
|
||||
While the representation of tags is a little more complicated then a single list, this makes it very easy to check if a
|
||||
block has a certain tag:
|
||||
|
||||
```lua
|
||||
--- Check if the block in front of the turtle is a log.
|
||||
local function is_log()
|
||||
local ok, block = turtle.inspect()
|
||||
return ok and block.tags["minecraft:logs"]
|
||||
end
|
||||
```
|
||||
|
||||
### Example
|
||||
A fully hydrated block of farmland:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:farmland",
|
||||
state = { ... },
|
||||
tags = {
|
||||
["minecraft:mineable/shovel"] = true,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Map colour
|
||||
The colour the block will appear on the map, if specified.
|
||||
|
||||
- `mapColour?: number`: The colour of the block, as an RGB hex value.
|
||||
- `mapColor?: number`: The color of the block, as an RGB hex value.
|
||||
|
||||
The map colour is just returned as a plain number (e.g. `9923917` for farmland). It can either be displayed in hex with
|
||||
[`string.format`], or converted to individual RGB values with [`colors.unpackRGB`].
|
||||
|
||||
### Example
|
||||
A fully hydrated block of farmland:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:farmland",
|
||||
state = { ... },
|
||||
mapColour = 9923917,
|
||||
mapColor = 9923917,
|
||||
}
|
||||
```
|
||||
|
||||
[block ids]: https://minecraft.wiki/w/Java_Edition_data_values#Blocks "Java Edition data values on the Minecraft Wiki"
|
||||
[block tags]:https://minecraft.wiki/w/Block_tag_%28Java_Edition%29 "Block tags on the Minecraft Wiki"
|
||||
267
doc/reference/item_details.md
Normal file
267
doc/reference/item_details.md
Normal file
@@ -0,0 +1,267 @@
|
||||
---
|
||||
module: [kind=reference] item_details
|
||||
since: 1.64
|
||||
changed: 1.94.0 Add NBT hash, item tags, lore, enchantment and unbreakable flag.
|
||||
changed: 1.100.9 Add item groups.
|
||||
changed: 1.117.0 Added map colour and potion effects.
|
||||
---
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
# Item details
|
||||
Several functions in CC: Tweaked, such as [`turtle.getItemDetail`] and [`inventory.getItemDetail`] provide a way to get
|
||||
information about an item stack. This page details information about items that CC: Tweaked may return.
|
||||
|
||||
Some methods (such as [`inventory.list`] and [`turtle.getItemDetail`] without the `detailed` flag), will only return
|
||||
the "Basic information" about the item.
|
||||
|
||||
## Basic information
|
||||
Item information will *always* contain:
|
||||
- `name: string`: The namespaced ID for this item, e.g. `minecraft:dirt`. See [the Minecraft wiki][item ids] for a
|
||||
list of vanilla item IDs.
|
||||
- `count: number`: The number of items in the stack.
|
||||
- `nbt?: string`: A hash of the NBT in the stack. While this does not expose any information about the item's NBT, it
|
||||
can be used as a way to compare items. If two items have the same `name` and `nbt`, then all other properties
|
||||
(e.g. durability, enchantment) will be the same.
|
||||
|
||||
### Example
|
||||
A stack of 32 Stripped Acacia Logs:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:stripped_acacia_log",
|
||||
count = 32,
|
||||
}
|
||||
```
|
||||
|
||||
A turtle with an upgrade attached:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "computercraft:turtle_normal",
|
||||
count = 1,
|
||||
nbt = "a33095c2eb17c10e12f2b970c4e1b2bb",
|
||||
}
|
||||
```
|
||||
|
||||
## Display information
|
||||
Common information shown in the item's tooltip:
|
||||
|
||||
- `displayName: string`: The translated display name of the item. This uses the *server's* language. This will
|
||||
typically be English on multi-player servers, and your current language on single player.
|
||||
- `lore: { string... }`: Additional lore about this item, as a list of strings.
|
||||
|
||||
### Example
|
||||
A stack of Stripped Acacia Logs:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:stripped_acacia_log",
|
||||
count = 32,
|
||||
displayName = "Stripped Acacia Log",
|
||||
}
|
||||
```
|
||||
|
||||
## Max count
|
||||
The maximum number of items this item can stack to:
|
||||
|
||||
- `maxCount: number`: The max possible size of the item stack.
|
||||
|
||||
### Example
|
||||
A stack of Stripped Acacia Logs:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:stripped_acacia_log",
|
||||
count = 32,
|
||||
maxCount = 64,
|
||||
}
|
||||
```
|
||||
|
||||
## Item tags
|
||||
The [tags][item tags] an item has.
|
||||
|
||||
- `tags: { [string] = boolean }`: The set of tags for this item. This is a mapping of tag name to `true`.
|
||||
|
||||
While the representation of tags is a little more complicated then a single list, this makes it very easy to check if an
|
||||
item has a certain tag:
|
||||
|
||||
```lua
|
||||
--- Check if the item in the turtle's inventory is a log.
|
||||
local function is_log(slot)
|
||||
local ok, block = turtle.getItemDetail(slot, true)
|
||||
return ok and block.tags["minecraft:logs"]
|
||||
end
|
||||
```
|
||||
|
||||
### Example
|
||||
A stack of Stripped Acacia Logs:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:stripped_acacia_log",
|
||||
count = 32,
|
||||
tags = {
|
||||
["minecraft:acacia_logs"] = true,
|
||||
["minecraft:logs"] = true,
|
||||
["minecraft:logs_that_burn"] = true,
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Item groups
|
||||
The creative tabs this item appears on:
|
||||
|
||||
- `itemGroups: { { id = string, displayName = string }... }`: The item groups this item appears on. Each item group is
|
||||
stored as a table, containing its id and display name.
|
||||
|
||||
> [Version differences][!INFO]
|
||||
> This information is not available on Minecraft 1.19.3 to 1.20.3. This field is present, but empty on those versions.
|
||||
|
||||
### Example
|
||||
A stack of Stripped Acacia Logs:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:stripped_acacia_log",
|
||||
count = 32,
|
||||
itemGroups = {
|
||||
{
|
||||
id = "minecraft:building_blocks",
|
||||
displayName = "Building Blocks"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Damage and durability
|
||||
If this item can be damaged (e.g. a pickaxe), then its damage and durability will be available:
|
||||
- `damage: number`: The amount of damage this item has taken.
|
||||
- `maxDamage: number`: The maximum amount of damage this item has taken.
|
||||
- `durability?: number`: If this item is damaged (i.e. the durability bar is visible), the percentage left on the
|
||||
durability bar, between 0 and 1 (inclusive).
|
||||
- `unbreakable?: boolean`: `true`, if the item is nubreakable
|
||||
|
||||
### Example
|
||||
An unused diamond pickaxe:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:diamond_pickaxe",
|
||||
count = 1,
|
||||
damage = 0,
|
||||
maxDamage = 1561,
|
||||
}
|
||||
```
|
||||
|
||||
A half-used wooden pickaxe:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:wooden_pickaxe",
|
||||
count = 1,
|
||||
damage = 21,
|
||||
maxDamage = 59,
|
||||
durability = 0.615,
|
||||
}
|
||||
```
|
||||
|
||||
## Enchantments
|
||||
The enchantments this item has. This includes both tools and enchanted books.
|
||||
|
||||
- `enchantments: { table... }`: The enchantments this item has. Each enchantment is a table containing several
|
||||
properties:
|
||||
- `name: string`: The namespaced ID for this enchantment, e.g. `minecraft:efficiency`. See [the Minecraft
|
||||
wiki][enchantment ids] for a list of vanilla enchantment IDs.
|
||||
- `displayName: string`: The translated display name for this enchantment.
|
||||
- `level: number`: The level for this enchantment.
|
||||
|
||||
### Example
|
||||
A diamond pickaxe with Efficiency V:
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:diamond_pickaxe",
|
||||
count = 1,
|
||||
enchantments = {
|
||||
{
|
||||
name = "minecraft:efficiency",
|
||||
level = 5,
|
||||
displayName = "Efficiency V",
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Potion effects
|
||||
The effects this potion (or potion-embued item, such as a tipped arrow) has:
|
||||
|
||||
- `potionEffects: { table... }`: The effects this item has. Each potion effect is a table containing several
|
||||
properties:
|
||||
- `name: string`: The namespaced ID for this effect, e.g. `minecraft:regeneration`. See [the Minecraft wiki][effect
|
||||
ids] for a list of vanilla effect IDs.
|
||||
- `displayName: string`: The translated display name for this potion effect.
|
||||
- `duration?: number`: The duration this effect will last for (if not instant), in seconds.
|
||||
- `potency?: number`: The potency of this potion.
|
||||
|
||||
### Example
|
||||
A basic Potion of Healing:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:potion",
|
||||
displayName = "Potion of Healing",
|
||||
potionEffects = {
|
||||
{
|
||||
name = "minecraft:instant_health",
|
||||
displayName = "Instant Health",
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
An upgraded Potion of Regeneration:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:potion",
|
||||
displayName = "Potion of Regeneration",
|
||||
potionEffects = {
|
||||
{
|
||||
name = "minecraft:regeneration",
|
||||
displayName = "Regeneration II",
|
||||
duration = 22.5,
|
||||
potency = 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
## Map colour
|
||||
The colour the item's block form will appear on the map, if specified.
|
||||
|
||||
- `mapColour?: number`: The colour of the block, as an RGB hex value.
|
||||
- `mapColor?: number`: The color of the block, as an RGB hex value.
|
||||
|
||||
The map colour is just returned as a plain number (e.g. `9923917` for dirt). It can either be displayed in hex with
|
||||
[`string.format`], or converted to individual RGB values with [`colors.unpackRGB`].
|
||||
|
||||
### Example
|
||||
A stack of Stripped Acacia Logs:
|
||||
|
||||
```lua {data-no-run=1}
|
||||
{
|
||||
name = "minecraft:stripped_acacia_log",
|
||||
count = 32,
|
||||
mapColour = 14188339,
|
||||
mapColor = 14188339,
|
||||
}
|
||||
```
|
||||
|
||||
[item ids]: https://minecraft.wiki/w/Java_Edition_data_values#Items "Java Edition data values on the Minecraft Wiki"
|
||||
[item tags]:https://minecraft.wiki/w/Item_tag_%28Java_Edition%29 "Item tags on the Minecraft Wiki"
|
||||
[effect ids]: https://minecraft.wiki/w/Java_Edition_data_values#Effects "Java Edition data values on the Minecraft Wiki"
|
||||
[enchantment ids]: https://minecraft.wiki/w/Java_Edition_data_values#Enchantments "Java Edition data values on the Minecraft Wiki"
|
||||
@@ -117,10 +117,14 @@ function read(replaceChar, history, completeFn, default) end
|
||||
-- Outside of Minecraft (for instance, in an emulator) [`_HOST`] will contain the
|
||||
-- emulator's version instead.
|
||||
--
|
||||
-- If you need to check for the presence of a feature, it is usually better to
|
||||
-- rely on feature detection, rather than comparing mod or Minecraft versions.
|
||||
--
|
||||
-- For example, `ComputerCraft 1.93.0 (Minecraft 1.15.2)`.
|
||||
-- @usage Print the current computer's environment.
|
||||
--
|
||||
-- print(_HOST)
|
||||
-- @see os.version
|
||||
-- @since 1.76
|
||||
_HOST = _HOST
|
||||
|
||||
|
||||
@@ -100,8 +100,12 @@ function sleep(time) end
|
||||
-- This is defined by `bios.lua`. For the current version of CC:Tweaked, this
|
||||
-- should return `CraftOS 1.9`.
|
||||
--
|
||||
-- If you need to check for the presence of a feature, it is usually better to
|
||||
-- rely on feature detection, rather than comparing CraftOS versions.
|
||||
--
|
||||
-- @treturn string The current CraftOS version.
|
||||
-- @usage os.version()
|
||||
-- @see _G._HOST
|
||||
function version() end
|
||||
|
||||
--[[- Run the program at the given path with the specified environment and
|
||||
|
||||
@@ -7,8 +7,11 @@ The turtle's inventory should set up like a crafting grid. For instance, to
|
||||
craft sticks, slots 1 and 5 should contain planks. _All_ other slots should be
|
||||
empty, including those outside the crafting "grid".
|
||||
|
||||
`turtle.craft(0)` can be used to check whether the turtle contains a valid
|
||||
recipe, without actually crafting it.
|
||||
|
||||
@tparam[opt=64] number limit The maximum number of crafting steps to run.
|
||||
@throws When limit is less than 1 or greater than 64.
|
||||
@throws When limit is less than 0 or greater than 64.
|
||||
@treturn[1] true If crafting succeeds.
|
||||
@treturn[2] false If crafting fails.
|
||||
@treturn string A string describing why crafting failed.
|
||||
|
||||
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
|
||||
|
||||
# Mod properties
|
||||
isUnstable=false
|
||||
modVersion=1.113.1
|
||||
modVersion=1.117.1
|
||||
|
||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||
mcVersion=1.20.1
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#This file is generated by updateDaemonJvm
|
||||
toolchainVersion=17
|
||||
toolchainVersion=25
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||
# Remember to update corresponding versions in fabric.mod.json/mods.toml
|
||||
fabric-api = "0.86.1+1.20.1"
|
||||
fabric-loader = "0.14.21"
|
||||
fabric-loader = "0.18.4"
|
||||
forge = "47.1.0"
|
||||
forgeSpi = "7.0.1"
|
||||
mixin = "0.8.5"
|
||||
@@ -23,17 +23,17 @@ netty = "4.1.82.Final"
|
||||
slf4j = "2.0.1"
|
||||
|
||||
# Core dependencies (independent of Minecraft)
|
||||
asm = "9.6"
|
||||
asm = "9.9.1"
|
||||
autoService = "1.1.1"
|
||||
checkerFramework = "3.42.0"
|
||||
cobalt = "0.9.4"
|
||||
commonsCli = "1.6.0"
|
||||
jetbrainsAnnotations = "24.1.0"
|
||||
jsr305 = "3.0.2"
|
||||
checkerFramework = "3.51.1"
|
||||
cobalt = { strictly = "0.9.7" }
|
||||
commonsCli = "1.10.0"
|
||||
jetbrainsAnnotations = "26.0.2-1"
|
||||
jspecify = "1.0.0"
|
||||
jzlib = "1.1.3"
|
||||
kotlin = "1.9.21"
|
||||
kotlin-coroutines = "1.7.3"
|
||||
nightConfig = "3.6.7"
|
||||
kotlin = "2.3.0"
|
||||
kotlin-coroutines = "1.10.2"
|
||||
nightConfig = "3.8.3"
|
||||
|
||||
# Minecraft mods
|
||||
emi = "1.0.8+1.20.1"
|
||||
@@ -46,37 +46,35 @@ oculus = "1.2.5"
|
||||
rei = "12.0.626"
|
||||
rubidium = "0.6.1"
|
||||
sodium = "mc1.20-0.4.10"
|
||||
create-forge = "0.5.1.f-33"
|
||||
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
||||
create-forge = "6.0.0-9"
|
||||
create-fabric = "6.0.7.0+mc1.20.1-build.1716"
|
||||
|
||||
# Testing
|
||||
hamcrest = "2.2"
|
||||
jqwik = "1.8.2"
|
||||
junit = "5.10.1"
|
||||
hamcrest = "3.0"
|
||||
jqwik = "1.9.3"
|
||||
junit = "6.0.1"
|
||||
junitPlatform = "6.0.1"
|
||||
jmh = "1.37"
|
||||
|
||||
# Build tools
|
||||
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.7.1"
|
||||
forgeGradle = "6.0.21"
|
||||
cctJavadoc = "1.9.0"
|
||||
checkstyle = "12.1.1"
|
||||
errorProne-core = "2.45.0"
|
||||
errorProne-plugin = "4.3.0"
|
||||
fabric-loom = "1.15.2"
|
||||
githubRelease = "2.5.2"
|
||||
gradleVersions = "0.50.0"
|
||||
ideaExt = "1.1.7"
|
||||
illuaminate = "0.1.0-73-g43ee16c"
|
||||
librarian = "1.+"
|
||||
lwjgl = "3.3.3"
|
||||
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.1.3"
|
||||
versionCatalogUpdate = "0.8.1"
|
||||
gradleVersions = "0.53.0"
|
||||
ideaExt = "1.3"
|
||||
illuaminate = "0.1.0-83-g1131f68"
|
||||
lwjgl = "3.3.6"
|
||||
minotaur = "2.8.7"
|
||||
modDevGradle = "2.0.140"
|
||||
nullAway = "0.12.11"
|
||||
shadow = "9.2.2"
|
||||
spotless = "8.0.0"
|
||||
teavm = "0.14.0-SQUID.1"
|
||||
vanillaExtract = "0.3.1"
|
||||
versionCatalogUpdate = "1.0.1"
|
||||
|
||||
[libraries]
|
||||
# Normal dependencies
|
||||
@@ -90,7 +88,7 @@ fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
|
||||
forgeSpi = { module = "net.minecraftforge:forgespi", version.ref = "forgeSpi" }
|
||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||
jetbrainsAnnotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
|
||||
jsr305 = { module = "com.google.code.findbugs:jsr305", version.ref = "jsr305" }
|
||||
jspecify = { module = "org.jspecify:jspecify", version.ref = "jspecify" }
|
||||
jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" }
|
||||
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
|
||||
kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
|
||||
@@ -132,6 +130,7 @@ 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,19 +144,17 @@ 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" }
|
||||
@@ -172,17 +169,14 @@ 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" }
|
||||
|
||||
[bundles]
|
||||
annotations = ["jsr305", "checkerFramework", "jetbrainsAnnotations"]
|
||||
annotations = ["checkerFramework", "jetbrainsAnnotations", "jspecify"]
|
||||
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
||||
|
||||
# Minecraft
|
||||
@@ -194,7 +188,7 @@ externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
|
||||
|
||||
# Testing
|
||||
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
||||
testRuntime = ["junit-jupiter-engine", "jqwik-engine"]
|
||||
testRuntime = ["junit-jupiter-engine", "junit-platform-launcher", "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.10-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
12
gradlew
vendored
12
gradlew
vendored
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
# Copyright © 2015 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -86,8 +86,7 @@ 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
|
||||
' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -115,7 +114,6 @@ case "$( uname )" in #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
@@ -173,7 +171,6 @@ fi
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
@@ -206,15 +203,14 @@ fi
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
|
||||
3
gradlew.bat
vendored
3
gradlew.bat
vendored
@@ -70,11 +70,10 @@ goto fail
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
|
||||
1765
package-lock.json
generated
1765
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,14 +9,15 @@
|
||||
"@squid-dev/cc-web-term": "^2.0.0",
|
||||
"preact": "^10.5.5",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tslib": "^2.0.3"
|
||||
"tslib": "^2.0.3",
|
||||
"wasm-feature-detect": "^1.8.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
"@rollup/plugin-typescript": "^12.0.0",
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@swc/core": "^1.3.92",
|
||||
"@types/node": "^20.8.3",
|
||||
"@types/node": "^25.0.0",
|
||||
"lightningcss": "^1.22.0",
|
||||
"preact-render-to-string": "^6.2.1",
|
||||
"rehype": "^13.0.0",
|
||||
|
||||
@@ -8,6 +8,8 @@ plugins {
|
||||
id("cc-tweaked.vanilla")
|
||||
}
|
||||
|
||||
val mcVersion: String by extra
|
||||
|
||||
java {
|
||||
withJavadocJar()
|
||||
}
|
||||
@@ -16,9 +18,70 @@ 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(),
|
||||
)
|
||||
|
||||
val snippetSources = listOf(":common", ":fabric", ":forge").flatMap {
|
||||
project(it).sourceSets["examples"].allSource.sourceDirectories
|
||||
}
|
||||
inputs.files(snippetSources)
|
||||
addPathOption("-snippet-path").value = snippetSources
|
||||
}
|
||||
|
||||
// Include the core-api in our javadoc export. This is wrong, but it means we can export a single javadoc dump.
|
||||
source(project(":core-api").sourceSets.main.map { it.allJava })
|
||||
|
||||
options {
|
||||
this as StandardJavadocDocletOptions
|
||||
addBooleanOption("-allow-script-in-comments", true)
|
||||
bottom(
|
||||
"""
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/components/prism-core.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/prismjs@v1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
||||
<link href=" https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism.min.css " rel="stylesheet">
|
||||
""".trimIndent(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@@ -22,7 +22,14 @@ 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
|
||||
* 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}
|
||||
*
|
||||
* @param <T> The type of turtle upgrade this modeller applies to.
|
||||
* @see RegisterTurtleUpgradeModeller For multi-loader registration support.
|
||||
|
||||
@@ -14,8 +14,7 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
final class TurtleUpgradeModellers {
|
||||
private static final Transformation leftTransform = getMatrixFor(-0.4065f);
|
||||
|
||||
@@ -11,8 +11,7 @@ import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@ApiStatus.Internal
|
||||
public interface ClientPlatformHelper {
|
||||
|
||||
@@ -10,8 +10,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Backing interface for {@link ComputerCraftAPIClient}
|
||||
|
||||
@@ -26,8 +26,7 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* The static entry point to the ComputerCraft API.
|
||||
@@ -171,16 +170,9 @@ 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 an additional API just to turtles with the following code:
|
||||
* computers. For example, one can add a new API just to turtles with the following code:
|
||||
*
|
||||
* <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>
|
||||
* {@snippet class=com.example.examplemod.ExampleAPI region=register}
|
||||
*
|
||||
* @param factory The factory for your API subclass.
|
||||
* @see ILuaAPIFactory
|
||||
|
||||
@@ -26,6 +26,20 @@ public class ComputerCraftTags {
|
||||
public static final TagKey<Item> WIRED_MODEM = make("wired_modem");
|
||||
public static final TagKey<Item> MONITOR = make("monitor");
|
||||
|
||||
/**
|
||||
* Floppy disks. Both the read/write version, and treasure disks.
|
||||
*
|
||||
* @since 1.116.0
|
||||
*/
|
||||
public static final TagKey<Item> DISKS = make("disks");
|
||||
|
||||
/**
|
||||
* All pocket computers.
|
||||
*
|
||||
* @since 1.116.0
|
||||
*/
|
||||
public static final TagKey<Item> POCKET_COMPUTERS = make("pocket_computers");
|
||||
|
||||
/**
|
||||
* Items which can be {@linkplain Item#use(Level, Player, InteractionHand) used} when calling
|
||||
* {@code turtle.place()}.
|
||||
|
||||
@@ -6,8 +6,8 @@ package dan200.computercraft.api.detail;
|
||||
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
@@ -8,8 +8,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A reference to a block in the world, used by block detail providers.
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.Map;
|
||||
*
|
||||
* @param <T> The type of object that this provider can provide details for.
|
||||
* @see DetailRegistry
|
||||
* @see dan200.computercraft.api.detail An overview of the detail system.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DetailProvider<T> {
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.Map;
|
||||
* also in this package.
|
||||
*
|
||||
* @param <T> The type of object that this registry provides details for.
|
||||
* @see dan200.computercraft.api.detail An overview of the detail system.
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
public interface DetailRegistry<T> {
|
||||
|
||||
@@ -17,6 +17,9 @@ public class VanillaDetailRegistries {
|
||||
* <p>
|
||||
* This instance's {@link DetailRegistry#getBasicDetails(Object)} is thread safe (assuming the stack is immutable)
|
||||
* and may be called from the computer thread.
|
||||
* <p>
|
||||
* This does not have special handling for {@linkplain ItemStack#isEmpty() empty item stacks}, and so the returned
|
||||
* details will be an empty stack of air. Callers should generally check for empty stacks before calling this.
|
||||
*/
|
||||
public static final DetailRegistry<ItemStack> ITEM_STACK = ComputerCraftAPIService.get().getItemStackDetailRegistry();
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
/**
|
||||
* The detail system provides a standard way for mods to return descriptions of common game objects, such as blocks or
|
||||
* items, as well as registering additional detail to be included in those descriptions.
|
||||
* <p>
|
||||
* For instance, the built-in {@code turtle.getItemDetail()} method uses
|
||||
* {@linkplain dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK in order to provide information about}
|
||||
* the selected item:
|
||||
*
|
||||
* <pre class="language language-lua">{@code
|
||||
* local item = turtle.getItemDetail(nil, true)
|
||||
* --[[
|
||||
* item = {
|
||||
* name = "minecraft:wheat",
|
||||
* displayName = "Wheat",
|
||||
* count = 1,
|
||||
* maxCount = 64,
|
||||
* tags = {},
|
||||
* }
|
||||
* ]]
|
||||
* }</pre>
|
||||
*
|
||||
* <h2>Built-in detail providers</h2>
|
||||
* While you can define your own detail providers (perhaps for types from your own mod), CC comes with several built-in
|
||||
* detail registries for vanilla and mod-loader objects:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link dan200.computercraft.api.detail.VanillaDetailRegistries}, for vanilla objects</li>
|
||||
* <li>{@code dan200.computercraft.api.detail.ForgeDetailRegistries} for Forge-specific objects</li>
|
||||
* <li>{@code dan200.computercraft.api.detail.FabricDetailRegistries} for Fabric-specific objects</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Example: Returning details from methods</h2>
|
||||
* Here we define a {@code getHeldItem()} method for pocket computers which finds the currently held item of the player
|
||||
* and returns it to the user using {@link dan200.computercraft.api.detail.VanillaDetailRegistries#ITEM_STACK} and
|
||||
* {@link dan200.computercraft.api.detail.DetailRegistry#getDetails(java.lang.Object)}.
|
||||
*
|
||||
* {@snippet class=com.example.examplemod.ExamplePocketPeripheral region=details}
|
||||
*
|
||||
* <h2>Example: Registering custom detail registries</h2>
|
||||
* Here we define a new detail provider for items that includes the nutrition and saturation values in the returned object.
|
||||
*
|
||||
* {@snippet class=com.example.examplemod.ExampleMod region=details}
|
||||
*/
|
||||
package dan200.computercraft.api.detail;
|
||||
@@ -9,8 +9,7 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An interface passed to {@link ILuaAPIFactory} in order to provide additional information
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
package dan200.computercraft.api.lua;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Construct an {@link ILuaAPI} for a computer.
|
||||
|
||||
@@ -12,8 +12,7 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Represents an item that can be placed in a disk drive and used by a Computer.
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
package dan200.computercraft.api.media;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* This interface is used to provide {@link IMedia} implementations for {@link ItemStack}.
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.api.media;
|
||||
|
||||
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* The contents of a page (or book) created by a ComputerCraft printer.
|
||||
*
|
||||
* @since 1.115
|
||||
*/
|
||||
@Nullable
|
||||
public interface PrintoutContents {
|
||||
/**
|
||||
* Get the (possibly empty) title for this printout.
|
||||
*
|
||||
* @return The title of this printout.
|
||||
*/
|
||||
String getTitle();
|
||||
|
||||
/**
|
||||
* Get the text contents of this printout, as a sequence of lines.
|
||||
* <p>
|
||||
* The lines in the printout may include blank lines at the end of the document, as well as trailing spaces on each
|
||||
* line.
|
||||
*
|
||||
* @return The text contents of this printout.
|
||||
*/
|
||||
Stream<String> getTextLines();
|
||||
|
||||
/**
|
||||
* Get the printout contents for a particular stack.
|
||||
*
|
||||
* @param stack The stack to get the contents for.
|
||||
* @return The printout contents, or {@code null} if this is not a printout item.
|
||||
*/
|
||||
static @Nullable PrintoutContents get(ItemStack stack) {
|
||||
return ComputerCraftAPIService.get().getPrintoutContents(stack);
|
||||
}
|
||||
}
|
||||
@@ -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 tile entity in world. In such as case, one should provide the
|
||||
* Elements are generally tied to a block or block 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 objects on the network change. This may occur when network nodes are added or removed, or when
|
||||
* peripherals change.
|
||||
* 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.
|
||||
*
|
||||
* @param change The change which occurred.
|
||||
* @see WiredNetworkChange
|
||||
|
||||
@@ -14,8 +14,8 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,20 +7,16 @@ package dan200.computercraft.api.pocket;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.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 Forge registry.
|
||||
* {@link PocketUpgradeSerialiser} instance, which are then registered in a Minecraft 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. 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.
|
||||
* the upgrade registered internally.
|
||||
*/
|
||||
public interface IPocketUpgrade extends UpgradeBase {
|
||||
/**
|
||||
|
||||
@@ -17,8 +17,7 @@ import net.minecraft.world.Container;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* The interface passed to turtle by turtles, providing methods that they can call.
|
||||
|
||||
@@ -8,21 +8,69 @@ 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 org.jspecify.annotations.Nullable;
|
||||
|
||||
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 Forge registry.
|
||||
* {@link TurtleUpgradeSerialiser} instance, which are then registered in a Minecraft 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. See the documentation in {@link TurtleUpgradeSerialiser} for details on this process
|
||||
* and where files should be located.
|
||||
* the upgrade automatically registered.
|
||||
*
|
||||
* @see TurtleUpgradeSerialiser For how to register a turtle upgrade.
|
||||
* <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.
|
||||
*
|
||||
* {@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.
|
||||
*/
|
||||
public interface ITurtleUpgrade extends UpgradeBase {
|
||||
/**
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
package dan200.computercraft.api.turtle;
|
||||
|
||||
import net.minecraft.core.Direction;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Used to indicate the result of executing a turtle command.
|
||||
@@ -60,9 +59,9 @@ public final class TurtleCommandResult {
|
||||
|
||||
private final boolean success;
|
||||
private final @Nullable String errorMessage;
|
||||
private final @Nullable Object[] results;
|
||||
private final @Nullable Object @Nullable [] results;
|
||||
|
||||
private TurtleCommandResult(boolean success, @Nullable String errorMessage, @Nullable Object[] results) {
|
||||
private TurtleCommandResult(boolean success, @Nullable String errorMessage, @Nullable Object @Nullable [] results) {
|
||||
this.success = success;
|
||||
this.errorMessage = errorMessage;
|
||||
this.results = results;
|
||||
@@ -92,8 +91,7 @@ public final class TurtleCommandResult {
|
||||
*
|
||||
* @return The command's result, or {@code null} if it was a failure.
|
||||
*/
|
||||
@Nullable
|
||||
public Object[] getResults() {
|
||||
public @Nullable Object @Nullable [] getResults() {
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -29,6 +29,9 @@ 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,32 +27,6 @@ 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
|
||||
|
||||
@@ -9,8 +9,7 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* An upgrade (i.e. a {@link ITurtleUpgrade}) and its current upgrade data.
|
||||
|
||||
@@ -19,8 +19,8 @@ import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
@@ -32,6 +32,8 @@ 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;
|
||||
@@ -84,13 +86,9 @@ public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends Upgra
|
||||
|
||||
/**
|
||||
* Add all turtle or pocket computer upgrades.
|
||||
* <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>
|
||||
*
|
||||
* <h4>Example</h4>
|
||||
* {@snippet class=com.example.examplemod.data.TurtleDataProvider region=body}
|
||||
*
|
||||
* @param addUpgrade A callback used to register an upgrade.
|
||||
*/
|
||||
|
||||
@@ -12,6 +12,7 @@ import dan200.computercraft.api.filesystem.WritableMount;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||
import dan200.computercraft.api.media.MediaProvider;
|
||||
import dan200.computercraft.api.media.PrintoutContents;
|
||||
import dan200.computercraft.api.network.PacketNetwork;
|
||||
import dan200.computercraft.api.network.wired.WiredElement;
|
||||
import dan200.computercraft.api.network.wired.WiredNode;
|
||||
@@ -27,8 +28,7 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Backing interface for {@link ComputerCraftAPI}
|
||||
@@ -75,6 +75,9 @@ public interface ComputerCraftAPIService {
|
||||
|
||||
DetailRegistry<BlockReference> getBlockInWorldDetailRegistry();
|
||||
|
||||
@Nullable
|
||||
PrintoutContents getPrintoutContents(ItemStack stack);
|
||||
|
||||
final class Instance {
|
||||
static final @Nullable ComputerCraftAPIService INSTANCE;
|
||||
static final @Nullable Throwable ERROR;
|
||||
|
||||
@@ -12,8 +12,7 @@ import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Abstraction layer for Forge and Fabric. See implementations for more details.
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
package dan200.computercraft.impl;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.Serial;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
package dan200.computercraft.impl;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
68
projects/common-api/src/overview.html
Normal file
68
projects/common-api/src/overview.html
Normal file
@@ -0,0 +1,68 @@
|
||||
<!--
|
||||
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,17 +6,11 @@ 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",
|
||||
@@ -43,7 +37,6 @@ dependencies {
|
||||
clientApi(clientClasses(project(":common-api")))
|
||||
|
||||
compileOnly(libs.bundles.externalMods.common)
|
||||
compileOnly(variantOf(libs.create.forge) { classifier("slim") }) { isTransitive = false }
|
||||
clientCompileOnly(variantOf(libs.emi) { classifier("api") })
|
||||
|
||||
annotationProcessorEverywhere(libs.autoService)
|
||||
@@ -67,7 +60,7 @@ dependencies {
|
||||
}
|
||||
|
||||
illuaminate {
|
||||
version.set(libs.versions.illuaminate)
|
||||
version = libs.versions.illuaminate
|
||||
}
|
||||
|
||||
val luaJavadoc by tasks.registering(Javadoc::class) {
|
||||
@@ -88,11 +81,7 @@ val luaJavadoc by tasks.registering(Javadoc::class) {
|
||||
options.addStringOption("project-root", rootProject.file(".").absolutePath)
|
||||
options.noTimestamp(false)
|
||||
|
||||
javadocTool.set(
|
||||
javaToolchains.javadocToolFor {
|
||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
||||
},
|
||||
)
|
||||
javadocTool = javaToolchains.javadocToolFor { languageVersion = CCTweakedPlugin.JDK_VERSION }
|
||||
}
|
||||
|
||||
val lintLua by tasks.registering(IlluaminateExec::class) {
|
||||
@@ -113,20 +102,31 @@ val lintLua by tasks.registering(IlluaminateExec::class) {
|
||||
doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
|
||||
}
|
||||
|
||||
val runData by tasks.registering(MergeTrees::class) {
|
||||
output = layout.projectDirectory.dir("src/generated/resources")
|
||||
fun MergeTrees.configureForDatagen(source: SourceSet, outputFolder: String) {
|
||||
output = layout.projectDirectory.dir(outputFolder)
|
||||
|
||||
for (loader in listOf("forge", "fabric")) {
|
||||
mustRunAfter(":$loader:runData")
|
||||
mustRunAfter(":$loader:$name")
|
||||
source {
|
||||
input {
|
||||
from(project(":$loader").layout.buildDirectory.dir("generatedResources"))
|
||||
from(project(":$loader").layout.buildDirectory.dir(source.getTaskName("generateResources", null)))
|
||||
exclude(".cache")
|
||||
}
|
||||
|
||||
output = project(":$loader").layout.projectDirectory.dir("src/generated/resources")
|
||||
output = project(":$loader").layout.projectDirectory.dir(outputFolder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(GenerateModuleMetadata::class).configureEach { isEnabled = false }
|
||||
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
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -64,6 +64,9 @@ public final class ClientHooks {
|
||||
public static void onWorldUnload() {
|
||||
MonitorRenderState.destroyAll();
|
||||
SpeakerManager.reset();
|
||||
}
|
||||
|
||||
public static void onDisconnect() {
|
||||
ClientPocketComputers.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -46,8 +46,10 @@ import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -63,6 +65,8 @@ import java.util.function.Supplier;
|
||||
* @see ModRegistry The common registry for actual game objects.
|
||||
*/
|
||||
public final class ClientRegistry {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ClientRegistry.class);
|
||||
|
||||
private ClientRegistry() {
|
||||
}
|
||||
|
||||
@@ -85,6 +89,7 @@ public final class ClientRegistry {
|
||||
public static void registerMainThread(RegisterItemProperty itemProperties) {
|
||||
MenuScreens.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.COMPUTER.get(), ComputerScreen::new);
|
||||
MenuScreens.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
|
||||
MenuScreens.register(ModRegistry.Menus.POCKET_COMPUTER_LECTERN.get(), PocketComputerLecternScreen::new);
|
||||
MenuScreens.register(ModRegistry.Menus.TURTLE.get(), TurtleScreen::new);
|
||||
|
||||
MenuScreens.register(ModRegistry.Menus.PRINTER.get(), PrinterScreen::new);
|
||||
@@ -182,7 +187,18 @@ public final class ClientRegistry {
|
||||
}
|
||||
|
||||
public static void registerShaders(ResourceProvider resources, BiConsumer<ShaderInstance, Consumer<ShaderInstance>> load) throws IOException {
|
||||
RenderTypes.registerShaders(resources, load);
|
||||
RenderTypes.registerShaders(resources, (name, create, onLoaded) -> {
|
||||
ShaderInstance shader;
|
||||
try {
|
||||
shader = create.get();
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to load {}", name, e);
|
||||
onLoaded.accept(null);
|
||||
return;
|
||||
}
|
||||
|
||||
load.accept(shader, onLoaded);
|
||||
});
|
||||
}
|
||||
|
||||
private record UnclampedPropertyFunction(
|
||||
|
||||
@@ -15,8 +15,8 @@ import net.minecraft.client.gui.components.ChatComponent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,10 +8,10 @@ import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
||||
import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.core.input.UserComputerInput;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import dan200.computercraft.shared.computer.upload.FileUpload;
|
||||
import dan200.computercraft.shared.computer.upload.UploadResult;
|
||||
@@ -26,11 +26,11 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
@@ -58,7 +58,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
protected @Nullable TerminalWidget terminal;
|
||||
protected Terminal terminalData;
|
||||
protected final ComputerFamily family;
|
||||
protected final InputHandler input;
|
||||
protected final UserComputerInput computerInput;
|
||||
protected final ClientComputerActions computerActions;
|
||||
|
||||
protected final int sidebarYOffset;
|
||||
|
||||
@@ -72,7 +73,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
family = container.getFamily();
|
||||
displayStack = container.getDisplayStack();
|
||||
uploadMaxSize = container.getUploadMaxSize();
|
||||
input = new ClientInputHandler(menu);
|
||||
computerInput = new UserComputerInput(new ClientComputerInput(menu), menu.getTerminal());
|
||||
computerActions = new ClientComputerActions(menu);
|
||||
this.sidebarYOffset = sidebarYOffset;
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
super.init();
|
||||
|
||||
terminal = addRenderableWidget(createTerminal());
|
||||
ComputerSidebar.addButtons(menu::isOn, input, this::addRenderableWidget, leftPos, topPos + sidebarYOffset);
|
||||
ComputerSidebar.addButtons(menu::isOn, computerActions, this::addRenderableWidget, leftPos, topPos + sidebarYOffset);
|
||||
setFocused(terminal);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
|
||||
/**
|
||||
* Actions that can be applied to a computer.
|
||||
*
|
||||
* @see ComputerActionServerMessage
|
||||
*/
|
||||
public final class ClientComputerActions {
|
||||
private final AbstractContainerMenu menu;
|
||||
|
||||
public ClientComputerActions(AbstractContainerMenu menu) {
|
||||
this.menu = menu;
|
||||
}
|
||||
|
||||
public void terminate() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TERMINATE));
|
||||
}
|
||||
|
||||
public void turnOn() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.SHUTDOWN));
|
||||
}
|
||||
|
||||
public void reboot() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
|
||||
}
|
||||
}
|
||||
@@ -5,48 +5,27 @@
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
import dan200.computercraft.core.input.ComputerInput;
|
||||
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.QueueEventServerMessage;
|
||||
import dan200.computercraft.shared.network.server.PasteEventComputerMessage;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* An {@link InputHandler} for use on the client.
|
||||
* An {@link ComputerInput} for use on the client.
|
||||
* <p>
|
||||
* This queues events on the remote player's open {@link ComputerMenu}.
|
||||
* This queues events on the player's open {@link ComputerMenu}.
|
||||
*/
|
||||
public final class ClientInputHandler implements InputHandler {
|
||||
public final class ClientComputerInput implements ComputerInput {
|
||||
private final AbstractContainerMenu menu;
|
||||
|
||||
public ClientInputHandler(AbstractContainerMenu menu) {
|
||||
public ClientComputerInput(AbstractContainerMenu menu) {
|
||||
this.menu = menu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void turnOn() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.SHUTDOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reboot() {
|
||||
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,6 +36,16 @@ 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));
|
||||
@@ -33,7 +33,10 @@ public final class ComputerScreen<T extends AbstractComputerMenu> extends Abstra
|
||||
|
||||
@Override
|
||||
protected TerminalWidget createTerminal() {
|
||||
return new TerminalWidget(terminalData, input, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH + BORDER, topPos + BORDER);
|
||||
return new TerminalWidget(
|
||||
terminalData, computerInput, computerActions,
|
||||
leftPos + AbstractComputerMenu.SIDEBAR_WIDTH + BORDER, topPos + BORDER
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,14 +6,13 @@ 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;
|
||||
import net.minecraft.client.resources.TextureAtlasHolder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -33,10 +32,13 @@ 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/buttons/" + name),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/buttons/" + name + "_hover")
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/sprites/buttons/" + name),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/sprites/buttons/" + name + "_hover")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -113,7 +115,6 @@ public final class GuiSprites extends TextureAtlasHolder {
|
||||
* @param pocketBottom The texture for the bottom of a pocket computer.
|
||||
* @param sidebar The texture for the computer sidebar.
|
||||
* @see ComputerBorderRenderer
|
||||
* @see ClientDataProviders
|
||||
*/
|
||||
public record ComputerTextures(
|
||||
ResourceLocation border,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user