mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-16 14:37:39 +00:00
Compare commits
155 Commits
v1.21-1.11
...
v1.21.1-1.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4710ee5bcc | ||
![]() |
62c9e5b08f | ||
![]() |
2ca5850060 | ||
![]() |
ed631b05e7 | ||
![]() |
a2b9490d5c | ||
![]() |
8204944b5f | ||
![]() |
ef0af67e96 | ||
![]() |
9a914e75c4 | ||
![]() |
4a532952d4 | ||
![]() |
546577041b | ||
![]() |
f881c0ced0 | ||
![]() |
0b389e04b0 | ||
![]() |
d3a3ab3c21 | ||
![]() |
22e6c06e59 | ||
![]() |
7337b91692 | ||
![]() |
3c46b8acd7 | ||
![]() |
d9fc1c3a80 | ||
![]() |
479aabdd09 | ||
![]() |
ad74893058 | ||
![]() |
2ba6d5815b | ||
![]() |
7e2f490626 | ||
![]() |
4dc649d5e5 | ||
![]() |
5bab415790 | ||
![]() |
f04c699df6 | ||
![]() |
9bbf3f3e1d | ||
![]() |
a3f8e653d4 | ||
![]() |
7c02979c22 | ||
![]() |
fdb65c9368 | ||
![]() |
ea670cc358 | ||
![]() |
b7396f3796 | ||
![]() |
1963e0160f | ||
![]() |
9a06904634 | ||
![]() |
5eb50ecb06 | ||
![]() |
5e24ad17d7 | ||
![]() |
8b1cb09ddf | ||
![]() |
7af2c14327 | ||
![]() |
d1a6b043c2 | ||
![]() |
cddb8fec11 | ||
![]() |
1d7d8006d4 | ||
![]() |
63bdc2537c | ||
![]() |
f776b17150 | ||
![]() |
0056709999 | ||
![]() |
31da2555cb | ||
![]() |
9b19a93ab9 | ||
![]() |
0c8e757314 | ||
![]() |
f39e86bb10 | ||
![]() |
ad52117f0f | ||
![]() |
bdffabc08e | ||
![]() |
87ce41f251 | ||
![]() |
e7c7919cad | ||
![]() |
4f66ac79d3 | ||
![]() |
ba6da3bc6c | ||
![]() |
b742745854 | ||
![]() |
3293639adf | ||
![]() |
064ff31830 | ||
![]() |
5d473725d5 | ||
![]() |
97a2f2dbdd | ||
![]() |
37c4789fa4 | ||
![]() |
0aaeeeee24 | ||
![]() |
2155ec3d63 | ||
![]() |
0da906fc93 | ||
![]() |
9e5e6a1b60 | ||
![]() |
dcc74e15c7 | ||
![]() |
c271ed7c7f | ||
![]() |
d6a246c122 | ||
![]() |
0bef3ee0d8 | ||
![]() |
bb04df7086 | ||
![]() |
a70baf0d74 | ||
![]() |
86e2f92493 | ||
![]() |
e9aceca1de | ||
![]() |
3042950507 | ||
![]() |
63181e73a1 | ||
![]() |
4f3247a0e2 | ||
![]() |
f7a6aac657 | ||
![]() |
782564e6ab | ||
![]() |
6b8ba8b80b | ||
![]() |
52b76d8886 | ||
![]() |
ba36c69583 | ||
![]() |
370e5f92a0 | ||
![]() |
36d05e4774 | ||
![]() |
89d1be17c9 | ||
![]() |
0069591af9 | ||
![]() |
c36c8605bf | ||
![]() |
3c72a00d46 | ||
![]() |
58aefc8df8 | ||
![]() |
97ddfc2794 | ||
![]() |
4f15f4197b | ||
![]() |
6e4ec86586 | ||
![]() |
0d8ac304c7 | ||
![]() |
fdd5f49369 | ||
![]() |
d24984c1d5 | ||
![]() |
8080dcdd9e | ||
![]() |
d7cea55e2a | ||
![]() |
9b2f974a81 | ||
![]() |
43770fa9bd | ||
![]() |
80c7a54ad4 | ||
![]() |
e57b6fede2 | ||
![]() |
34a2fd039f | ||
![]() |
3299d0e72a | ||
![]() |
b89e2615db | ||
![]() |
cdcd82679c | ||
![]() |
cdfa866760 | ||
![]() |
aa8078ddeb | ||
![]() |
7e53c19d74 | ||
![]() |
b7a8432cfb | ||
![]() |
356c8e8aeb | ||
![]() |
ed283155f7 | ||
![]() |
87dfad026e | ||
![]() |
bb97c465d9 | ||
![]() |
8bd4c3370e | ||
![]() |
3eb84ffedd | ||
![]() |
9484315d37 | ||
![]() |
be59f1a875 | ||
![]() |
bfb28b4710 | ||
![]() |
216f0adb3c | ||
![]() |
dad6874638 | ||
![]() |
77af4bc213 | ||
![]() |
5abab982c7 | ||
![]() |
764e1aa332 | ||
![]() |
c47718b09d | ||
![]() |
45cb597ecc | ||
![]() |
08d4f91c8b | ||
![]() |
b9eac4e509 | ||
![]() |
16577783d3 | ||
![]() |
c179da28f0 | ||
![]() |
dc3d8ea198 | ||
![]() |
cbe075b001 | ||
![]() |
ed0b156e05 | ||
![]() |
2765abf971 | ||
![]() |
4dd0735066 | ||
![]() |
38e516d7c7 | ||
![]() |
70a31855ac | ||
![]() |
6c8e64ffcd | ||
![]() |
7285c32d58 | ||
![]() |
99c60ac54b | ||
![]() |
63e40cf3cb | ||
![]() |
1d45935a25 | ||
![]() |
f80373e7a2 | ||
![]() |
63185629b7 | ||
![]() |
4bfb9ac323 | ||
![]() |
5926b6c994 | ||
![]() |
f5ed43584d | ||
![]() |
2c740bb904 | ||
![]() |
d77f5f135f | ||
![]() |
0e4710a956 | ||
![]() |
aca1d43550 | ||
![]() |
f10e401aea | ||
![]() |
7744d2663b | ||
![]() |
4566cb8273 | ||
![]() |
052e7a7ae5 | ||
![]() |
0895200681 | ||
![]() |
1a1623075f | ||
![]() |
54a95e07a4 | ||
![]() |
09d0f563b7 | ||
![]() |
e188f1d3fa |
@@ -18,11 +18,6 @@ ij_any_if_brace_force = if_multiline
|
|||||||
ij_any_for_brace_force = if_multiline
|
ij_any_for_brace_force = if_multiline
|
||||||
ij_any_spaces_within_array_initializer_braces = true
|
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]
|
[*.md]
|
||||||
trim_trailing_whitespace = false
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
@@ -31,3 +26,16 @@ indent_size = 2
|
|||||||
|
|
||||||
[*.yml]
|
[*.yml]
|
||||||
indent_size = 2
|
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
|
||||||
|
16
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
16
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -6,12 +6,11 @@ body:
|
|||||||
id: mc-version
|
id: mc-version
|
||||||
attributes:
|
attributes:
|
||||||
label: Minecraft Version
|
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:
|
options:
|
||||||
- 1.16.x
|
- 1.20.1
|
||||||
- 1.18.x
|
- 1.21.x
|
||||||
- 1.19.x
|
|
||||||
- 1.20.x
|
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: input
|
- type: input
|
||||||
@@ -28,8 +27,5 @@ body:
|
|||||||
label: Details
|
label: Details
|
||||||
description: |
|
description: |
|
||||||
Description of the bug. Please include the following:
|
Description of the bug. Please include the following:
|
||||||
- Logs: These will be located in the `logs/` directory of your Minecraft
|
- 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!
|
||||||
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.
|
||||||
- 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.
|
|
||||||
|
46
.github/workflows/main-ci.yml
vendored
46
.github/workflows/main-ci.yml
vendored
@@ -30,27 +30,6 @@ jobs:
|
|||||||
- name: ⚒️ Build
|
- name: ⚒️ Build
|
||||||
run: ./gradlew assemble || ./gradlew assemble
|
run: ./gradlew assemble || ./gradlew assemble
|
||||||
|
|
||||||
- name: 💡 Lint
|
|
||||||
uses: pre-commit/action@v3.0.0
|
|
||||||
|
|
||||||
- name: 🧪 Run tests
|
|
||||||
run: ./gradlew test validateMixinNames checkChangelog
|
|
||||||
|
|
||||||
- name: 📥 Download assets for game tests
|
|
||||||
run: ./gradlew downloadAssets || ./gradlew downloadAssets
|
|
||||||
|
|
||||||
- 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
|
- name: 📦 Prepare Jars
|
||||||
run: |
|
run: |
|
||||||
# Find the main jar and append the git hash onto it.
|
# Find the main jar and append the git hash onto it.
|
||||||
@@ -63,8 +42,29 @@ jobs:
|
|||||||
name: CC-Tweaked
|
name: CC-Tweaked
|
||||||
path: ./jars
|
path: ./jars
|
||||||
|
|
||||||
- name: 📤 Upload coverage
|
- name: Cache pre-commit
|
||||||
uses: codecov/codecov-action@v4
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pre-commit
|
||||||
|
key: pre-commit-3|${{ env.pythonLocation }}|${{ hashFiles('.pre-commit-config.yaml') }}
|
||||||
|
|
||||||
|
- name: 💡 Lint
|
||||||
|
run: |
|
||||||
|
pipx install pre-commit
|
||||||
|
pre-commit run --show-diff-on-failure --color=always
|
||||||
|
|
||||||
|
- name: 🧪 Run tests
|
||||||
|
run: ./gradlew test validateMixinNames checkChangelog
|
||||||
|
|
||||||
|
- name: 📥 Download assets for game tests
|
||||||
|
run: ./gradlew downloadAssets || ./gradlew downloadAssets
|
||||||
|
|
||||||
|
- name: 🧪 Run integration tests
|
||||||
|
run: ./gradlew runGametest
|
||||||
|
|
||||||
|
- name: 🧪 Parse test reports
|
||||||
|
run: ./tools/parse-reports.py
|
||||||
|
if: ${{ failure() }}
|
||||||
|
|
||||||
build-core:
|
build-core:
|
||||||
strategy:
|
strategy:
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,6 +27,7 @@
|
|||||||
*.iml
|
*.iml
|
||||||
.idea
|
.idea
|
||||||
.gradle
|
.gradle
|
||||||
|
.kotlin
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
|
||||||
/.classpath
|
/.classpath
|
||||||
|
@@ -27,7 +27,7 @@ repos:
|
|||||||
exclude: "^(.*\\.(bat)|LICENSE)$"
|
exclude: "^(.*\\.(bat)|LICENSE)$"
|
||||||
|
|
||||||
- repo: https://github.com/fsfe/reuse-tool
|
- repo: https://github.com/fsfe/reuse-tool
|
||||||
rev: v2.1.0
|
rev: v5.0.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: reuse
|
- id: reuse
|
||||||
|
|
||||||
@@ -58,6 +58,7 @@ repos:
|
|||||||
exclude: |
|
exclude: |
|
||||||
(?x)^(
|
(?x)^(
|
||||||
projects/[a-z]+/src/generated|
|
projects/[a-z]+/src/generated|
|
||||||
|
projects/[a-z]+/src/examples/generatedResources|
|
||||||
projects/core/src/test/resources/test-rom/data/json-parsing/|
|
projects/core/src/test/resources/test-rom/data/json-parsing/|
|
||||||
.*\.dfpwm
|
.*\.dfpwm
|
||||||
)
|
)
|
||||||
|
100
.reuse/dep5
100
.reuse/dep5
@@ -1,100 +0,0 @@
|
|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Source: https://github.com/cc-tweaked/cc-tweaked
|
|
||||||
Upstream-Name: CC: Tweaked
|
|
||||||
Upstream-Contact: Jonathan Coates <git@squiddev.cc>
|
|
||||||
|
|
||||||
Files:
|
|
||||||
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_upgrade/*
|
|
||||||
projects/common/src/testMod/resources/data/cctest/structures/*
|
|
||||||
projects/*/src/generated/*
|
|
||||||
projects/web/src/htmlTransform/export/index.json
|
|
||||||
projects/web/src/htmlTransform/export/items/minecraft/*
|
|
||||||
Comment: Generated/data files are CC0.
|
|
||||||
Copyright: The CC: Tweaked Developers
|
|
||||||
License: CC0-1.0
|
|
||||||
|
|
||||||
Files:
|
|
||||||
doc/images/*
|
|
||||||
package.json
|
|
||||||
package-lock.json
|
|
||||||
projects/common/src/client/resources/computercraft-client.mixins.json
|
|
||||||
projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.json
|
|
||||||
projects/common/src/main/resources/computercraft.mixins.json
|
|
||||||
projects/common/src/testMod/resources/computercraft-gametest.mixins.json
|
|
||||||
projects/common/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json
|
|
||||||
projects/common/src/testMod/resources/pack.mcmeta
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/modules/command/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/modules/turtle/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/motd.txt
|
|
||||||
projects/fabric-api/src/main/modJson/fabric.mod.json
|
|
||||||
projects/fabric/src/client/resources/computercraft-client.fabric.mixins.json
|
|
||||||
projects/fabric/src/main/resources/computercraft.fabric.mixins.json
|
|
||||||
projects/fabric/src/main/resources/fabric.mod.json
|
|
||||||
projects/fabric/src/testMod/resources/computercraft-gametest.fabric.mixins.json
|
|
||||||
projects/fabric/src/testMod/resources/fabric.mod.json
|
|
||||||
projects/forge/src/client/resources/computercraft-client.forge.mixins.json
|
|
||||||
projects/forge/src/main/resources/computercraft.forge.mixins.json
|
|
||||||
projects/web/src/frontend/mount/.settings
|
|
||||||
projects/web/src/frontend/mount/example.nfp
|
|
||||||
projects/web/src/frontend/mount/example.nft
|
|
||||||
projects/web/src/frontend/mount/expr_template.lua
|
|
||||||
projects/web/tsconfig.json
|
|
||||||
Comment: Several assets where it's inconvenient to create a .license file.
|
|
||||||
Copyright: The CC: Tweaked Developers
|
|
||||||
License: MPL-2.0
|
|
||||||
|
|
||||||
Files:
|
|
||||||
doc/logo.png
|
|
||||||
doc/logo-darkmode.png
|
|
||||||
projects/common/src/main/resources/assets/computercraft/models/*
|
|
||||||
projects/common/src/main/resources/assets/computercraft/textures/*
|
|
||||||
projects/common/src/main/resources/pack.mcmeta
|
|
||||||
projects/common/src/main/resources/pack.png
|
|
||||||
projects/core/src/main/resources/assets/computercraft/textures/gui/term_font.png
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/autorun/.ignoreme
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/help/*
|
|
||||||
projects/core/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/levels/*
|
|
||||||
projects/web/src/htmlTransform/export/items/computercraft/*
|
|
||||||
Comment: Bulk-license original assets as CCPL.
|
|
||||||
Copyright: 2011 Daniel Ratcliffe
|
|
||||||
License: LicenseRef-CCPL
|
|
||||||
|
|
||||||
Files:
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/ko_kr.json
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/pl_pl.json
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/pt_br.json
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json
|
|
||||||
Comment: Community-contributed license files
|
|
||||||
Copyright: 2017 The CC: Tweaked Developers
|
|
||||||
License: LicenseRef-CCPL
|
|
||||||
|
|
||||||
Files:
|
|
||||||
projects/common/src/main/resources/assets/computercraft/lang/*
|
|
||||||
Comment: Community-contributed license files
|
|
||||||
Copyright: 2017 The CC: Tweaked Developers
|
|
||||||
License: MPL-2.0
|
|
||||||
|
|
||||||
Files:
|
|
||||||
.github/*
|
|
||||||
Comment:
|
|
||||||
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.
|
|
||||||
Copyright: Jonathan Coates <git@squiddev.cc>
|
|
||||||
License: CC0-1.0
|
|
||||||
|
|
||||||
Files:
|
|
||||||
gradle/wrapper/*
|
|
||||||
gradlew
|
|
||||||
gradlew.bat
|
|
||||||
Copyright: Gradle Inc
|
|
||||||
License: Apache-2.0
|
|
||||||
|
|
||||||
Files: projects/core/src/test/resources/test-rom/data/json-parsing/*
|
|
||||||
Copyright: 2016 Nicolas Seriot
|
|
||||||
License: MIT
|
|
@@ -22,16 +22,15 @@ 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.
|
use the issue templates - they provide a useful hint on what information to provide.
|
||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
Translations are managed through [Weblate], an online interface for managing language strings. This is synced
|
Translations are managed through [CrowdIn], an online interface for managing language strings.
|
||||||
automatically with GitHub, so please don't submit PRs adding/changing translations!
|
|
||||||
|
|
||||||
## Setting up a development environment
|
## Setting up a development environment
|
||||||
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
|
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:
|
- Make sure you've got the following software installed:
|
||||||
- Java Development Kit (JDK). This can be downloaded from [Adoptium].
|
- Java Development Kit 21 (JDK). This can be downloaded from [Adoptium].
|
||||||
- [Git](https://git-scm.com/).
|
- [Git](https://git-scm.com/).
|
||||||
- [NodeJS][node].
|
- [NodeJS 20 or later][node].
|
||||||
|
|
||||||
- Download CC: Tweaked's source code:
|
- Download CC: Tweaked's source code:
|
||||||
```
|
```
|
||||||
@@ -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).
|
`projects/forge/build/libs` (for Forge) or `projects/fabric/build/libs` (for Fabric).
|
||||||
|
|
||||||
## Developing CC: Tweaked
|
## Developing CC: Tweaked
|
||||||
Before making any major changes to CC: Tweaked, I'd recommend you have a read of the [the architecture
|
Before making any major changes to CC: Tweaked, I'd recommend starting opening an issue or starting a discussion on
|
||||||
document][architecture] first. While it's not a comprehensive document, it gives a good hint of where you should start
|
GitHub first. It's often helpful to discuss features before spending time developing them!
|
||||||
looking to make your changes. As always, if you're not sure, [do ask the community][community]!
|
|
||||||
|
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
|
### Testing
|
||||||
When making larger changes, it may be useful to write a test to make sure your code works as expected.
|
When making larger changes, it may be useful to write a test to make sure your code works as expected.
|
||||||
@@ -101,10 +103,10 @@ about how you can build on that until you've covered everything!
|
|||||||
[community]: README.md#community "Get in touch with the community."
|
[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=17 "Download OpenJDK 17"
|
||||||
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
|
[illuaminate]: https://github.com/SquidDev/illuaminate/ "Illuaminate on GitHub"
|
||||||
[weblate]: https://i18n.tweaked.cc/projects/cc-tweaked/minecraft/ "CC: Tweaked weblate instance"
|
|
||||||
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
|
[docs]: https://tweaked.cc/ "CC: Tweaked documentation"
|
||||||
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
|
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
|
||||||
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
|
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
|
||||||
[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
|
[busted]: https://github.com/Olivine-Labs/busted "busted: Elegant Lua unit testing."
|
||||||
[node]: https://nodejs.org/en/ "Node.js"
|
[node]: https://nodejs.org/en/ "Node.js"
|
||||||
[architecture]: projects/ARCHITECTURE.md
|
[architecture]: projects/ARCHITECTURE.md
|
||||||
|
[Crowdin]: https://crowdin.com/project/cc-tweaked/
|
||||||
|
28
README.md
28
README.md
@@ -11,14 +11,13 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</picture>
|
</picture>
|
||||||
|
|
||||||
[](https://github.com/cc-tweaked/CC-Tweaked/actions "Current build status")
|
[](https://github.com/cc-tweaked/CC-Tweaked/actions "Current build status")
|
||||||
[][CurseForge]
|
|
||||||
[][Modrinth]
|
[][Modrinth]
|
||||||
|
|
||||||
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
|
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
|
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
||||||
new features.
|
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
|
## Contributing
|
||||||
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
|
Any contribution is welcome, be that using the mod, reporting bugs or contributing code. If you want to get started
|
||||||
@@ -26,8 +25,9 @@ developing the mod, [check out the instructions here](CONTRIBUTING.md#developing
|
|||||||
|
|
||||||
## Community
|
## Community
|
||||||
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
||||||
ComputerCraft, do check out our [forum] and [GitHub discussions page][GitHub discussions]! There's also a fairly
|
ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
|
||||||
populated, albeit quiet [IRC channel][irc], if that's more your cup of tea.
|
albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
|
||||||
|
desktop client, or online using [KiwiIRC].
|
||||||
|
|
||||||
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
|
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ on is present.
|
|||||||
```groovy
|
```groovy
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url "https://squiddev.cc/maven/"
|
url "https://maven.squiddev.cc"
|
||||||
content {
|
content {
|
||||||
includeGroup("cc.tweaked")
|
includeGroup("cc.tweaked")
|
||||||
}
|
}
|
||||||
@@ -60,19 +60,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
|
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
|
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!
|
an issue to let me know!
|
||||||
@@ -81,10 +68,9 @@ 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/).
|
the generated documentation [can be browsed online](https://tweaked.cc/javadoc/).
|
||||||
|
|
||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
[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"
|
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
||||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
||||||
[forum]: https://forums.computercraft.cc/
|
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
[EsperNet]: https://www.esper.net/
|
||||||
|
[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
|
||||||
|
100
REUSE.toml
Normal file
100
REUSE.toml
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
version = 1
|
||||||
|
SPDX-PackageName = "CC: Tweaked"
|
||||||
|
SPDX-PackageSupplier = "Jonathan Coates <git@squiddev.cc>"
|
||||||
|
SPDX-PackageDownloadLocation = "https://github.com/cc-tweaked/cc-tweaked"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
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_upgrade/**",
|
||||||
|
"projects/common/src/testMod/resources/data/cctest/structures/**",
|
||||||
|
"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]]
|
||||||
|
# Several assets where it's inconvenient to create a .license file.
|
||||||
|
SPDX-FileCopyrightText = "The CC: Tweaked Developers"
|
||||||
|
SPDX-License-Identifier = "MPL-2.0"
|
||||||
|
path = [
|
||||||
|
"doc/images/**",
|
||||||
|
"package.json",
|
||||||
|
"package-lock.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/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/web/src/frontend/mount/.settings",
|
||||||
|
"projects/web/src/frontend/mount/example.nfp",
|
||||||
|
"projects/web/src/frontend/mount/example.nft",
|
||||||
|
"projects/web/src/frontend/mount/expr_template.lua",
|
||||||
|
"projects/web/tsconfig.json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
# Bulk-license original assets as CCPL.
|
||||||
|
SPDX-FileCopyrightText = "2011 Daniel Ratcliffe"
|
||||||
|
SPDX-License-Identifier = "LicenseRef-CCPL"
|
||||||
|
path = [
|
||||||
|
"doc/logo.png",
|
||||||
|
"doc/logo-darkmode.png",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/models/**",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/textures/**",
|
||||||
|
"projects/common/src/main/resources/pack.mcmeta",
|
||||||
|
"projects/common/src/main/resources/pack.png",
|
||||||
|
"projects/core/src/main/resources/assets/computercraft/textures/gui/term_font.png",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/autorun/.ignoreme",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/help/**",
|
||||||
|
"projects/core/src/main/resources/data/computercraft/lua/rom/programs/fun/advanced/levels/**",
|
||||||
|
"projects/web/src/htmlTransform/export/items/computercraft/**",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
# Community-contributed language files
|
||||||
|
SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
|
||||||
|
SPDX-License-Identifier = "LicenseRef-CCPL"
|
||||||
|
path = [
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/cs_cz.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/ko_kr.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/pl_pl.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/pt_br.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/uk_ua.json",
|
||||||
|
"projects/common/src/main/resources/assets/computercraft/lang/zh_cn.json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
# 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]]
|
||||||
|
path = ["gradle/wrapper/**"]
|
||||||
|
SPDX-FileCopyrightText = "Gradle Inc"
|
||||||
|
SPDX-License-Identifier = "Apache-2.0"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = "projects/core/src/test/resources/test-rom/data/json-parsing/**"
|
||||||
|
SPDX-FileCopyrightText = "2016 Nicolas Seriot"
|
||||||
|
SPDX-License-Identifier = "MIT"
|
@@ -24,21 +24,19 @@ val mcVersion: String by extra
|
|||||||
|
|
||||||
githubRelease {
|
githubRelease {
|
||||||
token(findProperty("githubApiKey") as String? ?: "")
|
token(findProperty("githubApiKey") as String? ?: "")
|
||||||
owner.set("cc-tweaked")
|
owner = "cc-tweaked"
|
||||||
repo.set("CC-Tweaked")
|
repo = "CC-Tweaked"
|
||||||
targetCommitish.set(cct.gitBranch)
|
targetCommitish = cct.gitBranch
|
||||||
|
|
||||||
tagName.set("v$mcVersion-$modVersion")
|
tagName = "v$mcVersion-$modVersion"
|
||||||
releaseName.set("[$mcVersion] $modVersion")
|
releaseName = "[$mcVersion] $modVersion"
|
||||||
body.set(
|
body = provider {
|
||||||
provider {
|
"## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
|
||||||
"## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
|
.readLines()
|
||||||
.readLines()
|
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
|
||||||
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
|
.joinToString("\n").trim()
|
||||||
.joinToString("\n").trim()
|
}
|
||||||
},
|
prerelease = isUnstable
|
||||||
)
|
|
||||||
prerelease.set(isUnstable)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.publish { dependsOn(tasks.githubRelease) }
|
tasks.publish { dependsOn(tasks.githubRelease) }
|
||||||
@@ -118,7 +116,7 @@ idea.project.settings.compiler.javac {
|
|||||||
}
|
}
|
||||||
|
|
||||||
versionCatalogUpdate {
|
versionCatalogUpdate {
|
||||||
sortByKey.set(false)
|
sortByKey = false
|
||||||
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
|
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
|
||||||
keep { keepUnusedLibraries.set(true) }
|
keep { keepUnusedLibraries = true }
|
||||||
}
|
}
|
||||||
|
@@ -14,14 +14,10 @@ repositories {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
|
||||||
maven("https://maven.neoforged.net/releases") {
|
maven("https://maven.neoforged.net") {
|
||||||
name = "NeoForge"
|
name = "NeoForge"
|
||||||
content {
|
content {
|
||||||
includeGroup("net.minecraftforge")
|
|
||||||
includeGroup("net.neoforged")
|
includeGroup("net.neoforged")
|
||||||
includeGroup("net.neoforged.gradle")
|
|
||||||
includeModule("codechicken", "DiffPatch")
|
|
||||||
includeModule("net.covers1624", "Quack")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +28,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maven("https://squiddev.cc/maven") {
|
maven("https://maven.squiddev.cc") {
|
||||||
name = "SquidDev"
|
name = "SquidDev"
|
||||||
content {
|
content {
|
||||||
includeGroup("cc.tweaked.vanilla-extract")
|
includeGroup("cc.tweaked.vanilla-extract")
|
||||||
@@ -45,11 +41,10 @@ dependencies {
|
|||||||
implementation(libs.kotlin.plugin)
|
implementation(libs.kotlin.plugin)
|
||||||
implementation(libs.spotless)
|
implementation(libs.spotless)
|
||||||
|
|
||||||
implementation(libs.curseForgeGradle)
|
|
||||||
implementation(libs.fabric.loom)
|
implementation(libs.fabric.loom)
|
||||||
implementation(libs.ideaExt)
|
implementation(libs.ideaExt)
|
||||||
implementation(libs.minotaur)
|
implementation(libs.minotaur)
|
||||||
implementation(libs.neoGradle.userdev)
|
implementation(libs.modDevGradle)
|
||||||
implementation(libs.vanillaExtract)
|
implementation(libs.vanillaExtract)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +68,7 @@ gradlePlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
versionCatalogUpdate {
|
versionCatalogUpdate {
|
||||||
sortByKey.set(false)
|
sortByKey = false
|
||||||
keep { keepUnusedLibraries.set(true) }
|
keep { keepUnusedLibraries = true }
|
||||||
catalogFile.set(file("../gradle/libs.versions.toml"))
|
catalogFile = file("../gradle/libs.versions.toml")
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,7 @@ repositories {
|
|||||||
|
|
||||||
loom {
|
loom {
|
||||||
splitEnvironmentSourceSets()
|
splitEnvironmentSourceSets()
|
||||||
splitModDependencies.set(true)
|
splitModDependencies = true
|
||||||
}
|
}
|
||||||
|
|
||||||
MinecraftConfigurations.setup(project)
|
MinecraftConfigurations.setup(project)
|
||||||
|
@@ -11,20 +11,18 @@ import cc.tweaked.gradle.MinecraftConfigurations
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("cc-tweaked.java-convention")
|
id("cc-tweaked.java-convention")
|
||||||
id("net.neoforged.gradle.userdev")
|
id("net.neoforged.moddev")
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins.apply(CCTweakedPlugin::class.java)
|
plugins.apply(CCTweakedPlugin::class.java)
|
||||||
|
|
||||||
val mcVersion: String by extra
|
val mcVersion: String by extra
|
||||||
|
|
||||||
minecraft {
|
neoForge {
|
||||||
modIdentifier("computercraft")
|
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||||
}
|
version = libs.findVersion("neoForge").get().toString()
|
||||||
|
|
||||||
subsystems {
|
|
||||||
parchment {
|
parchment {
|
||||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
|
||||||
minecraftVersion = libs.findVersion("parchmentMc").get().toString()
|
minecraftVersion = libs.findVersion("parchmentMc").get().toString()
|
||||||
mappingsVersion = libs.findVersion("parchment").get().toString()
|
mappingsVersion = libs.findVersion("parchment").get().toString()
|
||||||
}
|
}
|
||||||
|
@@ -29,7 +29,7 @@ base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
|
|||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
languageVersion= CCTweakedPlugin.JAVA_VERSION
|
||||||
}
|
}
|
||||||
|
|
||||||
withSourcesJar()
|
withSourcesJar()
|
||||||
@@ -38,7 +38,7 @@ java {
|
|||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|
||||||
val mainMaven = maven("https://squiddev.cc/maven") {
|
val mainMaven = maven("https://maven.squiddev.cc/mirror") {
|
||||||
name = "SquidDev"
|
name = "SquidDev"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +47,7 @@ repositories {
|
|||||||
filter {
|
filter {
|
||||||
includeGroup("cc.tweaked")
|
includeGroup("cc.tweaked")
|
||||||
// Things we mirror
|
// Things we mirror
|
||||||
|
includeGroup("com.simibubi.create")
|
||||||
includeGroup("commoble.morered")
|
includeGroup("commoble.morered")
|
||||||
includeGroup("dev.architectury")
|
includeGroup("dev.architectury")
|
||||||
includeGroup("dev.emi")
|
includeGroup("dev.emi")
|
||||||
@@ -98,6 +99,7 @@ sourceSets.all {
|
|||||||
check("OperatorPrecedence", CheckSeverity.OFF) // For now.
|
check("OperatorPrecedence", CheckSeverity.OFF) // For now.
|
||||||
check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
|
check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
|
||||||
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
|
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
|
||||||
|
check("InvalidInlineTag", CheckSeverity.OFF) // Triggered by @snippet. Can be removed on Java 21.
|
||||||
|
|
||||||
check("NullAway", CheckSeverity.ERROR)
|
check("NullAway", CheckSeverity.ERROR)
|
||||||
option(
|
option(
|
||||||
@@ -133,8 +135,8 @@ tasks.processResources {
|
|||||||
tasks.withType(AbstractArchiveTask::class.java).configureEach {
|
tasks.withType(AbstractArchiveTask::class.java).configureEach {
|
||||||
isPreserveFileTimestamps = false
|
isPreserveFileTimestamps = false
|
||||||
isReproducibleFileOrder = true
|
isReproducibleFileOrder = true
|
||||||
dirMode = Integer.valueOf("755", 8)
|
filePermissions {}
|
||||||
fileMode = Integer.valueOf("664", 8)
|
dirPermissions {}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.jar {
|
tasks.jar {
|
||||||
@@ -168,8 +170,8 @@ tasks.test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JacocoReport::class.java).configureEach {
|
tasks.withType(JacocoReport::class.java).configureEach {
|
||||||
reports.xml.required.set(true)
|
reports.xml.required = true
|
||||||
reports.html.required.set(true)
|
reports.html.required =true
|
||||||
}
|
}
|
||||||
|
|
||||||
project.plugins.withType(CCTweakedPlugin::class.java) {
|
project.plugins.withType(CCTweakedPlugin::class.java) {
|
||||||
@@ -225,6 +227,5 @@ idea.module {
|
|||||||
|
|
||||||
// Force Gradle to write to inherit the output directory from the parent, instead of writing to out/xxx/classes.
|
// 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.
|
// 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
|
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
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
import net.darkhax.curseforgegradle.TaskPublishCurseForge
|
|
||||||
import cc.tweaked.gradle.setProvider
|
import cc.tweaked.gradle.setProvider
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("net.darkhax.curseforgegradle")
|
|
||||||
id("com.modrinth.minotaur")
|
id("com.modrinth.minotaur")
|
||||||
id("cc-tweaked.publishing")
|
id("cc-tweaked.publishing")
|
||||||
}
|
}
|
||||||
@@ -25,34 +23,17 @@ val isUnstable = project.properties["isUnstable"] == "true"
|
|||||||
val modVersion: String by extra
|
val modVersion: String by extra
|
||||||
val mcVersion: 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 {
|
modrinth {
|
||||||
token.set(findProperty("modrinthApiKey") as String? ?: "")
|
token = findProperty("modrinthApiKey") as String? ?: ""
|
||||||
projectId.set("gu7yAYhd")
|
projectId = "gu7yAYhd"
|
||||||
versionNumber.set(modVersion)
|
versionNumber = modVersion
|
||||||
versionName.set(modVersion)
|
versionName = modVersion
|
||||||
versionType.set(if (isUnstable) "alpha" else "release")
|
versionType = if (isUnstable) "alpha" else "release"
|
||||||
uploadFile.setProvider(modPublishing.output)
|
uploadFile.setProvider(modPublishing.output)
|
||||||
gameVersions.add(mcVersion)
|
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) }
|
tasks.publish { dependsOn(tasks.modrinth) }
|
||||||
|
@@ -2,44 +2,34 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
import cc.tweaked.gradle.clientClasses
|
|
||||||
import cc.tweaked.gradle.commonClasses
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the configurations for writing game tests.
|
* Sets up the configurations for writing game tests.
|
||||||
*
|
*
|
||||||
* See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
|
* See notes in [cc.tweaked.gradle.MinecraftConfigurations] for the general design behind these cursed ideas.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import cc.tweaked.gradle.MinecraftConfigurations
|
||||||
|
import cc.tweaked.gradle.clientClasses
|
||||||
|
import cc.tweaked.gradle.commonClasses
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("cc-tweaked.kotlin-convention")
|
kotlin("jvm")
|
||||||
id("cc-tweaked.java-convention")
|
id("cc-tweaked.java-convention")
|
||||||
}
|
}
|
||||||
|
|
||||||
val main = sourceSets["main"]
|
val main = sourceSets["main"]
|
||||||
val client = sourceSets["client"]
|
val client = sourceSets["client"]
|
||||||
|
|
||||||
// Both testMod and testFixtures inherit from the main and client classpath, just so we have access to Minecraft classes.
|
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.DATAGEN)
|
||||||
val testMod by sourceSets.creating {
|
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.EXAMPLES)
|
||||||
compileClasspath += main.compileClasspath + client.compileClasspath
|
MinecraftConfigurations.createDerivedConfiguration(project, MinecraftConfigurations.TEST_MOD)
|
||||||
runtimeClasspath += main.runtimeClasspath + client.runtimeClasspath
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations {
|
// Set up generated resources
|
||||||
named(testMod.compileClasspathConfigurationName) {
|
sourceSets.main { resources.srcDir("src/generated/resources") }
|
||||||
shouldResolveConsistentlyWith(compileClasspath.get())
|
sourceSets.named("examples") { resources.srcDir("src/examples/generatedResources") }
|
||||||
}
|
|
||||||
|
|
||||||
named(testMod.runtimeClasspathConfigurationName) {
|
// Make sure our examples compile.
|
||||||
shouldResolveConsistentlyWith(runtimeClasspath.get())
|
tasks.check { dependsOn(tasks.named("compileExamplesJava")) }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like the main test configurations, we're safe to depend on source set outputs.
|
|
||||||
dependencies {
|
|
||||||
add(testMod.implementationConfigurationName, main.output)
|
|
||||||
add(testMod.implementationConfigurationName, client.output)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
|
// Similar to java-test-fixtures, but tries to avoid putting the obfuscated jar on the classpath.
|
||||||
|
|
@@ -12,25 +12,26 @@ publishing {
|
|||||||
register<MavenPublication>("maven") {
|
register<MavenPublication>("maven") {
|
||||||
artifactId = base.archivesName.get()
|
artifactId = base.archivesName.get()
|
||||||
from(components["java"])
|
from(components["java"])
|
||||||
|
suppressAllPomMetadataWarnings()
|
||||||
|
|
||||||
pom {
|
pom {
|
||||||
name.set("CC: Tweaked")
|
name = "CC: Tweaked"
|
||||||
description.set("CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft.")
|
description = "CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles and more to Minecraft."
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked")
|
url = "https://github.com/cc-tweaked/CC-Tweaked"
|
||||||
|
|
||||||
scm {
|
scm {
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked.git")
|
url = "https://github.com/cc-tweaked/CC-Tweaked.git"
|
||||||
}
|
}
|
||||||
|
|
||||||
issueManagement {
|
issueManagement {
|
||||||
system.set("github")
|
system = "github"
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/issues")
|
url = "https://github.com/cc-tweaked/CC-Tweaked/issues"
|
||||||
}
|
}
|
||||||
|
|
||||||
licenses {
|
licenses {
|
||||||
license {
|
license {
|
||||||
name.set("ComputerCraft Public License, Version 1.0")
|
name = "ComputerCraft Public License, Version 1.0"
|
||||||
url.set("https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE")
|
url = "https://github.com/cc-tweaked/CC-Tweaked/blob/HEAD/LICENSE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,7 +39,7 @@ publishing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven("https://squiddev.cc/maven") {
|
maven("https://maven.squiddev.cc") {
|
||||||
name = "SquidDev"
|
name = "SquidDev"
|
||||||
|
|
||||||
credentials(PasswordCredentials::class)
|
credentials(PasswordCredentials::class)
|
||||||
|
@@ -11,22 +11,17 @@ import org.gradle.api.NamedDomainObjectProvider
|
|||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.Task
|
import org.gradle.api.Task
|
||||||
import org.gradle.api.artifacts.Dependency
|
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.plugins.JavaPluginExtension
|
||||||
import org.gradle.api.provider.ListProperty
|
import org.gradle.api.provider.ListProperty
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.provider.SetProperty
|
import org.gradle.api.provider.SetProperty
|
||||||
import org.gradle.api.reporting.ReportingExtension
|
|
||||||
import org.gradle.api.tasks.SourceSet
|
import org.gradle.api.tasks.SourceSet
|
||||||
import org.gradle.api.tasks.bundling.Jar
|
import org.gradle.api.tasks.bundling.Jar
|
||||||
import org.gradle.api.tasks.compile.JavaCompile
|
import org.gradle.api.tasks.compile.JavaCompile
|
||||||
import org.gradle.api.tasks.javadoc.Javadoc
|
import org.gradle.api.tasks.javadoc.Javadoc
|
||||||
import org.gradle.configurationcache.extensions.capitalized
|
|
||||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||||
import org.gradle.language.jvm.tasks.ProcessResources
|
import org.gradle.language.jvm.tasks.ProcessResources
|
||||||
import org.gradle.process.JavaForkOptions
|
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.JacocoPluginExtension
|
||||||
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
|
import org.gradle.testing.jacoco.plugins.JacocoTaskExtension
|
||||||
import org.gradle.testing.jacoco.tasks.JacocoReport
|
import org.gradle.testing.jacoco.tasks.JacocoReport
|
||||||
@@ -37,54 +32,36 @@ import java.io.IOException
|
|||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
abstract class CCTweakedExtension(
|
abstract class CCTweakedExtension(private val project: Project) {
|
||||||
private val project: Project,
|
|
||||||
private val fs: FileSystemOperations,
|
|
||||||
) {
|
|
||||||
/** 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the current git branch. */
|
/** Get the current git branch. */
|
||||||
val gitBranch: Provider<String> = gitProvider(project, "<no git branch>") {
|
val gitBranch: Provider<String> =
|
||||||
ProcessHelpers.captureOut("git", "-C", project.rootProject.projectDir.absolutePath, "rev-parse", "--abbrev-ref", "HEAD")
|
gitProvider("<no git branch>", listOf("rev-parse", "--abbrev-ref", "HEAD")) { it.trim() }
|
||||||
.trim()
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get a list of all contributors to the project. */
|
/** Get a list of all contributors to the project. */
|
||||||
val gitContributors: Provider<List<String>> = gitProvider(project, listOf()) {
|
val gitContributors: Provider<List<String>> =
|
||||||
ProcessHelpers.captureLines(
|
gitProvider(listOf(), listOf("shortlog", "-ns", "--group=author", "--group=trailer:co-authored-by", "HEAD")) { input ->
|
||||||
"git", "-C", project.rootProject.projectDir.absolutePath, "shortlog", "-ns",
|
input.lineSequence()
|
||||||
"--group=author", "--group=trailer:co-authored-by", "HEAD",
|
.filter { it.isNotEmpty() }
|
||||||
)
|
.map {
|
||||||
.asSequence()
|
val matcher = COMMIT_COUNTS.matcher(it)
|
||||||
.map {
|
matcher.find()
|
||||||
val matcher = COMMIT_COUNTS.matcher(it)
|
matcher.group(1)
|
||||||
matcher.find()
|
}
|
||||||
matcher.group(1)
|
.filter { !IGNORED_USERS.contains(it) }
|
||||||
}
|
.toList()
|
||||||
.filter { !IGNORED_USERS.contains(it) }
|
.sortedWith(String.CASE_INSENSITIVE_ORDER)
|
||||||
.toList()
|
}
|
||||||
.sortedWith(String.CASE_INSENSITIVE_ORDER)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* References to other sources
|
* References to other sources
|
||||||
*/
|
*/
|
||||||
val sourceDirectories: SetProperty<SourceSetReference> = project.objects.setProperty(SourceSetReference::class.java)
|
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. */
|
/** All source sets referenced by this project. */
|
||||||
val sourceSets = sourceDirectories.map { x -> x.map { it.sourceSet } }
|
val sourceSets = sourceDirectories.map { x -> x.map { it.sourceSet } }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
sourceDirectories.finalizeValueOnRead()
|
sourceDirectories.finalizeValueOnRead()
|
||||||
excludedDeps.finalizeValueOnRead()
|
|
||||||
project.afterEvaluate { sourceDirectories.disallowChanges() }
|
project.afterEvaluate { sourceDirectories.disallowChanges() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,14 +87,13 @@ abstract class CCTweakedExtension(
|
|||||||
val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
|
val otherJava = otherProject.extensions.getByType(JavaPluginExtension::class.java)
|
||||||
val main = otherJava.sourceSets.getByName("main")
|
val main = otherJava.sourceSets.getByName("main")
|
||||||
val client = otherJava.sourceSets.getByName("client")
|
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.
|
// Pull in sources from the other project.
|
||||||
extendSourceSet(otherProject, main)
|
extendSourceSet(otherProject, main)
|
||||||
extendSourceSet(otherProject, client)
|
extendSourceSet(otherProject, client)
|
||||||
if (testMod != null) extendSourceSet(otherProject, testMod)
|
for (sourceSet in listOf(MinecraftConfigurations.DATAGEN, MinecraftConfigurations.EXAMPLES, MinecraftConfigurations.TEST_MOD, "testFixtures")) {
|
||||||
if (testFixtures != null) extendSourceSet(otherProject, testFixtures)
|
otherJava.sourceSets.findByName(sourceSet)?.let { extendSourceSet(otherProject, it) }
|
||||||
|
}
|
||||||
|
|
||||||
// The extra source-processing tasks should include these files too.
|
// The extra source-processing tasks should include these files too.
|
||||||
project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
|
project.tasks.named(main.javadocTaskName, Javadoc::class.java) { source(main.allJava, client.allJava) }
|
||||||
@@ -180,23 +156,18 @@ abstract class CCTweakedExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T> jacoco(task: NamedDomainObjectProvider<T>) where T : Task, T : JavaForkOptions {
|
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 reportTaskName = "jacoco${task.name.capitalized()}Report"
|
|
||||||
|
|
||||||
val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
|
val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
|
||||||
task.configure {
|
task.configure {
|
||||||
finalizedBy(reportTaskName)
|
finalizedBy(reportTaskName)
|
||||||
|
|
||||||
doFirst("Clean class dump directory") { fs.delete { delete(classDump) } }
|
|
||||||
|
|
||||||
jacoco.applyTo(this)
|
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
|
extensions.configure(JacocoTaskExtension::class.java) {
|
||||||
// source). Jacoco skips such classes by default, so we need to explicitly include them.
|
excludes = listOf(
|
||||||
isIncludeNoLocationClasses = true
|
"dan200.computercraft.mixin.*", // Exclude mixins, as they're not executed at runtime.
|
||||||
|
"dan200.computercraft.shared.Capabilities$*", // Exclude capability tokens, as Forge rewrites them.
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,15 +176,11 @@ abstract class CCTweakedExtension(
|
|||||||
description = "Generates code coverage report for the ${task.name} task."
|
description = "Generates code coverage report for the ${task.name} task."
|
||||||
|
|
||||||
executionData(task.get())
|
executionData(task.get())
|
||||||
classDirectories.from(classDump)
|
|
||||||
|
|
||||||
// Don't want to use sourceSets(...) here as we have a custom class directory.
|
// Don't want to use sourceSets(...) here as we don't use all class directories.
|
||||||
for (ref in sourceSets.get()) sourceDirectories.from(ref.allSource.sourceDirectories)
|
for (ref in this@CCTweakedExtension.sourceDirectories.get()) {
|
||||||
}
|
sourceDirectories.from(ref.sourceSet.allSource.sourceDirectories)
|
||||||
|
if (ref.classes) classDirectories.from(ref.sourceSet.output)
|
||||||
project.extensions.configure(ReportingExtension::class.java) {
|
|
||||||
reports.register("${task.name}CodeCoverageReport", JacocoCoverageReport::class.java) {
|
|
||||||
testType.set(TestSuiteType.INTEGRATION_TEST)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,40 +220,31 @@ abstract class CCTweakedExtension(
|
|||||||
).resolve().single()
|
).resolve().single()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private fun <T> gitProvider(default: T, command: List<String>, process: (String) -> T): Provider<T> {
|
||||||
* Exclude a dependency from being published in Maven.
|
val baseResult = project.providers.exec {
|
||||||
*/
|
commandLine = listOf("git", "-C", project.rootDir.absolutePath) + command
|
||||||
fun exclude(dep: Dependency) {
|
}
|
||||||
excludedDeps.add(dep)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return project.provider {
|
||||||
* Configure a [MavenDependencySpec].
|
val res = try {
|
||||||
*/
|
baseResult.standardOutput.asText.get()
|
||||||
fun configureExcludes(spec: MavenDependencySpec) {
|
} catch (e: IOException) {
|
||||||
for (dep in excludedDeps.get()) spec.exclude(dep)
|
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 {
|
companion object {
|
||||||
private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
|
private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
|
||||||
private val IGNORED_USERS = setOf(
|
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
|
private val isIdeSync: Boolean
|
||||||
get() = java.lang.Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"))
|
get() = java.lang.Boolean.parseBoolean(System.getProperty("idea.sync.active", "false"))
|
||||||
}
|
}
|
||||||
|
@@ -22,19 +22,19 @@ import org.gradle.language.base.plugins.LifecycleBasePlugin
|
|||||||
|
|
||||||
abstract class DependencyCheck : DefaultTask() {
|
abstract class DependencyCheck : DefaultTask() {
|
||||||
@get:Input
|
@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.
|
* A mapping of module coordinates (`group:module`) to versions, overriding the requested version.
|
||||||
*/
|
*/
|
||||||
@get:Input
|
@get:Input
|
||||||
abstract val overrides: MapProperty<String, String>
|
protected abstract val overrides: MapProperty<String, String>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
description = "Check :core's dependencies are consistent with Minecraft's."
|
description = "Check :core's dependencies are consistent with Minecraft's."
|
||||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||||
|
|
||||||
configuration.finalizeValueOnRead()
|
dependencies.finalizeValueOnRead()
|
||||||
overrides.finalizeValueOnRead()
|
overrides.finalizeValueOnRead()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,13 +45,19 @@ abstract class DependencyCheck : DefaultTask() {
|
|||||||
overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
|
overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a configuration to check.
|
||||||
|
*/
|
||||||
|
fun configuration(configuration: Provider<Configuration>) {
|
||||||
|
// We can't store the Configuration in the cache, so store the resolved dependencies instead.
|
||||||
|
dependencies.addAll(configuration.map { it.incoming.resolutionResult.allDependencies })
|
||||||
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun run() {
|
fun run() {
|
||||||
var ok = true
|
var ok = true
|
||||||
for (configuration in configuration.get()) {
|
for (configuration in dependencies.get()) {
|
||||||
configuration.incoming.resolutionResult.allDependencies {
|
if (!check(configuration)) ok = false
|
||||||
if (!check(this@allDependencies)) ok = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
|
@@ -9,6 +9,7 @@ import org.gradle.api.file.FileSystemLocation
|
|||||||
import org.gradle.api.provider.Property
|
import org.gradle.api.provider.Property
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.JavaExec
|
import org.gradle.api.tasks.JavaExec
|
||||||
|
import org.gradle.kotlin.dsl.getByName
|
||||||
import org.gradle.process.BaseExecSpec
|
import org.gradle.process.BaseExecSpec
|
||||||
import org.gradle.process.JavaExecSpec
|
import org.gradle.process.JavaExecSpec
|
||||||
import org.gradle.process.ProcessForkOptions
|
import org.gradle.process.ProcessForkOptions
|
||||||
@@ -46,6 +47,21 @@ fun JavaExec.copyToFull(spec: JavaExec) {
|
|||||||
copyToExec(spec)
|
copyToExec(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base this [JavaExec] task on an existing task.
|
||||||
|
*/
|
||||||
|
fun JavaExec.copyFromTask(task: JavaExec) {
|
||||||
|
for (dep in task.dependsOn) dependsOn(dep)
|
||||||
|
task.copyToFull(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base this [JavaExec] task on an existing task.
|
||||||
|
*/
|
||||||
|
fun JavaExec.copyFromTask(task: String) {
|
||||||
|
copyFromTask(project.tasks.getByName<JavaExec>(task))
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo].
|
* Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo].
|
||||||
*/
|
*/
|
||||||
@@ -143,7 +159,7 @@ fun getNextVersion(version: String): String {
|
|||||||
val lastIndex = mainVersion.lastIndexOf('.')
|
val lastIndex = mainVersion.lastIndexOf('.')
|
||||||
if (lastIndex < 0) throw IllegalArgumentException("Cannot parse version format \"$version\"")
|
if (lastIndex < 0) throw IllegalArgumentException("Cannot parse version format \"$version\"")
|
||||||
val lastVersion = try {
|
val lastVersion = try {
|
||||||
version.substring(lastIndex + 1).toInt()
|
mainVersion.substring(lastIndex + 1).toInt()
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
throw IllegalArgumentException("Cannot parse version format \"$version\"", e)
|
throw IllegalArgumentException("Cannot parse version format \"$version\"", e)
|
||||||
}
|
}
|
||||||
@@ -155,3 +171,15 @@ fun getNextVersion(version: String): String {
|
|||||||
if (dashIndex >= 0) out.append(version, dashIndex, version.length)
|
if (dashIndex >= 0) out.append(version, dashIndex, version.length)
|
||||||
return out.toString()
|
return out.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capitalise the first letter of the string.
|
||||||
|
*
|
||||||
|
* This is a replacement for the now deprecated [String.capitalize].
|
||||||
|
*/
|
||||||
|
fun String.capitalise(): String {
|
||||||
|
if (isEmpty()) return this
|
||||||
|
val first = this[0]
|
||||||
|
val firstTitle = first.titlecaseChar()
|
||||||
|
return if (first == firstTitle) this else firstTitle + substring(1)
|
||||||
|
}
|
||||||
|
@@ -1,62 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package cc.tweaked.gradle
|
|
||||||
|
|
||||||
import net.neoforged.gradle.common.runs.run.RunImpl
|
|
||||||
import net.neoforged.gradle.common.runs.tasks.RunExec
|
|
||||||
import net.neoforged.gradle.dsl.common.extensions.RunnableSourceSet
|
|
||||||
import net.neoforged.gradle.dsl.common.runs.run.Run
|
|
||||||
import org.gradle.api.plugins.JavaPluginExtension
|
|
||||||
import org.gradle.api.tasks.JavaExec
|
|
||||||
import org.gradle.api.tasks.SourceSet
|
|
||||||
import org.gradle.jvm.toolchain.JavaToolchainService
|
|
||||||
import org.gradle.kotlin.dsl.assign
|
|
||||||
import org.gradle.kotlin.dsl.create
|
|
||||||
import org.gradle.kotlin.dsl.findByType
|
|
||||||
import java.nio.file.Files
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set [JavaExec] task to run a given [RunConfig].
|
|
||||||
*
|
|
||||||
* See also [RunExec].
|
|
||||||
*/
|
|
||||||
fun JavaExec.setRunConfig(config: Run) {
|
|
||||||
mainClass.set(config.mainClass)
|
|
||||||
workingDir = config.workingDirectory.get().asFile
|
|
||||||
argumentProviders.add { config.programArguments.get() }
|
|
||||||
jvmArgumentProviders.add { config.jvmArguments.get() }
|
|
||||||
|
|
||||||
environment(config.environmentVariables.get())
|
|
||||||
systemProperties(config.systemProperties.get())
|
|
||||||
|
|
||||||
config.modSources.all().get().values().forEach { classpath(it.runtimeClasspath) }
|
|
||||||
classpath(config.classpath)
|
|
||||||
classpath(config.dependencies.get().runtimeConfiguration)
|
|
||||||
|
|
||||||
(config as RunImpl).taskDependencies.forEach { dependsOn(it) }
|
|
||||||
|
|
||||||
javaLauncher.set(
|
|
||||||
project.extensions.getByType(JavaToolchainService::class.java)
|
|
||||||
.launcherFor(project.extensions.getByType(JavaPluginExtension::class.java).toolchain),
|
|
||||||
)
|
|
||||||
|
|
||||||
doFirst("Create working directory") { Files.createDirectories(workingDir.toPath()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new [Run.modSource] with a specific mod id.
|
|
||||||
*/
|
|
||||||
fun Run.modSourceAs(sourceSet: SourceSet, mod: String) {
|
|
||||||
// NeoGradle requires a RunnableSourceSet to be present, so we inject it into other project's source sets.
|
|
||||||
val runnable = sourceSet.extensions.findByType<RunnableSourceSet>() ?: run {
|
|
||||||
val extension = sourceSet.extensions.create<RunnableSourceSet>(RunnableSourceSet.NAME, project)
|
|
||||||
extension.modIdentifier = mod
|
|
||||||
extension.modIdentifier.finalizeValueOnRead()
|
|
||||||
extension
|
|
||||||
}
|
|
||||||
if (runnable.modIdentifier.get() != mod) throw IllegalArgumentException("Multiple mod identifiers")
|
|
||||||
|
|
||||||
modSource(sourceSet)
|
|
||||||
}
|
|
@@ -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 java = project.extensions.getByType(JavaPluginExtension::class.java)
|
||||||
private val sourceSets = java.sourceSets
|
private val sourceSets = java.sourceSets
|
||||||
private val configurations = project.configurations
|
private val configurations = project.configurations
|
||||||
private val objects = project.objects
|
|
||||||
|
|
||||||
private val main = sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
|
private val main = sourceSets[SourceSet.MAIN_SOURCE_SET_NAME]
|
||||||
private val test = sourceSets[SourceSet.TEST_SOURCE_SET_NAME]
|
private val test = sourceSets[SourceSet.TEST_SOURCE_SET_NAME]
|
||||||
@@ -37,13 +36,7 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
val client = sourceSets.maybeCreate("client")
|
val client = sourceSets.maybeCreate("client")
|
||||||
|
|
||||||
// Ensure the client classpaths behave the same as the main ones.
|
// Ensure the client classpaths behave the same as the main ones.
|
||||||
configurations.named(client.compileClasspathConfigurationName) {
|
consistentWithMain(client)
|
||||||
shouldResolveConsistentlyWith(configurations[main.compileClasspathConfigurationName])
|
|
||||||
}
|
|
||||||
|
|
||||||
configurations.named(client.runtimeClasspathConfigurationName) {
|
|
||||||
shouldResolveConsistentlyWith(configurations[main.runtimeClasspathConfigurationName])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set up an API configuration for clients (to ensure it's consistent with the main source set).
|
// Set up an API configuration for clients (to ensure it's consistent with the main source set).
|
||||||
val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
|
val clientApi = configurations.maybeCreate(client.apiConfigurationName).apply {
|
||||||
@@ -85,6 +78,16 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
setupBasic()
|
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() {
|
private fun setupBasic() {
|
||||||
val client = sourceSets["client"]
|
val client = sourceSets["client"]
|
||||||
|
|
||||||
@@ -96,13 +99,30 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
val checkDependencyConsistency =
|
val checkDependencyConsistency =
|
||||||
project.tasks.register("checkDependencyConsistency", DependencyCheck::class.java) {
|
project.tasks.register("checkDependencyConsistency", DependencyCheck::class.java) {
|
||||||
// We need to check both the main and client classpath *configurations*, as the actual configuration
|
// We need to check both the main and client classpath *configurations*, as the actual configuration
|
||||||
configuration.add(configurations.named(main.runtimeClasspathConfigurationName))
|
configuration(configurations.named(main.runtimeClasspathConfigurationName))
|
||||||
configuration.add(configurations.named(client.runtimeClasspathConfigurationName))
|
configuration(configurations.named(client.runtimeClasspathConfigurationName))
|
||||||
}
|
}
|
||||||
project.tasks.named("check") { dependsOn(checkDependencyConsistency) }
|
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 {
|
companion object {
|
||||||
|
const val DATAGEN = "datagen"
|
||||||
|
const val EXAMPLES = "examples"
|
||||||
|
const val TEST_MOD = "testMod"
|
||||||
|
|
||||||
fun setupBasic(project: Project) {
|
fun setupBasic(project: Project) {
|
||||||
MinecraftConfigurations(project).setupBasic()
|
MinecraftConfigurations(project).setupBasic()
|
||||||
}
|
}
|
||||||
@@ -110,6 +130,10 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
|||||||
fun setup(project: Project) {
|
fun setup(project: Project) {
|
||||||
MinecraftConfigurations(project).setup()
|
MinecraftConfigurations(project).setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createDerivedConfiguration(project: Project, name: String) {
|
||||||
|
MinecraftConfigurations(project).createDerivedConfiguration(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package cc.tweaked.gradle
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
|
import net.neoforged.moddevgradle.internal.RunGameTask
|
||||||
import org.gradle.api.GradleException
|
import org.gradle.api.GradleException
|
||||||
import org.gradle.api.file.FileSystemOperations
|
import org.gradle.api.file.FileSystemOperations
|
||||||
import org.gradle.api.invocation.Gradle
|
import org.gradle.api.invocation.Gradle
|
||||||
@@ -18,6 +19,7 @@ import java.nio.file.Files
|
|||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.function.Supplier
|
import java.util.function.Supplier
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.collections.set
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,6 +66,22 @@ abstract class ClientJavaExec : JavaExec() {
|
|||||||
setTestProperties()
|
setTestProperties()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun copyFromForge(path: String) = copyFromForge(project.tasks.getByName(path, RunGameTask::class))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this task to run a given [RunGameTask].
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy configuration from a task with the given name.
|
* Copy configuration from a task with the given name.
|
||||||
*/
|
*/
|
||||||
@@ -108,6 +126,23 @@ abstract class ClientJavaExec : JavaExec() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure Iris to use Complementary Shaders.
|
||||||
|
*/
|
||||||
|
fun withComplementaryShaders() {
|
||||||
|
val cct = project.extensions.getByType(CCTweakedExtension::class.java)
|
||||||
|
|
||||||
|
withFileFrom(workingDir.resolve("shaderpacks/ComplementaryShaders_v4.6.zip")) {
|
||||||
|
cct.downloadFile("Complementary Shaders", "https://edge.forgecdn.net/files/3951/170/ComplementaryShaders_v4.6.zip")
|
||||||
|
}
|
||||||
|
withFileContents(workingDir.resolve("config/iris.properties")) {
|
||||||
|
"""
|
||||||
|
enableShaders=true
|
||||||
|
shaderPack=ComplementaryShaders_v4.6.zip
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
override fun exec() {
|
override fun exec() {
|
||||||
Files.createDirectories(workingDir.toPath())
|
Files.createDirectories(workingDir.toPath())
|
||||||
|
@@ -11,7 +11,9 @@ import org.gradle.api.file.Directory
|
|||||||
import org.gradle.api.file.DirectoryProperty
|
import org.gradle.api.file.DirectoryProperty
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
|
import org.gradle.process.ExecOperations
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
class NodePlugin : Plugin<Project> {
|
class NodePlugin : Plugin<Project> {
|
||||||
override fun apply(project: Project) {
|
override fun apply(project: Project) {
|
||||||
@@ -43,9 +45,12 @@ abstract class NpmInstall : DefaultTask() {
|
|||||||
@get:OutputDirectory
|
@get:OutputDirectory
|
||||||
val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
|
val nodeModules: Provider<Directory> = projectRoot.dir("node_modules")
|
||||||
|
|
||||||
|
@get:Inject
|
||||||
|
protected abstract val execOperations: ExecOperations
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun install() {
|
fun install() {
|
||||||
project.exec {
|
execOperations.exec {
|
||||||
commandLine(ProcessHelpers.getExecutable("npm"), "ci")
|
commandLine(ProcessHelpers.getExecutable("npm"), "ci")
|
||||||
workingDir = projectRoot.get().asFile
|
workingDir = projectRoot.get().asFile
|
||||||
}
|
}
|
||||||
|
@@ -4,45 +4,10 @@
|
|||||||
|
|
||||||
package cc.tweaked.gradle
|
package cc.tweaked.gradle
|
||||||
|
|
||||||
import org.codehaus.groovy.runtime.ProcessGroovyMethods
|
|
||||||
import org.gradle.api.GradleException
|
import org.gradle.api.GradleException
|
||||||
import java.io.BufferedReader
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStreamReader
|
|
||||||
import java.nio.charset.StandardCharsets
|
|
||||||
|
|
||||||
internal object ProcessHelpers {
|
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 {
|
fun onPath(name: String): Boolean {
|
||||||
val path = System.getenv("PATH") ?: return false
|
val path = System.getenv("PATH") ?: return false
|
||||||
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
||||||
|
@@ -21,6 +21,15 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<property name="file" value="${config_loc}/suppressions.xml" />
|
<property name="file" value="${config_loc}/suppressions.xml" />
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Checkstyle doesn't support @snippet (https://github.com/checkstyle/checkstyle/issues/11455),
|
||||||
|
so suppress warnings nearby
|
||||||
|
-->
|
||||||
|
<module name="SuppressWithNearbyTextFilter">
|
||||||
|
<property name="nearbyTextPattern" value="@snippet" />
|
||||||
|
<property name="lineRange" value="20" />
|
||||||
|
</module>
|
||||||
|
|
||||||
<module name="BeforeExecutionExclusionFileFilter">
|
<module name="BeforeExecutionExclusionFileFilter">
|
||||||
<property name="fileNamePattern" value="render_old"/>
|
<property name="fileNamePattern" value="render_old"/>
|
||||||
</module>
|
</module>
|
||||||
@@ -124,7 +133,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
</module>
|
</module>
|
||||||
<module name="MethodTypeParameterName" />
|
<module name="MethodTypeParameterName" />
|
||||||
<module name="PackageName">
|
<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>
|
||||||
<module name="ParameterName" />
|
<module name="ParameterName" />
|
||||||
<module name="StaticVariableName">
|
<module name="StaticVariableName">
|
||||||
|
28
crowdin.yml
Normal file
28
crowdin.yml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
files:
|
||||||
|
- source: projects/common/src/generated/resources/assets/computercraft/lang/en_us.json
|
||||||
|
translation: /projects/common/src/main/resources/assets/computercraft/lang/%locale_with_underscore%.json
|
||||||
|
languages_mapping:
|
||||||
|
locale_with_underscore:
|
||||||
|
cs: cs_cz # Czech
|
||||||
|
da: da_dk # Danish
|
||||||
|
de: de_de # German
|
||||||
|
es-ES: es_es # Spanish
|
||||||
|
fr: fr_fr # French
|
||||||
|
it: it_it # Italian
|
||||||
|
ja: ja_jp # Japanese
|
||||||
|
ko: ko_kr # Korean
|
||||||
|
nb: nb_no # Norwegian Bokmal
|
||||||
|
nl: nl_nl # Dutch
|
||||||
|
pl: pl_pl # Polish
|
||||||
|
pt-BR: pt_br # Portuguese, Brazilian
|
||||||
|
ru: ru_ru # Russian
|
||||||
|
sv-SE: sv_se # Sweedish
|
||||||
|
tok: tok # Toki Pona
|
||||||
|
tr: tr_tr # Turkish
|
||||||
|
uk: uk_ua # Ukraine
|
||||||
|
vi: vi_vn # Vietnamese
|
||||||
|
zh-CN: zh_cn # Chinese Simplified
|
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
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
|
## Return Values
|
||||||
1. [`string`]: The event name.
|
1. [`string`]: The event name.
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
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
|
## Return Values
|
||||||
1. [`string`]: The event name.
|
1. [`string`]: The event name.
|
||||||
|
@@ -8,7 +8,7 @@ SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
|||||||
SPDX-License-Identifier: MPL-2.0
|
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
|
## Return values
|
||||||
1. [`string`]: The event name.
|
1. [`string`]: The event name.
|
||||||
@@ -21,3 +21,7 @@ while true do
|
|||||||
print("A redstone input has changed!")
|
print("A redstone input has changed!")
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## See also
|
||||||
|
- [The `redstone` API on computers][`module!redstone`]
|
||||||
|
- [The `redstone_relay` peripheral][`redstone_relay`]
|
||||||
|
@@ -191,7 +191,7 @@ end
|
|||||||
|
|
||||||
> [Confused?][!NOTE]
|
> [Confused?][!NOTE]
|
||||||
> Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
|
> Don't worry if you don't understand this example. It's quite advanced, and does use some ideas that this guide doesn't
|
||||||
> cover. That said, don't be afraid to ask on [GitHub Discussions] or [IRC] either!
|
> cover. That said, don't be afraid to ask [the community for help][community].
|
||||||
|
|
||||||
It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
|
It's worth noting that the examples of audio processing we've mentioned here are about manipulating the _amplitude_ of
|
||||||
the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex.
|
the wave. If you wanted to modify the _frequency_ (for instance, shifting the pitch), things get rather more complex.
|
||||||
@@ -205,5 +205,4 @@ This is, I'm afraid, left as an exercise to the reader.
|
|||||||
[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
|
[PCM]: https://en.wikipedia.org/wiki/Pulse-code_modulation "Pulse-code Modulation - Wikipedia"
|
||||||
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
|
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
|
||||||
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
|
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[Community]: /#community
|
||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
|
||||||
|
12
doc/index.md
12
doc/index.md
@@ -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
|
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
||||||
new features.
|
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
|
## Features
|
||||||
Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
|
Controlled using the [Lua programming language][lua], CC: Tweaked's computers provides all the tools you need to start
|
||||||
@@ -50,7 +50,11 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
|
|||||||
Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the
|
Once you're a little more familiar with the mod, the sidebar and links below provide more detailed documentation on the
|
||||||
various APIs and peripherals provided by the mod.
|
various APIs and peripherals provided by the mod.
|
||||||
|
|
||||||
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
|
<h2 id="community">Community</h2>
|
||||||
|
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
||||||
|
ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
|
||||||
|
albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
|
||||||
|
desktop client, or online using [KiwiIRC].
|
||||||
|
|
||||||
## Get Involved
|
## Get Involved
|
||||||
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
||||||
@@ -58,11 +62,11 @@ 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"
|
[github]: https://github.com/cc-tweaked/CC-Tweaked/ "CC: Tweaked on GitHub"
|
||||||
[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
|
[bug]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose
|
||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
[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"
|
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
||||||
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
[forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
||||||
[lua]: https://www.lua.org/ "Lua's main website"
|
[lua]: https://www.lua.org/ "Lua's main website"
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
||||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
[EsperNet]: https://www.esper.net/
|
||||||
|
[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
|
||||||
|
@@ -50,7 +50,11 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
|
|||||||
Once you're a little more familiar with the mod, the [wiki](https://tweaked.cc/) provides more detailed documentation on the
|
Once you're a little more familiar with the mod, the [wiki](https://tweaked.cc/) provides more detailed documentation on the
|
||||||
various APIs and peripherals provided by the mod.
|
various APIs and peripherals provided by the mod.
|
||||||
|
|
||||||
If you get stuck, do [ask a question on GitHub][GitHub Discussions] or pop in to the ComputerCraft's [IRC channel][IRC].
|
## Community
|
||||||
|
If you need help getting started with CC: Tweaked, want to show off your latest project, or just want to chat about
|
||||||
|
ComputerCraft, do check out our [GitHub discussions page][GitHub discussions]! There's also a fairly populated,
|
||||||
|
albeit quiet IRC channel on [EsperNet], if that's more your cup of tea. You can join `#computercraft` through your
|
||||||
|
desktop client, or online using [KiwiIRC].
|
||||||
|
|
||||||
## Get Involved
|
## Get Involved
|
||||||
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
||||||
@@ -60,4 +64,5 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
|
|||||||
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
[computercraft]: https://github.com/dan200/ComputerCraft "ComputerCraft on GitHub"
|
||||||
[lua]: https://www.lua.org/ "Lua's main website"
|
[lua]: https://www.lua.org/ "Lua's main website"
|
||||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
||||||
[IRC]: http://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
[EsperNet]: https://www.esper.net/
|
||||||
|
[KiwiIRC]: https://kiwiirc.com/nextclient/#irc://irc.esper.net:+6697/#computercraft "#computercraft on EsperNet"
|
||||||
|
@@ -25,13 +25,13 @@ as documentation for breaking changes and "gotchas" one should look out for betw
|
|||||||
|
|
||||||
- Update to Lua 5.2:
|
- Update to Lua 5.2:
|
||||||
- Support for Lua 5.0's pseudo-argument `arg` has been removed. You should always use `...` for varargs.
|
- Support for Lua 5.0's pseudo-argument `arg` has been removed. You should always use `...` for varargs.
|
||||||
- Environments are no longer baked into the runtime, and instead use the `_ENV` local or upvalue. `getfenv`/`setfenv`
|
- Environments are no longer baked into the runtime, and instead use the `_ENV` local or upvalue. [`getfenv`]/[`setfenv`]
|
||||||
now only work on Lua functions with an `_ENV` upvalue. `getfenv` will return the global environment when called
|
now only work on Lua functions with an `_ENV` upvalue. [`getfenv`] will return the global environment when called
|
||||||
with other functions, and `setfenv` will have no effect.
|
with other functions, and [`setfenv`] will have no effect.
|
||||||
- `load`/`loadstring` defaults to using the global environment (`_G`) rather than the current coroutine's
|
- [`load`]/[`loadstring`] defaults to using the global environment (`_G`) rather than the current coroutine's
|
||||||
environment.
|
environment.
|
||||||
- Support for dumping functions (`string.dump`) and loading binary chunks has been removed.
|
- Support for dumping functions ([`string.dump`]) and loading binary chunks has been removed.
|
||||||
- `math.random` now uses Lua 5.4's random number generator.
|
- [`math.random`] now uses Lua 5.4's random number generator.
|
||||||
|
|
||||||
- File handles, HTTP requests and websockets now always use the original bytes rather than encoding/decoding to UTF-8.
|
- File handles, HTTP requests and websockets now always use the original bytes rather than encoding/decoding to UTF-8.
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ as documentation for breaking changes and "gotchas" one should look out for betw
|
|||||||
`keys.enter` constant was queued when the key was pressed)
|
`keys.enter` constant was queued when the key was pressed)
|
||||||
|
|
||||||
- Minecraft 1.13 removed the concept of item damage and block metadata (see ["The Flattening"][flattening]). As a
|
- Minecraft 1.13 removed the concept of item damage and block metadata (see ["The Flattening"][flattening]). As a
|
||||||
result `turtle.inspect` no longer provides block metadata, and `turtle.getItemDetail` no longer provides damage.
|
result [`turtle.inspect`] no longer provides block metadata, and [`turtle.getItemDetail`] no longer provides damage.
|
||||||
|
|
||||||
- Block states (`turtle.inspect().state`) should provide all the same information as block metadata, but in a much
|
- Block states (`turtle.inspect().state`) should provide all the same information as block metadata, but in a much
|
||||||
more understandable format.
|
more understandable format.
|
||||||
@@ -70,7 +70,7 @@ as documentation for breaking changes and "gotchas" one should look out for betw
|
|||||||
- Unlabelled computers and turtles now keep their ID when broken, meaning that unlabelled computers/items do not stack.
|
- Unlabelled computers and turtles now keep their ID when broken, meaning that unlabelled computers/items do not stack.
|
||||||
|
|
||||||
## ComputerCraft 1.80pr1 {#cc-1.80}
|
## ComputerCraft 1.80pr1 {#cc-1.80}
|
||||||
- Programs run via `shell.run` are now started in their own isolated environment. This means globals set by programs
|
- Programs run via [`shell.run`] are now started in their own isolated environment. This means globals set by programs
|
||||||
will not be accessible outside of this program.
|
will not be accessible outside of this program.
|
||||||
|
|
||||||
- Programs containing `/` are looked up in the current directory and are no longer looked up on the path. For instance,
|
- Programs containing `/` are looked up in the current directory and are no longer looked up on the path. For instance,
|
||||||
|
@@ -81,7 +81,7 @@ compatibility for these newer versions.
|
|||||||
| `string.dump` strip argument | ✔ | |
|
| `string.dump` strip argument | ✔ | |
|
||||||
| `string.pack`/`string.unpack`/`string.packsize` | ✔ | |
|
| `string.pack`/`string.unpack`/`string.packsize` | ✔ | |
|
||||||
| `table.move` | ✔ | |
|
| `table.move` | ✔ | |
|
||||||
| `math.atan2` -> `math.atan` | ❌ | |
|
| `math.atan2` -> `math.atan` | 🔶 | `math.atan` supports its two argument form. |
|
||||||
| Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌ | |
|
| Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌ | |
|
||||||
| `math.maxinteger`/`math.mininteger` | ❌ | |
|
| `math.maxinteger`/`math.mininteger` | ❌ | |
|
||||||
| `math.tointeger` | ❌ | |
|
| `math.tointeger` | ❌ | |
|
||||||
|
@@ -10,9 +10,8 @@ kotlin.jvm.target.validation.mode=error
|
|||||||
|
|
||||||
neogradle.subsystems.conventions.runs.enabled=false
|
neogradle.subsystems.conventions.runs.enabled=false
|
||||||
|
|
||||||
# Mod properties
|
|
||||||
isUnstable=true
|
isUnstable=true
|
||||||
modVersion=1.111.0
|
modVersion=1.114.3
|
||||||
|
|
||||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||||
mcVersion=1.21
|
mcVersion=1.21.1
|
||||||
|
2
gradle/gradle-daemon-jvm.properties
Normal file
2
gradle/gradle-daemon-jvm.properties
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#This file is generated by updateDaemonJvm
|
||||||
|
toolchainVersion=21
|
@@ -7,14 +7,14 @@
|
|||||||
# Minecraft
|
# Minecraft
|
||||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||||
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
||||||
fabric-api = "0.100.3+1.21"
|
fabric-api = "0.102.1+1.21.1"
|
||||||
fabric-loader = "0.15.11"
|
fabric-loader = "0.15.11"
|
||||||
neoForge = "21.0.21-beta"
|
neoForge = "21.1.9"
|
||||||
neoForgeSpi = "8.0.1"
|
neoForgeSpi = "8.0.1"
|
||||||
mixin = "0.8.5"
|
mixin = "0.8.5"
|
||||||
parchment = "2024.06.16"
|
parchment = "2024.07.28"
|
||||||
parchmentMc = "1.20.6"
|
parchmentMc = "1.21"
|
||||||
yarn = "1.21+build.1"
|
yarn = "1.21.1+build.1"
|
||||||
|
|
||||||
# Core dependencies (these versions are tied to the version Minecraft uses)
|
# Core dependencies (these versions are tied to the version Minecraft uses)
|
||||||
fastutil = "8.5.12"
|
fastutil = "8.5.12"
|
||||||
@@ -26,53 +26,56 @@ slf4j = "2.0.9"
|
|||||||
asm = "9.6"
|
asm = "9.6"
|
||||||
autoService = "1.1.1"
|
autoService = "1.1.1"
|
||||||
checkerFramework = "3.42.0"
|
checkerFramework = "3.42.0"
|
||||||
cobalt = { strictly = "0.9.3" }
|
cobalt = { strictly = "0.9.5" }
|
||||||
commonsCli = "1.6.0"
|
commonsCli = "1.6.0"
|
||||||
jetbrainsAnnotations = "24.1.0"
|
jetbrainsAnnotations = "24.1.0"
|
||||||
jsr305 = "3.0.2"
|
jsr305 = "3.0.2"
|
||||||
jzlib = "1.1.3"
|
jzlib = "1.1.3"
|
||||||
kotlin = "1.9.21"
|
kotlin = "2.1.0"
|
||||||
kotlin-coroutines = "1.7.3"
|
kotlin-coroutines = "1.10.1"
|
||||||
nightConfig = "3.6.7"
|
nightConfig = "3.8.1"
|
||||||
|
|
||||||
# Minecraft mods
|
# Minecraft mods
|
||||||
emi = "1.1.7+1.21"
|
emi = "1.1.7+1.21"
|
||||||
fabricPermissions = "0.3.1"
|
fabricPermissions = "0.3.1"
|
||||||
iris = "1.6.14+1.20.4"
|
iris-fabric = "1.8.0-beta.3+1.21-fabric"
|
||||||
jei = "19.0.0.1"
|
iris-forge = "1.8.0-beta.3+1.21-neoforge"
|
||||||
|
jei = "19.8.2.99"
|
||||||
modmenu = "11.0.0-rc.4"
|
modmenu = "11.0.0-rc.4"
|
||||||
moreRed = "4.0.0.4"
|
moreRed = "4.0.0.4"
|
||||||
oculus = "1.2.5"
|
|
||||||
rei = "16.0.729"
|
rei = "16.0.729"
|
||||||
rubidium = "0.6.1"
|
sodium-fabric = "mc1.21-0.6.0-beta.1-fabric"
|
||||||
sodium = "mc1.20-0.4.10"
|
sodium-forge = "mc1.21-0.6.0-beta.1-neoforge"
|
||||||
mixinExtra = "0.3.5"
|
mixinExtra = "0.3.5"
|
||||||
|
create-forge = "0.5.1.f-33"
|
||||||
|
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
hamcrest = "2.2"
|
hamcrest = "2.2"
|
||||||
jqwik = "1.8.2"
|
jqwik = "1.8.2"
|
||||||
junit = "5.10.1"
|
junit = "5.11.4"
|
||||||
|
junitPlatform = "1.11.4"
|
||||||
jmh = "1.37"
|
jmh = "1.37"
|
||||||
|
|
||||||
# Build tools
|
# Build tools
|
||||||
cctJavadoc = "1.8.2"
|
cctJavadoc = "1.8.3"
|
||||||
checkstyle = "10.14.1"
|
checkstyle = "10.20.1"
|
||||||
curseForgeGradle = "1.1.18"
|
|
||||||
errorProne-core = "2.27.0"
|
errorProne-core = "2.27.0"
|
||||||
errorProne-plugin = "3.1.0"
|
errorProne-plugin = "3.1.0"
|
||||||
fabric-loom = "1.6.7"
|
fabric-loom = "1.9.2"
|
||||||
githubRelease = "2.5.2"
|
githubRelease = "2.5.2"
|
||||||
gradleVersions = "0.50.0"
|
gradleVersions = "0.50.0"
|
||||||
ideaExt = "1.1.7"
|
ideaExt = "1.1.7"
|
||||||
illuaminate = "0.1.0-73-g43ee16c"
|
illuaminate = "0.1.0-74-gf1551d5"
|
||||||
lwjgl = "3.3.3"
|
lwjgl = "3.3.3"
|
||||||
minotaur = "2.8.7"
|
minotaur = "2.8.7"
|
||||||
neoGradle = "7.0.145"
|
modDevGradle = "2.0.74"
|
||||||
nullAway = "0.10.25"
|
nullAway = "0.10.25"
|
||||||
|
shadow = "8.3.1"
|
||||||
spotless = "6.23.3"
|
spotless = "6.23.3"
|
||||||
taskTree = "2.1.1"
|
taskTree = "2.1.1"
|
||||||
teavm = "0.10.0-SQUID.4"
|
teavm = "0.11.0-SQUID.1"
|
||||||
vanillaExtract = "0.1.3"
|
vanillaExtract = "0.2.0"
|
||||||
versionCatalogUpdate = "0.8.1"
|
versionCatalogUpdate = "0.8.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
@@ -92,20 +95,24 @@ jzlib = { module = "com.jcraft:jzlib", version.ref = "jzlib" }
|
|||||||
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
|
kotlin-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" }
|
||||||
kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
|
kotlin-platform = { module = "org.jetbrains.kotlin:kotlin-bom", version.ref = "kotlin" }
|
||||||
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
|
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
|
||||||
|
netty-codec = { module = "io.netty:netty-codec", version.ref = "netty" }
|
||||||
netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
|
netty-http = { module = "io.netty:netty-codec-http", version.ref = "netty" }
|
||||||
netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" }
|
|
||||||
netty-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" }
|
netty-proxy = { module = "io.netty:netty-handler-proxy", version.ref = "netty" }
|
||||||
|
netty-socks = { module = "io.netty:netty-codec-socks", version.ref = "netty" }
|
||||||
nightConfig-core = { module = "com.electronwill.night-config:core", version.ref = "nightConfig" }
|
nightConfig-core = { module = "com.electronwill.night-config:core", version.ref = "nightConfig" }
|
||||||
nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref = "nightConfig" }
|
nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref = "nightConfig" }
|
||||||
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
||||||
|
|
||||||
# Minecraft mods
|
# Minecraft mods
|
||||||
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
|
create-fabric = { module = "com.simibubi.create:create-fabric-1.20.1", version.ref = "create-fabric" }
|
||||||
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
|
create-forge = { module = "com.simibubi.create:create-1.20.1", version.ref = "create-forge" }
|
||||||
fabric-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" }
|
|
||||||
fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" }
|
|
||||||
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
|
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
|
||||||
iris = { module = "maven.modrinth:iris", version.ref = "iris" }
|
fabric-api = { module = "net.fabricmc.fabric-api:fabric-api", version.ref = "fabric-api" }
|
||||||
|
fabric-junit = { module = "net.fabricmc:fabric-loader-junit", version.ref = "fabric-loader" }
|
||||||
|
fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-loader" }
|
||||||
|
fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" }
|
||||||
|
iris-fabric = { module = "maven.modrinth:iris", version.ref = "iris-fabric" }
|
||||||
|
iris-forge = { module = "maven.modrinth:iris", version.ref = "iris-forge" }
|
||||||
jei-api = { module = "mezz.jei:jei-1.21-common-api", version.ref = "jei" }
|
jei-api = { module = "mezz.jei:jei-1.21-common-api", version.ref = "jei" }
|
||||||
jei-fabric = { module = "mezz.jei:jei-1.21-fabric", version.ref = "jei" }
|
jei-fabric = { module = "mezz.jei:jei-1.21-fabric", version.ref = "jei" }
|
||||||
jei-forge = { module = "mezz.jei:jei-1.21-neoforge", version.ref = "jei" }
|
jei-forge = { module = "mezz.jei:jei-1.21-neoforge", version.ref = "jei" }
|
||||||
@@ -113,12 +120,11 @@ mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" }
|
|||||||
mixinExtra = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinExtra" }
|
mixinExtra = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinExtra" }
|
||||||
modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" }
|
modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" }
|
||||||
moreRed = { module = "commoble.morered:morered-1.20.1", version.ref = "moreRed" }
|
moreRed = { module = "commoble.morered:morered-1.20.1", version.ref = "moreRed" }
|
||||||
oculus = { module = "maven.modrinth:oculus", version.ref = "oculus" }
|
|
||||||
rei-api = { module = "me.shedaniel:RoughlyEnoughItems-api", version.ref = "rei" }
|
rei-api = { module = "me.shedaniel:RoughlyEnoughItems-api", version.ref = "rei" }
|
||||||
rei-builtin = { module = "me.shedaniel:RoughlyEnoughItems-default-plugin", version.ref = "rei" }
|
rei-builtin = { module = "me.shedaniel:RoughlyEnoughItems-default-plugin", version.ref = "rei" }
|
||||||
rei-fabric = { module = "me.shedaniel:RoughlyEnoughItems-fabric", version.ref = "rei" }
|
rei-fabric = { module = "me.shedaniel:RoughlyEnoughItems-fabric", version.ref = "rei" }
|
||||||
rubidium = { module = "maven.modrinth:rubidium", version.ref = "rubidium" }
|
sodium-fabric = { module = "maven.modrinth:sodium", version.ref = "sodium.fabric" }
|
||||||
sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
|
sodium-forge = { module = "maven.modrinth:sodium", version.ref = "sodium.forge" }
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
|
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
|
||||||
@@ -127,6 +133,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-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-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-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" }
|
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
|
||||||
jmh = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
|
jmh = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
|
||||||
jmh-processor = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
|
jmh-processor = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
|
||||||
@@ -140,7 +147,6 @@ lwjgl-glfw = { module = "org.lwjgl:lwjgl-glfw" }
|
|||||||
# Build tools
|
# Build tools
|
||||||
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
|
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
|
||||||
checkstyle = { module = "com.puppycrawl.tools:checkstyle", version.ref = "checkstyle" }
|
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-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-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-core = { module = "com.google.errorprone:error_prone_core", version.ref = "errorProne-core" }
|
||||||
@@ -150,8 +156,8 @@ fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom"
|
|||||||
ideaExt = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "ideaExt" }
|
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" }
|
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||||
minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
|
minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
|
||||||
neoGradle-userdev = { module = "net.neoforged.gradle:userdev", version.ref = "neoGradle" }
|
|
||||||
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
|
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" }
|
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
|
||||||
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
|
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
|
||||||
teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
|
teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
|
||||||
@@ -169,6 +175,7 @@ yarn = { module = "net.fabricmc:yarn", version.ref = "yarn" }
|
|||||||
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
|
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
|
||||||
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
|
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
|
shadow = { id = "com.gradleup.shadow", version.ref = "shadow" }
|
||||||
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
|
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
|
||||||
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
|
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
|
||||||
|
|
||||||
@@ -177,15 +184,15 @@ annotations = ["jsr305", "checkerFramework", "jetbrainsAnnotations"]
|
|||||||
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
||||||
|
|
||||||
# Minecraft
|
# Minecraft
|
||||||
externalMods-common = ["jei-api", "nightConfig-core", "nightConfig-toml"]
|
externalMods-common = ["iris-forge", "jei-api", "nightConfig-core", "nightConfig-toml"]
|
||||||
externalMods-forge-compile = ["moreRed", "oculus", "jei-api"]
|
externalMods-forge-compile = ["moreRed", "iris-forge", "jei-api"]
|
||||||
externalMods-forge-runtime = ["jei-forge"]
|
externalMods-forge-runtime = ["jei-forge"]
|
||||||
externalMods-fabric-compile = ["fabricPermissions", "iris", "jei-api", "rei-api", "rei-builtin"]
|
externalMods-fabric-compile = ["fabricPermissions", "iris-fabric", "jei-api", "rei-api", "rei-builtin"]
|
||||||
externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
|
externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
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
|
# Build tools
|
||||||
teavm-api = ["teavm-jso", "teavm-jso-apis", "teavm-platform", "teavm-classlib", "teavm-metaprogramming-api"]
|
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
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
6
gradlew
vendored
6
gradlew
vendored
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -84,7 +86,7 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || 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.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
2
gradlew.bat
vendored
2
gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
1277
package-lock.json
generated
1277
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -13,10 +13,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||||
"@rollup/plugin-typescript": "^11.0.0",
|
"@rollup/plugin-typescript": "^12.0.0",
|
||||||
"@rollup/plugin-url": "^8.0.1",
|
"@rollup/plugin-url": "^8.0.1",
|
||||||
"@swc/core": "^1.3.92",
|
"@swc/core": "^1.3.92",
|
||||||
"@types/node": "^20.8.3",
|
"@types/node": "^22.0.0",
|
||||||
"lightningcss": "^1.22.0",
|
"lightningcss": "^1.22.0",
|
||||||
"preact-render-to-string": "^6.2.1",
|
"preact-render-to-string": "^6.2.1",
|
||||||
"rehype": "^13.0.0",
|
"rehype": "^13.0.0",
|
||||||
|
@@ -8,6 +8,8 @@ plugins {
|
|||||||
id("cc-tweaked.vanilla")
|
id("cc-tweaked.vanilla")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val mcVersion: String by extra
|
||||||
|
|
||||||
java {
|
java {
|
||||||
withJavadocJar()
|
withJavadocJar()
|
||||||
}
|
}
|
||||||
@@ -16,9 +18,58 @@ dependencies {
|
|||||||
api(project(":core-api"))
|
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 {
|
tasks.javadoc {
|
||||||
|
title = "CC: Tweaked $version for Minecraft $mcVersion"
|
||||||
include("dan200/computercraft/api/**/*.java")
|
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.
|
// 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 })
|
source(project(":core-api").sourceSets.main.map { it.allJava })
|
||||||
|
|
||||||
|
@@ -21,7 +21,14 @@ import java.util.stream.Stream;
|
|||||||
* <p>
|
* <p>
|
||||||
* Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a
|
* 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
|
* 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.
|
* @param <T> The type of turtle upgrade this modeller applies to.
|
||||||
* @see RegisterTurtleUpgradeModeller For multi-loader registration support.
|
* @see RegisterTurtleUpgradeModeller For multi-loader registration support.
|
||||||
|
@@ -4,9 +4,11 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api;
|
package dan200.computercraft.api;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.component.ComputerComponent;
|
||||||
import dan200.computercraft.api.filesystem.Mount;
|
import dan200.computercraft.api.filesystem.Mount;
|
||||||
import dan200.computercraft.api.filesystem.WritableMount;
|
import dan200.computercraft.api.filesystem.WritableMount;
|
||||||
import dan200.computercraft.api.lua.GenericSource;
|
import dan200.computercraft.api.lua.GenericSource;
|
||||||
|
import dan200.computercraft.api.lua.IComputerSystem;
|
||||||
import dan200.computercraft.api.lua.ILuaAPI;
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
import dan200.computercraft.api.media.IMedia;
|
import dan200.computercraft.api.media.IMedia;
|
||||||
@@ -165,7 +167,13 @@ public final class ComputerCraftAPI {
|
|||||||
* Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
|
* Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
|
||||||
* <p>
|
* <p>
|
||||||
* Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
|
* Before implementing this interface, consider alternative methods of providing methods. It is generally preferred
|
||||||
* to use peripherals to provide functionality to users.
|
* to use peripherals to provide functionality to users. If an API is <em>required</em>, you may want to consider
|
||||||
|
* using {@link ILuaAPI#getModuleName()} to expose this library as a module instead of as a global.
|
||||||
|
* <p>
|
||||||
|
* This may be used with {@link IComputerSystem#getComponent(ComputerComponent)} to only attach APIs to specific
|
||||||
|
* computers. For example, one can add a new API just to turtles with the following code:
|
||||||
|
*
|
||||||
|
* {@snippet class=com.example.examplemod.ExampleAPI region=register}
|
||||||
*
|
*
|
||||||
* @param factory The factory for your API subclass.
|
* @param factory The factory for your API subclass.
|
||||||
* @see ILuaAPIFactory
|
* @see ILuaAPIFactory
|
||||||
|
@@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.component;
|
||||||
|
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A computer which has permission to perform administrative/op commands, such as the command computer.
|
||||||
|
*/
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
public interface AdminComputer {
|
||||||
|
/**
|
||||||
|
* The permission level that this computer can operate at.
|
||||||
|
*
|
||||||
|
* @return The permission level for this computer.
|
||||||
|
* @see CommandSourceStack#hasPermission(int)
|
||||||
|
*/
|
||||||
|
default int permissionLevel() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.component;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.IComputerSystem;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component attached to a computer.
|
||||||
|
* <p>
|
||||||
|
* Components provide a mechanism to attach additional data to a computer, that can then be queried with
|
||||||
|
* {@link IComputerSystem#getComponent(ComputerComponent)}.
|
||||||
|
* <p>
|
||||||
|
* This is largely designed for {@linkplain ILuaAPIFactory custom APIs}, allowing APIs to read additional properties
|
||||||
|
* of the computer, such as its position.
|
||||||
|
*
|
||||||
|
* @param <T> The type of this component.
|
||||||
|
* @see ComputerComponents The built-in components.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("UnusedTypeParameter")
|
||||||
|
public final class ComputerComponent<T> {
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
private ComputerComponent(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new computer component.
|
||||||
|
* <p>
|
||||||
|
* Mods typically will not need to create their own components.
|
||||||
|
*
|
||||||
|
* @param namespace The namespace of this component. This should be the mod id.
|
||||||
|
* @param id The unique id of this component.
|
||||||
|
* @param <T> The component
|
||||||
|
* @return The newly created component.
|
||||||
|
*/
|
||||||
|
public static <T> ComputerComponent<T> create(String namespace, String id) {
|
||||||
|
return new ComputerComponent<>(namespace + ":" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "ComputerComponent(" + id + ")";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.component;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.pocket.IPocketAccess;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link ComputerComponent}s provided by ComputerCraft.
|
||||||
|
*/
|
||||||
|
public class ComputerComponents {
|
||||||
|
/**
|
||||||
|
* The {@link ITurtleAccess} associated with a turtle.
|
||||||
|
*/
|
||||||
|
public static final ComputerComponent<ITurtleAccess> TURTLE = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "turtle");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link IPocketAccess} associated with a pocket computer.
|
||||||
|
*/
|
||||||
|
public static final ComputerComponent<IPocketAccess> POCKET = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "pocket");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component is only present on "command computers", and other computers with admin capabilities.
|
||||||
|
*/
|
||||||
|
public static final ComputerComponent<AdminComputer> ADMIN_COMPUTER = ComputerComponent.create(ComputerCraftAPI.MOD_ID, "admin_computer");
|
||||||
|
}
|
@@ -13,7 +13,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An item detail provider for {@link ItemStack}'s whose {@link Item} has a specific type.
|
* An item detail provider for {@link ItemStack}s whose {@link Item} has a specific type.
|
||||||
*
|
*
|
||||||
* @param <T> The type the stack's item must have.
|
* @param <T> The type the stack's item must have.
|
||||||
*/
|
*/
|
||||||
@@ -22,7 +22,7 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
|||||||
private final @Nullable String namespace;
|
private final @Nullable String namespace;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new item detail provider. Meta will be inserted into a new sub-map named as per {@code namespace}.
|
* Create a new item detail provider. Details will be inserted into a new sub-map named as per {@code namespace}.
|
||||||
*
|
*
|
||||||
* @param itemType The type the stack's item must have.
|
* @param itemType The type the stack's item must have.
|
||||||
* @param namespace The namespace to use for this provider.
|
* @param namespace The namespace to use for this provider.
|
||||||
@@ -34,7 +34,7 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new item detail provider. Meta will be inserted directly into the results.
|
* Create a new item detail provider. Details will be inserted directly into the results.
|
||||||
*
|
*
|
||||||
* @param itemType The type the stack's item must have.
|
* @param itemType The type the stack's item must have.
|
||||||
*/
|
*/
|
||||||
@@ -53,21 +53,18 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
|||||||
* @param stack The item stack to provide details for.
|
* @param stack The item stack to provide details for.
|
||||||
* @param item The item to provide details for.
|
* @param item The item to provide details for.
|
||||||
*/
|
*/
|
||||||
public abstract void provideDetails(
|
public abstract void provideDetails(Map<? super String, Object> data, ItemStack stack, T item);
|
||||||
Map<? super String, Object> data, ItemStack stack, T item
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void provideDetails(Map<? super String, Object> data, ItemStack stack) {
|
public final void provideDetails(Map<? super String, Object> data, ItemStack stack) {
|
||||||
var item = stack.getItem();
|
var item = stack.getItem();
|
||||||
if (!itemType.isInstance(item)) return;
|
if (!itemType.isInstance(item)) return;
|
||||||
|
|
||||||
// If `namespace` is specified, insert into a new data map instead of the existing one.
|
if (namespace == null) {
|
||||||
Map<? super String, Object> child = namespace == null ? data : new HashMap<>();
|
provideDetails(data, stack, itemType.cast(item));
|
||||||
|
} else {
|
||||||
provideDetails(child, stack, itemType.cast(item));
|
Map<? super String, Object> child = new HashMap<>();
|
||||||
|
provideDetails(child, stack, itemType.cast(item));
|
||||||
if (namespace != null) {
|
|
||||||
data.put(namespace, child);
|
data.put(namespace, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,72 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.detail;
|
||||||
|
|
||||||
|
import net.minecraft.core.component.DataComponentHolder;
|
||||||
|
import net.minecraft.core.component.DataComponentType;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item detail provider for a specific {@linkplain DataComponentType data component} on {@link ItemStack}s or
|
||||||
|
* other {@link DataComponentHolder}.
|
||||||
|
*
|
||||||
|
* @param <T> The type of the component's contents.
|
||||||
|
*/
|
||||||
|
public abstract class ComponentDetailProvider<T> implements DetailProvider<DataComponentHolder> {
|
||||||
|
private final DataComponentType<T> component;
|
||||||
|
private final @Nullable String namespace;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new component detail provider. Details will be inserted into a new sub-map named as per {@code namespace}.
|
||||||
|
*
|
||||||
|
* @param component The data component to provide details for.
|
||||||
|
* @param namespace The namespace to use for this provider.
|
||||||
|
*/
|
||||||
|
public ComponentDetailProvider(@Nullable String namespace, DataComponentType<T> component) {
|
||||||
|
Objects.requireNonNull(component);
|
||||||
|
this.component = component;
|
||||||
|
this.namespace = namespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new component detail provider. Details will be inserted directly into the results.
|
||||||
|
*
|
||||||
|
* @param component The data component to provide details for.
|
||||||
|
*/
|
||||||
|
public ComponentDetailProvider(DataComponentType<T> component) {
|
||||||
|
this(null, component);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide additional details for the given data component. This method is called by {@code turtle.getItemDetail()}.
|
||||||
|
* New properties should be added to the given {@link Map}, {@code data}.
|
||||||
|
* <p>
|
||||||
|
* This method is always called on the server thread, so it is safe to interact with the world here, but you should
|
||||||
|
* take care to avoid long blocking operations as this will stall the server and other computers.
|
||||||
|
*
|
||||||
|
* @param data The full details to be returned for this item stack. New properties should be added to this map.
|
||||||
|
* @param item The component to provide details for.
|
||||||
|
*/
|
||||||
|
public abstract void provideComponentDetails(Map<? super String, Object> data, T item);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void provideDetails(Map<? super String, Object> data, DataComponentHolder holder) {
|
||||||
|
var value = holder.get(component);
|
||||||
|
if (value == null) return;
|
||||||
|
|
||||||
|
if (namespace == null) {
|
||||||
|
provideComponentDetails(data, value);
|
||||||
|
} else {
|
||||||
|
Map<? super String, Object> child = new HashMap<>();
|
||||||
|
provideComponentDetails(child, value);
|
||||||
|
data.put(namespace, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -26,7 +26,7 @@ public interface DetailRegistry<T> {
|
|||||||
* @param provider The detail provider to register.
|
* @param provider The detail provider to register.
|
||||||
* @see DetailProvider
|
* @see DetailProvider
|
||||||
*/
|
*/
|
||||||
void addProvider(DetailProvider<T> provider);
|
void addProvider(DetailProvider<? super T> provider);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute basic details about an object. This is cheaper than computing all details operation, and so is suitable
|
* Compute basic details about an object. This is cheaper than computing all details operation, and so is suitable
|
||||||
|
@@ -0,0 +1,59 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.component.ComputerComponent;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface passed to {@link ILuaAPIFactory} in order to provide additional information
|
||||||
|
* about a computer.
|
||||||
|
*/
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
|
public interface IComputerSystem extends IComputerAccess {
|
||||||
|
/**
|
||||||
|
* Get the level this computer is currently in.
|
||||||
|
* <p>
|
||||||
|
* This method is not guaranteed to remain the same (even for stationary computers).
|
||||||
|
*
|
||||||
|
* @return The computer's current level.
|
||||||
|
*/
|
||||||
|
ServerLevel getLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position this computer is currently at.
|
||||||
|
* <p>
|
||||||
|
* This method is not guaranteed to remain the same (even for stationary computers).
|
||||||
|
*
|
||||||
|
* @return The computer's current position.
|
||||||
|
*/
|
||||||
|
BlockPos getPosition();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the label for this computer.
|
||||||
|
*
|
||||||
|
* @return This computer's label, or {@code null} if it is not set.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
String getLabel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a component attached to this computer.
|
||||||
|
* <p>
|
||||||
|
* No component is guaranteed to be on a computer, and so this method should always be guarded with a null check.
|
||||||
|
* <p>
|
||||||
|
* This method will always return the same value for a given component, and so may be cached.
|
||||||
|
*
|
||||||
|
* @param component The component to query.
|
||||||
|
* @param <T> The type of the component.
|
||||||
|
* @return The component, if present.
|
||||||
|
*/
|
||||||
|
<T> @Nullable T getComponent(ComputerComponent<T> component);
|
||||||
|
}
|
@@ -4,13 +4,15 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.lua;
|
package dan200.computercraft.api.lua;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct an {@link ILuaAPI} for a specific computer.
|
* Construct an {@link ILuaAPI} for a computer.
|
||||||
*
|
*
|
||||||
* @see ILuaAPI
|
* @see ILuaAPI
|
||||||
* @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
||||||
*/
|
*/
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface ILuaAPIFactory {
|
public interface ILuaAPIFactory {
|
@@ -14,7 +14,7 @@ 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
|
* as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant
|
||||||
* for its lifespan.
|
* for its lifespan.
|
||||||
* <p>
|
* <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.
|
* {@link WiredElement} capability for the appropriate sides.
|
||||||
*/
|
*/
|
||||||
public interface WiredElement extends WiredSender {
|
public interface WiredElement extends WiredSender {
|
||||||
|
@@ -5,16 +5,35 @@
|
|||||||
package dan200.computercraft.api.pocket;
|
package dan200.computercraft.api.pocket;
|
||||||
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper class for pocket computers.
|
* Wrapper class for pocket computers.
|
||||||
*/
|
*/
|
||||||
|
@ApiStatus.NonExtendable
|
||||||
public interface IPocketAccess {
|
public interface IPocketAccess {
|
||||||
|
/**
|
||||||
|
* Get the level in which the pocket computer exists.
|
||||||
|
*
|
||||||
|
* @return The pocket computer's level.
|
||||||
|
*/
|
||||||
|
ServerLevel getLevel();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the position of the pocket computer.
|
||||||
|
*
|
||||||
|
* @return The pocket computer's position.
|
||||||
|
*/
|
||||||
|
Vec3 getPosition();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the entity holding this item.
|
* Gets the entity holding this item.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -61,6 +80,26 @@ public interface IPocketAccess {
|
|||||||
*/
|
*/
|
||||||
void setLight(int colour);
|
void setLight(int colour);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currently equipped upgrade.
|
||||||
|
*
|
||||||
|
* @return The currently equipped upgrade.
|
||||||
|
* @see #getUpgradeData()
|
||||||
|
* @see #setUpgrade(UpgradeData)
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
UpgradeData<IPocketUpgrade> getUpgrade();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the upgrade for this pocket computer, also updating the item stack.
|
||||||
|
* <p>
|
||||||
|
* Note this method is not thread safe - it must be called from the server thread.
|
||||||
|
*
|
||||||
|
* @param upgrade The new upgrade to set it to, may be {@code null}.
|
||||||
|
* @see #getUpgrade()
|
||||||
|
*/
|
||||||
|
void setUpgrade(@Nullable UpgradeData<IPocketUpgrade> upgrade);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the upgrade-specific NBT.
|
* Get the upgrade-specific NBT.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -70,6 +109,7 @@ public interface IPocketAccess {
|
|||||||
* @see #setUpgradeData(DataComponentPatch)
|
* @see #setUpgradeData(DataComponentPatch)
|
||||||
* @see UpgradeBase#getUpgradeItem(DataComponentPatch)
|
* @see UpgradeBase#getUpgradeItem(DataComponentPatch)
|
||||||
* @see UpgradeBase#getUpgradeData(ItemStack)
|
* @see UpgradeBase#getUpgradeData(ItemStack)
|
||||||
|
* @see #getUpgrade()
|
||||||
*/
|
*/
|
||||||
DataComponentPatch getUpgradeData();
|
DataComponentPatch getUpgradeData();
|
||||||
|
|
||||||
|
@@ -20,32 +20,10 @@ import javax.annotation.Nullable;
|
|||||||
* A peripheral which can be equipped to the back side of a pocket computer.
|
* A peripheral which can be equipped to the back side of a pocket computer.
|
||||||
* <p>
|
* <p>
|
||||||
* Pocket upgrades are defined in two stages. First, one creates a {@link IPocketUpgrade} subclass and corresponding
|
* Pocket upgrades are defined in two stages. First, one creates a {@link IPocketUpgrade} subclass and corresponding
|
||||||
* {@link UpgradeType} instance, which are then registered in a registry.
|
* {@link UpgradeType} instance, which are then registered in a Minecraft registry.
|
||||||
* <p>
|
* <p>
|
||||||
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
||||||
* the upgrade automatically registered. It is recommended this is done via
|
* the upgrade registered internally.
|
||||||
* <a href="../upgrades/UpgradeType.html#datagen">data generators</a>.
|
|
||||||
*
|
|
||||||
* <h2>Example</h2>
|
|
||||||
* {@snippet lang="java" :
|
|
||||||
* // We use Forge's DeferredRegister to register our upgrade type. Fabric mods may register their type directly.
|
|
||||||
* static final DeferredRegister<UpgradeType<? extends IPocketUpgrade>> POCKET_UPGRADES = DeferredRegister.create(IPocketUpgrade.typeRegistry(), "my_mod");
|
|
||||||
*
|
|
||||||
* // Register a new upgrade upgrade type called "my_upgrade".
|
|
||||||
* public static final RegistryObject<UpgradeType<MyUpgrade>> MY_UPGRADE =
|
|
||||||
* POCKET_UPGRADES.register("my_upgrade", () -> UpgradeType.simple(new MyUpgrade()));
|
|
||||||
*
|
|
||||||
* // Then in your constructor
|
|
||||||
* POCKET_UPGRADES.register(bus);
|
|
||||||
* }
|
|
||||||
* <p>
|
|
||||||
* We can then define a new upgrade using JSON by placing the following in
|
|
||||||
* {@code data/<my_mod>/computercraft/pocket_upgrade/<my_upgrade_id>.json}.
|
|
||||||
* {@snippet lang="json" :
|
|
||||||
* {
|
|
||||||
* "type": "my_mod:my_upgrade"
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
*/
|
||||||
public interface IPocketUpgrade extends UpgradeBase {
|
public interface IPocketUpgrade extends UpgradeBase {
|
||||||
ResourceKey<Registry<IPocketUpgrade>> REGISTRY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_upgrade"));
|
ResourceKey<Registry<IPocketUpgrade>> REGISTRY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_upgrade"));
|
||||||
|
@@ -11,47 +11,79 @@ import dan200.computercraft.api.upgrades.UpgradeType;
|
|||||||
import dan200.computercraft.impl.ComputerCraftAPIService;
|
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.core.RegistrySetBuilder.PatchedRegistries;
|
||||||
import net.minecraft.core.component.DataComponentPatch;
|
import net.minecraft.core.component.DataComponentPatch;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new
|
* The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new
|
||||||
* peripheral.
|
* peripheral.
|
||||||
* <p>
|
* <p>
|
||||||
* Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
|
* Turtle upgrades are defined in two stages. First, one creates a {@link ITurtleUpgrade} subclass and corresponding
|
||||||
* {@link UpgradeType} instance, which are then registered in a registry.
|
* {@link UpgradeType} instance, which are then registered in a Minecraft registry.
|
||||||
* <p>
|
* <p>
|
||||||
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
* You then write a JSON file in your mod's {@literal data/} folder. This is then parsed when the world is loaded, and
|
||||||
* the upgrade automatically registered. It is recommended this is done via
|
* the upgrade automatically registered.
|
||||||
* <a href="../upgrades/UpgradeType.html#datagen">data generators</a>.
|
|
||||||
*
|
*
|
||||||
* <h2>Example</h2>
|
* <h2>Example</h2>
|
||||||
* {@snippet lang="java" :
|
* <h3>Registering the upgrade type</h3>
|
||||||
* // We use Forge's DeferredRegister to register our upgrade type. Fabric mods may register their type directly.
|
* First, let's create a new class that implements {@link ITurtleUpgrade}. It is recommended to subclass
|
||||||
* static final DeferredRegister<UpgradeType<? extends ITurtleUpgrade>> TURTLE_UPGRADES = DeferredRegister.create(ITurtleUpgrade.typeRegistry(), "my_mod");
|
* {@link AbstractTurtleUpgrade}, as that provides a default implementation of most methods.
|
||||||
*
|
*
|
||||||
* // Register a new upgrade type called "my_upgrade".
|
* {@snippet class=com.example.examplemod.ExampleTurtleUpgrade region=body}
|
||||||
* public static final RegistryObject<UpgradeType<MyUpgrade>> MY_UPGRADE =
|
|
||||||
* TURTLE_UPGRADES.register("my_upgrade", () -> UpgradeType.simple(MyUpgrade::new));
|
|
||||||
*
|
*
|
||||||
* // Then in your constructor
|
* Now we must construct a new upgrade type. In most cases, you can use one of the helper methods (e.g.
|
||||||
* TURTLE_UPGRADES.register(bus);
|
* {@link UpgradeType#simpleWithCustomItem(Function)}), rather than defining your own implementation.
|
||||||
* }
|
*
|
||||||
|
* {@snippet class=com.example.examplemod.ExampleMod region=turtle_upgrades}
|
||||||
|
*
|
||||||
|
* We now must register this upgrade type. 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 type.
|
||||||
|
*
|
||||||
|
* <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 id="datagen">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_upgrade/<my_upgrade_id>.json}.
|
||||||
|
*
|
||||||
|
* {@snippet file=data/examplemod/computercraft/turtle_upgrade/example_turtle_upgrade.json}
|
||||||
|
*
|
||||||
|
* The {@code "type"} field points to the ID of the upgrade type we've just registered, while the other fields are read
|
||||||
|
* by the type itself. As our upgrade was defined with {@link UpgradeType#simpleWithCustomItem(Function)}, the
|
||||||
|
* {@code "item"} field will construct our upgrade with {@link Items#COMPASS}.
|
||||||
* <p>
|
* <p>
|
||||||
* We can then define a new upgrade using JSON by placing the following in
|
* Rather than manually creating the file, it is recommended to use data-generators to generate this file. First, we
|
||||||
* {@code data/<my_mod>/computercraft/turtle_upgrade/<my_upgrade_id>.json}.
|
* register our new upgrades into a {@linkplain PatchedRegistries patched registry}.
|
||||||
* <p>
|
*
|
||||||
* {@snippet lang="json" :
|
* {@snippet class=com.example.examplemod.data.TurtleUpgradeProvider region=body}
|
||||||
* {
|
*
|
||||||
* "type": "my_mod:my_upgrade"
|
* Next, we must write these upgrades to disk. Vanilla does not have complete support for this yet, so this must be done
|
||||||
* }
|
* with mod-loader-specific APIs.
|
||||||
* }
|
*
|
||||||
* <p>
|
* <h4>Fabric</h4>
|
||||||
* Finally, we need to register a model for our upgrade, see
|
* {@snippet class=com.example.examplemod.FabricExampleModDataGenerator region=turtle_upgrades}
|
||||||
* {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for more information.
|
*
|
||||||
|
* <h4>Forge</h4>
|
||||||
|
* {@snippet class=com.example.examplemod.ForgeExampleModDataGenerator region=turtle_upgrades}
|
||||||
*/
|
*/
|
||||||
public interface ITurtleUpgrade extends UpgradeBase {
|
public interface ITurtleUpgrade extends UpgradeBase {
|
||||||
/**
|
/**
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
package dan200.computercraft.api.turtle;
|
package dan200.computercraft.api.turtle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An enum representing the two sides of the turtle that a turtle turtle might reside.
|
* An enum representing the two sides of the turtle that a turtle upgrade might reside.
|
||||||
*/
|
*/
|
||||||
public enum TurtleSide {
|
public enum TurtleSide {
|
||||||
/**
|
/**
|
||||||
|
@@ -25,19 +25,11 @@ import java.util.Optional;
|
|||||||
/**
|
/**
|
||||||
* A builder for custom turtle tool upgrades.
|
* A builder for custom turtle tool upgrades.
|
||||||
* <p>
|
* <p>
|
||||||
* This can be used from your <a href="../upgrades/UpgradeType.html#datagen">data generator</a> code in order to
|
* This can be used from your <a href="./ITurtleUpgrade.html#datagen">data generator</a> code in order to
|
||||||
* register turtle tools for your mod's tools.
|
* register turtle tools for your mod's tools.
|
||||||
*
|
*
|
||||||
* <h2>Example:</h2>
|
* <h2>Example</h2>
|
||||||
* {@snippet lang = "java":
|
* {@snippet class=com.example.examplemod.data.TurtleToolProvider region=body}
|
||||||
* import net.minecraft.data.worldgen.BootstrapContext;
|
|
||||||
* import net.minecraft.resources.ResourceLocation;
|
|
||||||
* import net.minecraft.world.item.Items;
|
|
||||||
*
|
|
||||||
* public void registerTool(BootstrapContext<ITurtleUpgrade> upgrades) {
|
|
||||||
* TurtleToolBuilder.tool(ResourceLocation.fromNamespaceAndPath("my_mod", "wooden_pickaxe"), Items.WOODEN_PICKAXE).register(upgrades);
|
|
||||||
* }
|
|
||||||
*}
|
|
||||||
*/
|
*/
|
||||||
public final class TurtleToolBuilder {
|
public final class TurtleToolBuilder {
|
||||||
private final ResourceKey<ITurtleUpgrade> id;
|
private final ResourceKey<ITurtleUpgrade> id;
|
||||||
|
@@ -7,9 +7,7 @@ package dan200.computercraft.api.upgrades;
|
|||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
import dan200.computercraft.impl.upgrades.UpgradeTypeImpl;
|
|
||||||
import net.minecraft.core.registries.BuiltInRegistries;
|
import net.minecraft.core.registries.BuiltInRegistries;
|
||||||
import net.minecraft.data.registries.RegistryPatchGenerator;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.crafting.Recipe;
|
import net.minecraft.world.item.crafting.Recipe;
|
||||||
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
|
import net.minecraft.world.level.storage.loot.functions.LootItemFunction;
|
||||||
@@ -23,13 +21,10 @@ import java.util.function.Function;
|
|||||||
* follow a similar design to other dynamic content, such as {@linkplain Recipe recipes} or {@link LootItemFunction
|
* follow a similar design to other dynamic content, such as {@linkplain Recipe recipes} or {@link LootItemFunction
|
||||||
* loot functions}.
|
* loot functions}.
|
||||||
* <p>
|
* <p>
|
||||||
* First, one adds a new class implementing {@link ITurtleUpgrade} or {@link IPocketUpgrade}). This is responsible for
|
* While the {@link ITurtleUpgrade}/{@link IPocketUpgrade} class should contain the core logic of the upgrade, they are
|
||||||
* handling all the logic of your upgrade.
|
* not registered directly. Instead, each upgrade class has a corresponding {@link UpgradeType}, which is responsible
|
||||||
* <p>
|
* for loading the upgrade from a datapack. The upgrade type should then be registered in its appropriate registry
|
||||||
* However, the upgrades are not registered directly. Instead, each upgrade class should have a corresponding
|
* ({@link ITurtleUpgrade#typeRegistry()}, {@link IPocketUpgrade#typeRegistry()}).
|
||||||
* {@link UpgradeType}, which is responsible for loading the upgrade from a datapack. The upgrade type should then be
|
|
||||||
* registered in its appropriate registry ({@link ITurtleUpgrade#typeRegistry()},
|
|
||||||
* {@link IPocketUpgrade#typeRegistry()}).
|
|
||||||
* <p>
|
* <p>
|
||||||
* In order to register the actual upgrade, a JSON file referencing your upgrade type should be added to a datapack. It
|
* In order to register the actual upgrade, a JSON file referencing your upgrade type should be added to a datapack. It
|
||||||
* is recommended to do this via the data generators.
|
* is recommended to do this via the data generators.
|
||||||
@@ -38,29 +33,7 @@ import java.util.function.Function;
|
|||||||
* As turtle and pocket upgrades are just loaded using vanilla's dynamic loaders, one may use the same data generation
|
* As turtle and pocket upgrades are just loaded using vanilla's dynamic loaders, one may use the same data generation
|
||||||
* tools as you would for any other dynamic registry.
|
* tools as you would for any other dynamic registry.
|
||||||
* <p>
|
* <p>
|
||||||
* This can typically be done by extending vanilla's built-in registries using {@link RegistryPatchGenerator}, and then
|
* See <a href="../turtle/ITurtleUpgrade.html#datagen">the turtle upgrade docs</a> for a concrete example.
|
||||||
* writing out the new registries using {@code net.fabricmc.fabric.api.datagen.v1.provider.FabricDynamicRegistryProvider}
|
|
||||||
* on Fabric or {@code net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider} on Forge.
|
|
||||||
* <p>
|
|
||||||
* {@snippet lang="java" :
|
|
||||||
* import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|
||||||
* import net.minecraft.Util;
|
|
||||||
* import net.minecraft.core.HolderLookup;
|
|
||||||
* import net.minecraft.core.RegistrySetBuilder;
|
|
||||||
* import net.minecraft.data.DataGenerator;
|
|
||||||
* import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider;
|
|
||||||
*
|
|
||||||
* import java.util.concurrent.CompletableFuture;
|
|
||||||
*
|
|
||||||
* public void generate(DataGenerator.PackGenerator output, CompletableFuture<HolderLookup.Provider> registries) {
|
|
||||||
* var newRegistries = RegistryPatchGenerator.createLookup(registries, Util.make(new RegistrySetBuilder(), builder -> {
|
|
||||||
* builder.add(ITurtleUpgrade.REGISTRY, upgrades -> {
|
|
||||||
* upgrades.register(ITurtleUpgrade.createKey(ResourceLocation.fromNamespaceAndPath("my_mod", "my_upgrade")), new MyUpgrade());
|
|
||||||
* });
|
|
||||||
* }));
|
|
||||||
* output.addProvider(o -> new DatapackBuiltinEntriesProvider(o, newRegistries, Set.of("my_mod")));
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*
|
*
|
||||||
* @param <T> The upgrade subclass that this upgrade type represents.
|
* @param <T> The upgrade subclass that this upgrade type represents.
|
||||||
* @see ITurtleUpgrade
|
* @see ITurtleUpgrade
|
||||||
|
@@ -2,12 +2,9 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
package dan200.computercraft.impl.upgrades;
|
package dan200.computercraft.api.upgrades;
|
||||||
|
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeType;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple implementation of {@link UpgradeType}.
|
* Simple implementation of {@link UpgradeType}.
|
||||||
@@ -15,6 +12,5 @@ import org.jetbrains.annotations.ApiStatus;
|
|||||||
* @param codec The codec to read/write upgrades with.
|
* @param codec The codec to read/write upgrades with.
|
||||||
* @param <T> The upgrade subclass that this upgrade type represents.
|
* @param <T> The upgrade subclass that this upgrade type represents.
|
||||||
*/
|
*/
|
||||||
@ApiStatus.Internal
|
record UpgradeTypeImpl<T extends UpgradeBase>(MapCodec<T> codec) implements UpgradeType<T> {
|
||||||
public record UpgradeTypeImpl<T extends UpgradeBase>(MapCodec<T> codec) implements UpgradeType<T> {
|
|
||||||
}
|
}
|
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 {
|
plugins {
|
||||||
id("cc-tweaked.vanilla")
|
id("cc-tweaked.vanilla")
|
||||||
id("cc-tweaked.gametest")
|
|
||||||
id("cc-tweaked.illuaminate")
|
id("cc-tweaked.illuaminate")
|
||||||
|
id("cc-tweaked.mod")
|
||||||
id("cc-tweaked.publishing")
|
id("cc-tweaked.publishing")
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
resources.srcDir("src/generated/resources")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
minecraft {
|
minecraft {
|
||||||
accessWideners(
|
accessWideners(
|
||||||
"src/main/resources/computercraft.accesswidener",
|
"src/main/resources/computercraft.accesswidener",
|
||||||
@@ -38,13 +32,14 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Pull in our other projects. See comments in MinecraftConfigurations on this nastiness.
|
// Pull in our other projects. See comments in MinecraftConfigurations on this nastiness.
|
||||||
implementation(project(":core"))
|
api(project(":core"))
|
||||||
implementation(commonClasses(project(":common-api")))
|
api(commonClasses(project(":common-api")))
|
||||||
clientImplementation(clientClasses(project(":common-api")))
|
clientApi(clientClasses(project(":common-api")))
|
||||||
|
|
||||||
compileOnly(libs.mixin)
|
compileOnly(libs.mixin)
|
||||||
compileOnly(libs.mixinExtra)
|
compileOnly(libs.mixinExtra)
|
||||||
compileOnly(libs.bundles.externalMods.common)
|
compileOnly(libs.bundles.externalMods.common)
|
||||||
|
compileOnly(variantOf(libs.create.forge) { classifier("slim") }) { isTransitive = false }
|
||||||
clientCompileOnly(variantOf(libs.emi) { classifier("api") })
|
clientCompileOnly(variantOf(libs.emi) { classifier("api") })
|
||||||
|
|
||||||
annotationProcessorEverywhere(libs.autoService)
|
annotationProcessorEverywhere(libs.autoService)
|
||||||
@@ -68,7 +63,7 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
illuaminate {
|
illuaminate {
|
||||||
version.set(libs.versions.illuaminate)
|
version = libs.versions.illuaminate
|
||||||
}
|
}
|
||||||
|
|
||||||
val luaJavadoc by tasks.registering(Javadoc::class) {
|
val luaJavadoc by tasks.registering(Javadoc::class) {
|
||||||
@@ -89,11 +84,7 @@ val luaJavadoc by tasks.registering(Javadoc::class) {
|
|||||||
options.addStringOption("project-root", rootProject.file(".").absolutePath)
|
options.addStringOption("project-root", rootProject.file(".").absolutePath)
|
||||||
options.noTimestamp(false)
|
options.noTimestamp(false)
|
||||||
|
|
||||||
javadocTool.set(
|
javadocTool = javaToolchains.javadocToolFor { languageVersion = CCTweakedPlugin.JAVA_VERSION }
|
||||||
javaToolchains.javadocToolFor {
|
|
||||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val lintLua by tasks.registering(IlluaminateExec::class) {
|
val lintLua by tasks.registering(IlluaminateExec::class) {
|
||||||
@@ -114,20 +105,31 @@ val lintLua by tasks.registering(IlluaminateExec::class) {
|
|||||||
doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
|
doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
|
||||||
}
|
}
|
||||||
|
|
||||||
val runData by tasks.registering(MergeTrees::class) {
|
fun MergeTrees.configureForDatagen(source: SourceSet, outputFolder: String) {
|
||||||
output = layout.projectDirectory.dir("src/generated/resources")
|
output = layout.projectDirectory.dir(outputFolder)
|
||||||
|
|
||||||
for (loader in listOf("forge", "fabric")) {
|
for (loader in listOf("forge", "fabric")) {
|
||||||
mustRunAfter(":$loader:runData")
|
mustRunAfter(":$loader:$name")
|
||||||
source {
|
source {
|
||||||
input {
|
input {
|
||||||
from(project(":$loader").layout.buildDirectory.dir("generatedResources"))
|
from(project(":$loader").layout.buildDirectory.dir(source.getTaskName("generateResources", null)))
|
||||||
exclude(".cache")
|
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
|
||||||
|
}
|
||||||
|
@@ -64,6 +64,9 @@ public final class ClientHooks {
|
|||||||
public static void onWorldUnload() {
|
public static void onWorldUnload() {
|
||||||
MonitorRenderState.destroyAll();
|
MonitorRenderState.destroyAll();
|
||||||
SpeakerManager.reset();
|
SpeakerManager.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onDisconnect() {
|
||||||
ClientPocketComputers.reset();
|
ClientPocketComputers.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,6 +13,7 @@ import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller;
|
|||||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||||
import dan200.computercraft.client.gui.*;
|
import dan200.computercraft.client.gui.*;
|
||||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||||
|
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||||
import dan200.computercraft.client.render.RenderTypes;
|
import dan200.computercraft.client.render.RenderTypes;
|
||||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
||||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||||
@@ -25,6 +26,7 @@ import dan200.computercraft.shared.computer.core.ComputerState;
|
|||||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||||
import dan200.computercraft.shared.media.items.DiskItem;
|
import dan200.computercraft.shared.media.items.DiskItem;
|
||||||
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.color.item.ItemColor;
|
import net.minecraft.client.color.item.ItemColor;
|
||||||
@@ -53,6 +55,7 @@ import net.minecraft.world.level.ItemLike;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
@@ -77,6 +80,7 @@ public final class ClientRegistry {
|
|||||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), MonitorBlockEntityRenderer::new);
|
BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), MonitorBlockEntityRenderer::new);
|
||||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), TurtleBlockEntityRenderer::new);
|
BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), TurtleBlockEntityRenderer::new);
|
||||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), TurtleBlockEntityRenderer::new);
|
BlockEntityRenderers.register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), TurtleBlockEntityRenderer::new);
|
||||||
|
BlockEntityRenderers.register(ModRegistry.BlockEntities.LECTERN.get(), CustomLecternRenderer::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -143,15 +147,14 @@ public final class ClientRegistry {
|
|||||||
register.accept(GuiSprites.initialise(minecraft.getTextureManager()));
|
register.accept(GuiSprites.initialise(minecraft.getTextureManager()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String[] EXTRA_MODELS = new String[]{
|
private static final ResourceLocation[] EXTRA_MODELS = {
|
||||||
"block/turtle_colour",
|
TurtleOverlay.ELF_MODEL,
|
||||||
"block/turtle_elf_overlay",
|
TurtleBlockEntityRenderer.COLOUR_TURTLE_MODEL,
|
||||||
"block/turtle_rainbow_overlay",
|
|
||||||
"block/turtle_trans_overlay",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void registerExtraModels(Consumer<ResourceLocation> register) {
|
public static void registerExtraModels(Consumer<ResourceLocation> register, Collection<ResourceLocation> extraModels) {
|
||||||
for (var model : EXTRA_MODELS) register.accept(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, model));
|
for (var model : EXTRA_MODELS) register.accept(model);
|
||||||
|
extraModels.forEach(register);
|
||||||
TurtleUpgradeModellers.getDependencies().forEach(register);
|
TurtleUpgradeModellers.getDependencies().forEach(register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,6 @@ package dan200.computercraft.client.gui;
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.client.render.ComputerBorderRenderer;
|
import dan200.computercraft.client.render.ComputerBorderRenderer;
|
||||||
import dan200.computercraft.data.client.ClientDataProviders;
|
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||||
import net.minecraft.client.renderer.texture.TextureManager;
|
import net.minecraft.client.renderer.texture.TextureManager;
|
||||||
@@ -113,7 +112,6 @@ public final class GuiSprites extends TextureAtlasHolder {
|
|||||||
* @param pocketBottom The texture for the bottom of a pocket computer.
|
* @param pocketBottom The texture for the bottom of a pocket computer.
|
||||||
* @param sidebar The texture for the computer sidebar.
|
* @param sidebar The texture for the computer sidebar.
|
||||||
* @see ComputerBorderRenderer
|
* @see ComputerBorderRenderer
|
||||||
* @see ClientDataProviders
|
|
||||||
*/
|
*/
|
||||||
public record ComputerTextures(
|
public record ComputerTextures(
|
||||||
ResourceLocation border,
|
ResourceLocation border,
|
||||||
|
@@ -6,15 +6,19 @@ package dan200.computercraft.client.gui;
|
|||||||
|
|
||||||
import dan200.computercraft.core.terminal.TextBuffer;
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.common.HeldItemMenu;
|
import dan200.computercraft.shared.media.PrintoutMenu;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.inventory.ContainerListener;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
||||||
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
||||||
|
|
||||||
@@ -23,41 +27,65 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA
|
|||||||
*
|
*
|
||||||
* @see dan200.computercraft.client.render.PrintoutRenderer
|
* @see dan200.computercraft.client.render.PrintoutRenderer
|
||||||
*/
|
*/
|
||||||
public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu> implements ContainerListener {
|
||||||
private final boolean book;
|
private PrintoutInfo printout = PrintoutInfo.DEFAULT;
|
||||||
private final int pages;
|
private int page = 0;
|
||||||
private final TextBuffer[] text;
|
|
||||||
private final TextBuffer[] colours;
|
|
||||||
private int page;
|
|
||||||
|
|
||||||
public PrintoutScreen(HeldItemMenu container, Inventory player, Component title) {
|
public PrintoutScreen(PrintoutMenu container, Inventory player, Component title) {
|
||||||
super(container, player, title);
|
super(container, player, title);
|
||||||
|
|
||||||
imageHeight = Y_SIZE;
|
imageHeight = Y_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
var printout = container.getStack().getOrDefault(ModRegistry.DataComponents.PRINTOUT.get(), PrintoutData.EMPTY);
|
private void setPrintout(ItemStack stack) {
|
||||||
this.text = new TextBuffer[printout.lines().size()];
|
|
||||||
this.colours = new TextBuffer[printout.lines().size()];
|
|
||||||
for (var i = 0; i < this.text.length; i++) {
|
|
||||||
var line = printout.lines().get(i);
|
|
||||||
this.text[i] = new TextBuffer(line.text());
|
|
||||||
this.colours[i] = new TextBuffer(line.foreground());
|
|
||||||
}
|
|
||||||
|
|
||||||
page = 0;
|
page = 0;
|
||||||
pages = Math.max(this.text.length / PrintoutData.LINES_PER_PAGE, 1);
|
printout = PrintoutInfo.of(PrintoutData.getOrEmpty(stack), stack.is(ModRegistry.Items.PRINTED_BOOK.get()));
|
||||||
book = ((PrintoutItem) container.getStack().getItem()).getType() == PrintoutItem.Type.BOOK;
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
super.init();
|
||||||
|
menu.addSlotListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removed() {
|
||||||
|
menu.removeSlotListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void slotChanged(AbstractContainerMenu menu, int slot, ItemStack stack) {
|
||||||
|
if (slot == 0) setPrintout(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void dataChanged(AbstractContainerMenu menu, int slot, int data) {
|
||||||
|
if (slot == PrintoutMenu.DATA_CURRENT_PAGE) page = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPage(int page) {
|
||||||
|
this.page = page;
|
||||||
|
|
||||||
|
var gameMode = Objects.requireNonNull(Objects.requireNonNull(minecraft).gameMode);
|
||||||
|
gameMode.handleInventoryButtonClick(menu.containerId, PrintoutMenu.PAGE_BUTTON_OFFSET + page);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void previousPage() {
|
||||||
|
if (page > 0) setPage(page - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void nextPage() {
|
||||||
|
if (page < printout.pages() - 1) setPage(page + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
public boolean keyPressed(int key, int scancode, int modifiers) {
|
||||||
if (key == GLFW.GLFW_KEY_RIGHT) {
|
if (key == GLFW.GLFW_KEY_RIGHT) {
|
||||||
if (page < pages - 1) page++;
|
nextPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key == GLFW.GLFW_KEY_LEFT) {
|
if (key == GLFW.GLFW_KEY_LEFT) {
|
||||||
if (page > 0) page--;
|
previousPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,13 +97,13 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
|||||||
if (super.mouseScrolled(x, y, deltaX, deltaY)) return true;
|
if (super.mouseScrolled(x, y, deltaX, deltaY)) return true;
|
||||||
if (deltaY < 0) {
|
if (deltaY < 0) {
|
||||||
// Scroll up goes to the next page
|
// Scroll up goes to the next page
|
||||||
if (page < pages - 1) page++;
|
nextPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deltaY > 0) {
|
if (deltaY > 0) {
|
||||||
// Scroll down goes to the previous page
|
// Scroll down goes to the previous page
|
||||||
if (page > 0) page--;
|
previousPage();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,8 +116,8 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
|||||||
graphics.pose().pushPose();
|
graphics.pose().pushPose();
|
||||||
graphics.pose().translate(0, 0, 1);
|
graphics.pose().translate(0, 0, 1);
|
||||||
|
|
||||||
drawBorder(graphics.pose(), graphics.bufferSource(), leftPos, topPos, 0, page, pages, book, FULL_BRIGHT_LIGHTMAP);
|
drawBorder(graphics.pose(), graphics.bufferSource(), leftPos, topPos, 0, page, printout.pages(), printout.book(), FULL_BRIGHT_LIGHTMAP);
|
||||||
drawText(graphics.pose(), graphics.bufferSource(), leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours);
|
drawText(graphics.pose(), graphics.bufferSource(), leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, printout.text(), printout.colour());
|
||||||
|
|
||||||
graphics.pose().popPose();
|
graphics.pose().popPose();
|
||||||
}
|
}
|
||||||
@@ -98,4 +126,21 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
|||||||
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
|
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
|
||||||
// Skip rendering labels.
|
// Skip rendering labels.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record PrintoutInfo(int pages, boolean book, TextBuffer[] text, TextBuffer[] colour) {
|
||||||
|
public static final PrintoutInfo DEFAULT = of(PrintoutData.EMPTY, false);
|
||||||
|
|
||||||
|
public static PrintoutInfo of(PrintoutData printout, boolean book) {
|
||||||
|
var text = new TextBuffer[printout.lines().size()];
|
||||||
|
var colours = new TextBuffer[printout.lines().size()];
|
||||||
|
for (var i = 0; i < text.length; i++) {
|
||||||
|
var line = printout.lines().get(i);
|
||||||
|
text[i] = new TextBuffer(line.text());
|
||||||
|
colours[i] = new TextBuffer(line.foreground());
|
||||||
|
}
|
||||||
|
|
||||||
|
var pages = Math.max(text.length / PrintoutData.LINES_PER_PAGE, 1);
|
||||||
|
return new PrintoutInfo(pages, book, text, colours);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,9 +8,10 @@ import com.google.auto.service.AutoService;
|
|||||||
import com.mojang.blaze3d.vertex.VertexFormat;
|
import com.mojang.blaze3d.vertex.VertexFormat;
|
||||||
import dan200.computercraft.client.render.RenderTypes;
|
import dan200.computercraft.client.render.RenderTypes;
|
||||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import net.irisshaders.iris.api.v0.IrisApi;
|
import net.irisshaders.iris.api.v0.IrisApi;
|
||||||
import net.irisshaders.iris.api.v0.IrisTextVertexSink;
|
import net.irisshaders.iris.api.v0.IrisTextVertexSink;
|
||||||
|
import net.minecraft.util.FastColor;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -20,7 +21,7 @@ import java.util.function.IntFunction;
|
|||||||
public class IrisShaderMod implements ShaderMod.Provider {
|
public class IrisShaderMod implements ShaderMod.Provider {
|
||||||
@Override
|
@Override
|
||||||
public Optional<ShaderMod> get() {
|
public Optional<ShaderMod> get() {
|
||||||
return FabricLoader.getInstance().isModLoaded("iris") ? Optional.of(new Impl()) : Optional.empty();
|
return PlatformHelper.get().isModLoaded("iris") ? Optional.of(new Impl()) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Impl extends ShaderMod {
|
private static final class Impl extends ShaderMod {
|
||||||
@@ -54,12 +55,8 @@ public class IrisShaderMod implements ShaderMod.Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void quad(float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2) {
|
public void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
|
||||||
sink.quad(x1, y1, x2, y2, z, pack(rgba[0], rgba[1], rgba[2], rgba[3]), u1, v1, u2, v2, RenderTypes.FULL_BRIGHT_LIGHTMAP);
|
sink.quad(x1, y1, x2, y2, z, FastColor.ABGR32.fromArgb32(colour), u1, v1, u2, v2, RenderTypes.FULL_BRIGHT_LIGHTMAP);
|
||||||
}
|
|
||||||
|
|
||||||
private static int pack(int r, int g, int b, int a) {
|
|
||||||
return (a & 255) << 24 | (b & 255) << 16 | (g & 255) << 8 | r & 255;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,68 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.client.model;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import com.mojang.serialization.JsonOps;
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.packs.resources.ResourceManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of extra models to load on the client.
|
||||||
|
* <p>
|
||||||
|
* This is largely intended for use with {@linkplain TurtleOverlay turtle overlays}. As overlays are stored in a dynamic
|
||||||
|
* registry, they are not available when resources are loaded, and so we need a way to request the overlays' models be
|
||||||
|
* loaded.
|
||||||
|
*
|
||||||
|
* @param models The models to load.
|
||||||
|
*/
|
||||||
|
public record ExtraModels(List<ResourceLocation> models) {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(ExtraModels.class);
|
||||||
|
private static final Gson GSON = new Gson();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path where the extra models are listed.
|
||||||
|
*/
|
||||||
|
public static final ResourceLocation PATH = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "extra_models.json");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The coded used to store the extra model file.
|
||||||
|
*/
|
||||||
|
public static final Codec<ExtraModels> CODEC = ResourceLocation.CODEC.listOf().xmap(ExtraModels::new, ExtraModels::models);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of all extra models to load.
|
||||||
|
*
|
||||||
|
* @param resources The current resource manager.
|
||||||
|
* @return A set of all resources to load.
|
||||||
|
*/
|
||||||
|
public static Collection<ResourceLocation> loadAll(ResourceManager resources) {
|
||||||
|
Set<ResourceLocation> out = new HashSet<>();
|
||||||
|
|
||||||
|
for (var path : resources.getResourceStack(PATH)) {
|
||||||
|
ExtraModels models;
|
||||||
|
try (var stream = path.openAsReader()) {
|
||||||
|
models = ExtraModels.CODEC.parse(JsonOps.INSTANCE, GSON.fromJson(stream, JsonElement.class)).getOrThrow(JsonParseException::new);
|
||||||
|
} catch (IOException | RuntimeException e) {
|
||||||
|
LOG.error("Failed to load extra models from {}", path.sourcePackId());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.addAll(models.models());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Collections.unmodifiableCollection(out);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,117 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.client.model;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||||
|
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||||
|
import net.minecraft.client.model.geom.ModelPart;
|
||||||
|
import net.minecraft.client.model.geom.PartPose;
|
||||||
|
import net.minecraft.client.model.geom.builders.CubeListBuilder;
|
||||||
|
import net.minecraft.client.model.geom.builders.MeshDefinition;
|
||||||
|
import net.minecraft.client.resources.model.Material;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.inventory.InventoryMenu;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A model for {@linkplain PrintoutItem printouts} placed on a lectern.
|
||||||
|
* <p>
|
||||||
|
* This provides two models, {@linkplain #renderPages(PoseStack, VertexConsumer, int, int, int) one for a variable
|
||||||
|
* number of pages}, and {@linkplain #renderBook(PoseStack, VertexConsumer, int, int) one for books}.
|
||||||
|
*
|
||||||
|
* @see CustomLecternRenderer
|
||||||
|
*/
|
||||||
|
public class LecternPrintoutModel {
|
||||||
|
public static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/printout");
|
||||||
|
public static final Material MATERIAL = new Material(InventoryMenu.BLOCK_ATLAS, TEXTURE);
|
||||||
|
|
||||||
|
private static final int TEXTURE_WIDTH = 32;
|
||||||
|
private static final int TEXTURE_HEIGHT = 32;
|
||||||
|
|
||||||
|
private static final String PAGE_1 = "page_1";
|
||||||
|
private static final String PAGE_2 = "page_2";
|
||||||
|
private static final String PAGE_3 = "page_3";
|
||||||
|
private static final List<String> PAGES = List.of(PAGE_1, PAGE_2, PAGE_3);
|
||||||
|
|
||||||
|
private final ModelPart pagesRoot;
|
||||||
|
private final ModelPart bookRoot;
|
||||||
|
private final ModelPart[] pages;
|
||||||
|
|
||||||
|
public LecternPrintoutModel() {
|
||||||
|
pagesRoot = buildPages();
|
||||||
|
bookRoot = buildBook();
|
||||||
|
pages = PAGES.stream().map(pagesRoot::getChild).toArray(ModelPart[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModelPart buildPages() {
|
||||||
|
var mesh = new MeshDefinition();
|
||||||
|
var parts = mesh.getRoot();
|
||||||
|
parts.addOrReplaceChild(
|
||||||
|
PAGE_1,
|
||||||
|
CubeListBuilder.create().texOffs(0, 0).addBox(-0.005f, -4.0f, -2.5f, 1f, 8.0f, 5.0f),
|
||||||
|
PartPose.ZERO
|
||||||
|
);
|
||||||
|
|
||||||
|
parts.addOrReplaceChild(
|
||||||
|
PAGE_2,
|
||||||
|
CubeListBuilder.create().texOffs(12, 0).addBox(-0.005f, -4.0f, -2.5f, 1f, 8.0f, 5.0f),
|
||||||
|
PartPose.offsetAndRotation(-0.125f, 0, 1.5f, (float) Math.PI * (1f / 16), 0, 0)
|
||||||
|
);
|
||||||
|
parts.addOrReplaceChild(
|
||||||
|
PAGE_3,
|
||||||
|
CubeListBuilder.create().texOffs(12, 0).addBox(-0.005f, -4.0f, -2.5f, 1f, 8.0f, 5.0f),
|
||||||
|
PartPose.offsetAndRotation(-0.25f, 0, -1.5f, (float) -Math.PI * (2f / 16), 0, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ModelPart buildBook() {
|
||||||
|
var mesh = new MeshDefinition();
|
||||||
|
var parts = mesh.getRoot();
|
||||||
|
|
||||||
|
parts.addOrReplaceChild(
|
||||||
|
"spine",
|
||||||
|
CubeListBuilder.create().texOffs(12, 15).addBox(-0.005f, -5.0f, -0.5f, 0, 10, 1.0f),
|
||||||
|
PartPose.ZERO
|
||||||
|
);
|
||||||
|
|
||||||
|
var angle = (float) Math.toRadians(5);
|
||||||
|
parts.addOrReplaceChild(
|
||||||
|
"left",
|
||||||
|
CubeListBuilder.create()
|
||||||
|
.texOffs(0, 10).addBox(0, -5.0f, -6.0f, 0, 10, 6.0f)
|
||||||
|
.texOffs(0, 0).addBox(0.005f, -4.0f, -5.0f, 1.0f, 8.0f, 5.0f),
|
||||||
|
PartPose.offsetAndRotation(-0.005f, 0, -0.5f, 0, -angle, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
parts.addOrReplaceChild(
|
||||||
|
"right",
|
||||||
|
CubeListBuilder.create()
|
||||||
|
.texOffs(14, 10).addBox(0, -5.0f, 0, 0, 10, 6.0f)
|
||||||
|
.texOffs(0, 0).addBox(0.005f, -4.0f, 0, 1.0f, 8.0f, 5.0f),
|
||||||
|
PartPose.offsetAndRotation(-0.005f, 0, 0.5f, 0, angle, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderBook(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay) {
|
||||||
|
bookRoot.render(poseStack, buffer, packedLight, packedOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void renderPages(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int pageCount) {
|
||||||
|
if (pageCount > pages.length) pageCount = pages.length;
|
||||||
|
var i = 0;
|
||||||
|
for (; i < pageCount; i++) pages[i].visible = true;
|
||||||
|
for (; i < pages.length; i++) pages[i].visible = false;
|
||||||
|
|
||||||
|
pagesRoot.render(poseStack, buffer, packedLight, packedOverlay);
|
||||||
|
}
|
||||||
|
}
|
@@ -12,13 +12,14 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
|||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
|
||||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||||
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||||
import dan200.computercraft.shared.util.Holiday;
|
import dan200.computercraft.shared.util.Holiday;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
|
import net.minecraft.client.resources.model.ModelManager;
|
||||||
import net.minecraft.core.component.DataComponents;
|
import net.minecraft.core.component.DataComponents;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@@ -52,7 +53,7 @@ public final class TurtleModelParts<T> {
|
|||||||
boolean colour,
|
boolean colour,
|
||||||
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade,
|
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade,
|
||||||
@Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
|
@Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
|
||||||
@Nullable ResourceLocation overlay,
|
@Nullable TurtleOverlay overlay,
|
||||||
boolean christmas,
|
boolean christmas,
|
||||||
boolean flip
|
boolean flip
|
||||||
) {
|
) {
|
||||||
@@ -113,10 +114,10 @@ public final class TurtleModelParts<T> {
|
|||||||
var parts = new ArrayList<BakedModel>(4);
|
var parts = new ArrayList<BakedModel>(4);
|
||||||
parts.add(transform(combo.colour() ? colourModel : familyModel, transformation));
|
parts.add(transform(combo.colour() ? colourModel : familyModel, transformation));
|
||||||
|
|
||||||
var overlayModelLocation = TurtleBlockEntityRenderer.getTurtleOverlayModel(combo.overlay(), combo.christmas());
|
if (combo.overlay() != null) addPart(parts, modelManager, transformation, combo.overlay().model());
|
||||||
if (overlayModelLocation != null) {
|
|
||||||
parts.add(transform(ClientPlatformHelper.get().getModel(modelManager, overlayModelLocation), transformation));
|
var showChristmas = TurtleOverlay.showElfOverlay(combo.overlay(), combo.christmas());
|
||||||
}
|
if (showChristmas) addPart(parts, modelManager, transformation, TurtleOverlay.ELF_MODEL);
|
||||||
|
|
||||||
addUpgrade(parts, transformation, TurtleSide.LEFT, combo.leftUpgrade());
|
addUpgrade(parts, transformation, TurtleSide.LEFT, combo.leftUpgrade());
|
||||||
addUpgrade(parts, transformation, TurtleSide.RIGHT, combo.rightUpgrade());
|
addUpgrade(parts, transformation, TurtleSide.RIGHT, combo.rightUpgrade());
|
||||||
@@ -124,6 +125,10 @@ public final class TurtleModelParts<T> {
|
|||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addPart(List<BakedModel> parts, ModelManager modelManager, Transformation transformation, ResourceLocation model) {
|
||||||
|
parts.add(transform(ClientPlatformHelper.get().getModel(modelManager, model), transformation));
|
||||||
|
}
|
||||||
|
|
||||||
private void addUpgrade(List<BakedModel> parts, Transformation transformation, TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
private void addUpgrade(List<BakedModel> parts, Transformation transformation, TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
if (upgrade == null) return;
|
if (upgrade == null) return;
|
||||||
var model = TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side);
|
var model = TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side);
|
||||||
|
@@ -0,0 +1,52 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.client.render;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.math.Axis;
|
||||||
|
import dan200.computercraft.client.model.LecternPrintoutModel;
|
||||||
|
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
|
||||||
|
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||||
|
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||||
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.client.renderer.RenderType;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||||
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
|
import net.minecraft.client.renderer.blockentity.LecternRenderer;
|
||||||
|
import net.minecraft.world.level.block.LecternBlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block entity renderer for our {@linkplain CustomLecternBlockEntity lectern}.
|
||||||
|
* <p>
|
||||||
|
* This largely follows {@link LecternRenderer}, but with support for multiple types of item.
|
||||||
|
*/
|
||||||
|
public class CustomLecternRenderer implements BlockEntityRenderer<CustomLecternBlockEntity> {
|
||||||
|
private final LecternPrintoutModel printoutModel;
|
||||||
|
|
||||||
|
public CustomLecternRenderer(BlockEntityRendererProvider.Context context) {
|
||||||
|
printoutModel = new LecternPrintoutModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(CustomLecternBlockEntity lectern, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) {
|
||||||
|
poseStack.pushPose();
|
||||||
|
poseStack.translate(0.5f, 1.0625f, 0.5f);
|
||||||
|
poseStack.mulPose(Axis.YP.rotationDegrees(-lectern.getBlockState().getValue(LecternBlock.FACING).getClockWise().toYRot()));
|
||||||
|
poseStack.mulPose(Axis.ZP.rotationDegrees(67.5f));
|
||||||
|
poseStack.translate(0, -0.125f, 0);
|
||||||
|
|
||||||
|
var item = lectern.getItem();
|
||||||
|
if (item.getItem() instanceof PrintoutItem printout) {
|
||||||
|
var vertexConsumer = LecternPrintoutModel.MATERIAL.buffer(buffer, RenderType::entitySolid);
|
||||||
|
if (printout.getType() == PrintoutItem.Type.BOOK) {
|
||||||
|
printoutModel.renderBook(poseStack, vertexConsumer, packedLight, packedOverlay);
|
||||||
|
} else {
|
||||||
|
printoutModel.renderPages(poseStack, vertexConsumer, packedLight, packedOverlay, PrintoutData.getOrEmpty(item).pages());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
poseStack.popPose();
|
||||||
|
}
|
||||||
|
}
|
@@ -14,6 +14,7 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
|
|||||||
import dan200.computercraft.shared.config.Config;
|
import dan200.computercraft.shared.config.Config;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
|
import net.minecraft.util.FastColor;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
@@ -93,16 +94,11 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void renderLight(PoseStack transform, MultiBufferSource render, int colour, int width, int height) {
|
private static void renderLight(PoseStack transform, MultiBufferSource render, int colour, int width, int height) {
|
||||||
var r = (byte) ((colour >>> 16) & 0xFF);
|
|
||||||
var g = (byte) ((colour >>> 8) & 0xFF);
|
|
||||||
var b = (byte) (colour & 0xFF);
|
|
||||||
var c = new byte[]{ r, g, b, (byte) 255 };
|
|
||||||
|
|
||||||
var buffer = render.getBuffer(RenderTypes.TERMINAL);
|
var buffer = render.getBuffer(RenderTypes.TERMINAL);
|
||||||
FixedWidthFontRenderer.drawQuad(
|
FixedWidthFontRenderer.drawQuad(
|
||||||
FixedWidthFontRenderer.toVertexConsumer(transform, buffer),
|
FixedWidthFontRenderer.toVertexConsumer(transform, buffer),
|
||||||
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
|
width - LIGHT_HEIGHT * 2, height + BORDER / 2.0f, 0.001f, LIGHT_HEIGHT * 2, LIGHT_HEIGHT,
|
||||||
c, RenderTypes.FULL_BRIGHT_LIGHTMAP
|
FastColor.ARGB32.opaque(colour), RenderTypes.FULL_BRIGHT_LIGHTMAP
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,6 +11,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
|||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||||
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||||
import dan200.computercraft.shared.util.Holiday;
|
import dan200.computercraft.shared.util.Holiday;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
@@ -21,14 +22,15 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
|||||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||||
import net.minecraft.client.resources.model.BakedModel;
|
import net.minecraft.client.resources.model.BakedModel;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.CommonColors;
|
||||||
|
import net.minecraft.util.FastColor;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.HitResult;
|
import net.minecraft.world.phys.HitResult;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
||||||
private static final ResourceLocation COLOUR_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
|
public static final ResourceLocation COLOUR_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
|
||||||
private static final ResourceLocation ELF_OVERLAY_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_elf_overlay");
|
|
||||||
|
|
||||||
private final BlockEntityRenderDispatcher renderer;
|
private final BlockEntityRenderDispatcher renderer;
|
||||||
private final Font font;
|
private final Font font;
|
||||||
@@ -38,12 +40,6 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
|||||||
font = context.getFont();
|
font = context.getFont();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable ResourceLocation getTurtleOverlayModel(@Nullable ResourceLocation overlay, boolean christmas) {
|
|
||||||
if (overlay != null) return overlay;
|
|
||||||
if (christmas) return ELF_OVERLAY_MODEL;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight) {
|
public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight) {
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
@@ -62,13 +58,13 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
|||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
transform.translate(0.5, 1.2, 0.5);
|
transform.translate(0.5, 1.2, 0.5);
|
||||||
transform.mulPose(mc.getEntityRenderDispatcher().cameraOrientation());
|
transform.mulPose(mc.getEntityRenderDispatcher().cameraOrientation());
|
||||||
transform.scale(-0.025f, -0.025f, 0.025f);
|
transform.scale(0.025f, -0.025f, 0.025f);
|
||||||
|
|
||||||
var matrix = transform.last().pose();
|
var matrix = transform.last().pose();
|
||||||
var opacity = (int) (mc.options.getBackgroundOpacity(0.25f) * 255) << 24;
|
var opacity = (int) (mc.options.getBackgroundOpacity(0.25f) * 255) << 24;
|
||||||
var width = -font.width(label) / 2.0f;
|
var width = -font.width(label) / 2.0f;
|
||||||
font.drawInBatch(label, width, (float) 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
|
font.drawInBatch(label, width, (float) 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
|
||||||
font.drawInBatch(label, width, (float) 0, 0xffffffff, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
font.drawInBatch(label, width, (float) 0, CommonColors.WHITE, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
@@ -94,14 +90,15 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
|||||||
renderModel(transform, buffers, lightmapCoord, overlayLight, model, null);
|
renderModel(transform, buffers, lightmapCoord, overlayLight, model, null);
|
||||||
} else {
|
} else {
|
||||||
// Otherwise render it using the colour item.
|
// Otherwise render it using the colour item.
|
||||||
renderModel(transform, buffers, lightmapCoord, overlayLight, COLOUR_TURTLE_MODEL, new int[]{ colour });
|
renderModel(transform, buffers, lightmapCoord, overlayLight, COLOUR_TURTLE_MODEL, new int[]{ FastColor.ARGB32.opaque(colour) });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the overlay
|
// Render the overlay
|
||||||
var overlayModel = getTurtleOverlayModel(overlay, Holiday.getCurrent() == Holiday.CHRISTMAS);
|
if (overlay != null) renderModel(transform, buffers, lightmapCoord, overlayLight, overlay.model(), null);
|
||||||
if (overlayModel != null) {
|
|
||||||
renderModel(transform, buffers, lightmapCoord, overlayLight, overlayModel, null);
|
// And the Christmas overlay.
|
||||||
}
|
var showChristmas = TurtleOverlay.showElfOverlay(overlay, Holiday.getCurrent() == Holiday.CHRISTMAS);
|
||||||
|
if (showChristmas) renderModel(transform, buffers, lightmapCoord, overlayLight, TurtleOverlay.ELF_MODEL, null);
|
||||||
|
|
||||||
// Render the upgrades
|
// Render the upgrades
|
||||||
renderUpgrade(transform, buffers, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks);
|
renderUpgrade(transform, buffers, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks);
|
||||||
|
@@ -178,7 +178,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
var size = DirectFixedWidthFontRenderer.getVertexCount(terminal);
|
var size = DirectFixedWidthFontRenderer.getVertexCount(terminal);
|
||||||
|
|
||||||
// In an ideal world we could upload these both into one buffer. However, we can't render VBOs with
|
// In an ideal world we could upload these both into one buffer. However, we can't render VBOs with
|
||||||
// and starting and ending offset, and so need to use two buffers instead.
|
// a starting and ending offset, and so need to use two buffers instead.
|
||||||
|
|
||||||
renderToBuffer(backgroundBuffer, size, sink ->
|
renderToBuffer(backgroundBuffer, size, sink ->
|
||||||
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
|
DirectFixedWidthFontRenderer.drawTerminalBackground(sink, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin));
|
||||||
@@ -216,10 +216,10 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
foregroundBuffer.bind();
|
foregroundBuffer.bind();
|
||||||
foregroundBuffer.drawWithShader(
|
foregroundBuffer.drawWithShader(
|
||||||
modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(),
|
modelView, RenderSystem.getProjectionMatrix(), RenderTypes.getTerminalShader(),
|
||||||
// As mentioned in the above comment, render the extra cursor quad if it is visible this frame. Each
|
// Skip the cursor quad if it is not visible this frame.
|
||||||
// // quad has an index count of 6.
|
FixedWidthFontRenderer.isCursorVisible(terminal) && !FrameInfo.getGlobalCursorBlink()
|
||||||
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
|
? foregroundBuffer.getIndexCount() - RenderTypes.TERMINAL.mode().indexCount(4)
|
||||||
? foregroundBuffer.getIndexCount() + 6 : foregroundBuffer.getIndexCount()
|
: foregroundBuffer.getIndexCount()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Clear state
|
// Clear state
|
||||||
|
@@ -12,9 +12,11 @@ import dan200.computercraft.core.terminal.Palette;
|
|||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.core.terminal.TextBuffer;
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
|
import net.minecraft.util.FastColor;
|
||||||
import org.lwjgl.system.MemoryUtil;
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.*;
|
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.*;
|
||||||
import static org.lwjgl.system.MemoryUtil.*;
|
import static org.lwjgl.system.MemoryUtil.*;
|
||||||
@@ -37,10 +39,12 @@ import static org.lwjgl.system.MemoryUtil.*;
|
|||||||
* {@link FixedWidthFontRenderer}.
|
* {@link FixedWidthFontRenderer}.
|
||||||
*/
|
*/
|
||||||
public final class DirectFixedWidthFontRenderer {
|
public final class DirectFixedWidthFontRenderer {
|
||||||
|
private static final boolean IS_LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
|
||||||
|
|
||||||
private DirectFixedWidthFontRenderer() {
|
private DirectFixedWidthFontRenderer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawChar(QuadEmitter emitter, float x, float y, int index, byte[] colour) {
|
private static void drawChar(QuadEmitter emitter, float x, float y, int index, int colour) {
|
||||||
// Short circuit to avoid the common case - the texture should be blank here after all.
|
// Short circuit to avoid the common case - the texture should be blank here after all.
|
||||||
if (index == '\0' || index == ' ') return;
|
if (index == '\0' || index == ' ') return;
|
||||||
|
|
||||||
@@ -157,8 +161,8 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
return (terminal.getHeight() + 2) * (terminal.getWidth() + 2) * 2;
|
return (terminal.getHeight() + 2) * (terminal.getWidth() + 2) * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void quad(QuadEmitter buffer, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2) {
|
private static void quad(QuadEmitter buffer, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
|
||||||
buffer.quad(x1, y1, x2, y2, z, rgba, u1, v1, u2, v2);
|
buffer.quad(x1, y1, x2, y2, z, colour, u1, v1, u2, v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface QuadEmitter {
|
public interface QuadEmitter {
|
||||||
@@ -166,7 +170,7 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
|
|
||||||
ByteBuffer buffer();
|
ByteBuffer buffer();
|
||||||
|
|
||||||
void quad(float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2);
|
void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ByteBufferEmitter(ByteBuffer buffer) implements QuadEmitter {
|
public record ByteBufferEmitter(ByteBuffer buffer) implements QuadEmitter {
|
||||||
@@ -176,12 +180,12 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void quad(float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2) {
|
public void quad(float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
|
||||||
DirectFixedWidthFontRenderer.quad(buffer, x1, y1, x2, y2, z, rgba, u1, v1, u2, v2);
|
DirectFixedWidthFontRenderer.quad(buffer, x1, y1, x2, y2, z, colour, u1, v1, u2, v2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quad(ByteBuffer buffer, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2) {
|
static void quad(ByteBuffer buffer, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2) {
|
||||||
// Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the
|
// Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the
|
||||||
// underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write.
|
// underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write.
|
||||||
// This provides significant performance gains, at the cost of well, using Unsafe.
|
// This provides significant performance gains, at the cost of well, using Unsafe.
|
||||||
@@ -195,16 +199,15 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
if (position < 0 || 112 > buffer.limit() - position) throw new IndexOutOfBoundsException();
|
if (position < 0 || 112 > buffer.limit() - position) throw new IndexOutOfBoundsException();
|
||||||
// Require the pointer to be aligned to a 32-bit boundary.
|
// Require the pointer to be aligned to a 32-bit boundary.
|
||||||
if ((addr & 3) != 0) throw new IllegalStateException("Memory is not aligned");
|
if ((addr & 3) != 0) throw new IllegalStateException("Memory is not aligned");
|
||||||
// Also assert the length of the array. This appears to help elide bounds checks on the array in some circumstances.
|
|
||||||
if (rgba.length != 4) throw new IllegalStateException();
|
// Pack colour so it is equivalent to rgba:BBBB. This matches the logic in BufferBuilder.
|
||||||
|
var colourAbgr = FastColor.ABGR32.fromArgb32(colour);
|
||||||
|
var nativeColour = IS_LITTLE_ENDIAN ? colourAbgr : Integer.reverseBytes(colourAbgr);
|
||||||
|
|
||||||
memPutFloat(addr + 0, x1);
|
memPutFloat(addr + 0, x1);
|
||||||
memPutFloat(addr + 4, y1);
|
memPutFloat(addr + 4, y1);
|
||||||
memPutFloat(addr + 8, z);
|
memPutFloat(addr + 8, z);
|
||||||
memPutByte(addr + 12, rgba[0]);
|
memPutInt(addr + 12, nativeColour);
|
||||||
memPutByte(addr + 13, rgba[1]);
|
|
||||||
memPutByte(addr + 14, rgba[2]);
|
|
||||||
memPutByte(addr + 15, (byte) 255);
|
|
||||||
memPutFloat(addr + 16, u1);
|
memPutFloat(addr + 16, u1);
|
||||||
memPutFloat(addr + 20, v1);
|
memPutFloat(addr + 20, v1);
|
||||||
memPutShort(addr + 24, (short) 0xF0);
|
memPutShort(addr + 24, (short) 0xF0);
|
||||||
@@ -213,10 +216,7 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
memPutFloat(addr + 28, x1);
|
memPutFloat(addr + 28, x1);
|
||||||
memPutFloat(addr + 32, y2);
|
memPutFloat(addr + 32, y2);
|
||||||
memPutFloat(addr + 36, z);
|
memPutFloat(addr + 36, z);
|
||||||
memPutByte(addr + 40, rgba[0]);
|
memPutInt(addr + 40, nativeColour);
|
||||||
memPutByte(addr + 41, rgba[1]);
|
|
||||||
memPutByte(addr + 42, rgba[2]);
|
|
||||||
memPutByte(addr + 43, (byte) 255);
|
|
||||||
memPutFloat(addr + 44, u1);
|
memPutFloat(addr + 44, u1);
|
||||||
memPutFloat(addr + 48, v2);
|
memPutFloat(addr + 48, v2);
|
||||||
memPutShort(addr + 52, (short) 0xF0);
|
memPutShort(addr + 52, (short) 0xF0);
|
||||||
@@ -225,10 +225,7 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
memPutFloat(addr + 56, x2);
|
memPutFloat(addr + 56, x2);
|
||||||
memPutFloat(addr + 60, y2);
|
memPutFloat(addr + 60, y2);
|
||||||
memPutFloat(addr + 64, z);
|
memPutFloat(addr + 64, z);
|
||||||
memPutByte(addr + 68, rgba[0]);
|
memPutInt(addr + 68, nativeColour);
|
||||||
memPutByte(addr + 69, rgba[1]);
|
|
||||||
memPutByte(addr + 70, rgba[2]);
|
|
||||||
memPutByte(addr + 71, (byte) 255);
|
|
||||||
memPutFloat(addr + 72, u2);
|
memPutFloat(addr + 72, u2);
|
||||||
memPutFloat(addr + 76, v2);
|
memPutFloat(addr + 76, v2);
|
||||||
memPutShort(addr + 80, (short) 0xF0);
|
memPutShort(addr + 80, (short) 0xF0);
|
||||||
@@ -237,10 +234,7 @@ public final class DirectFixedWidthFontRenderer {
|
|||||||
memPutFloat(addr + 84, x2);
|
memPutFloat(addr + 84, x2);
|
||||||
memPutFloat(addr + 88, y1);
|
memPutFloat(addr + 88, y1);
|
||||||
memPutFloat(addr + 92, z);
|
memPutFloat(addr + 92, z);
|
||||||
memPutByte(addr + 96, rgba[0]);
|
memPutInt(addr + 96, nativeColour);
|
||||||
memPutByte(addr + 97, rgba[1]);
|
|
||||||
memPutByte(addr + 98, rgba[2]);
|
|
||||||
memPutByte(addr + 99, (byte) 255);
|
|
||||||
memPutFloat(addr + 100, u2);
|
memPutFloat(addr + 100, u2);
|
||||||
memPutFloat(addr + 104, v1);
|
memPutFloat(addr + 104, v1);
|
||||||
memPutShort(addr + 108, (short) 0xF0);
|
memPutShort(addr + 108, (short) 0xF0);
|
||||||
|
@@ -12,6 +12,7 @@ import dan200.computercraft.core.terminal.Terminal;
|
|||||||
import dan200.computercraft.core.terminal.TextBuffer;
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.util.FastColor;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
@@ -41,7 +42,7 @@ public final class FixedWidthFontRenderer {
|
|||||||
static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
|
static final float BACKGROUND_START = (WIDTH - 6.0f) / WIDTH;
|
||||||
static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
|
static final float BACKGROUND_END = (WIDTH - 4.0f) / WIDTH;
|
||||||
|
|
||||||
private static final byte[] BLACK = new byte[]{ byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()), (byte) 255 };
|
private static final int BLACK = FastColor.ARGB32.color(255, byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()), byteColour(Colour.BLACK.getR()));
|
||||||
private static final float Z_OFFSET = 1e-3f;
|
private static final float Z_OFFSET = 1e-3f;
|
||||||
|
|
||||||
private FixedWidthFontRenderer() {
|
private FixedWidthFontRenderer() {
|
||||||
@@ -59,7 +60,7 @@ public final class FixedWidthFontRenderer {
|
|||||||
return 15 - Terminal.getColour(c, def);
|
return 15 - Terminal.getColour(c, def);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void drawChar(QuadEmitter emitter, float x, float y, int index, byte[] colour, int light) {
|
private static void drawChar(QuadEmitter emitter, float x, float y, int index, int colour, int light) {
|
||||||
// Short circuit to avoid the common case - the texture should be blank here after all.
|
// Short circuit to avoid the common case - the texture should be blank here after all.
|
||||||
if (index == '\0' || index == ' ') return;
|
if (index == '\0' || index == ' ') return;
|
||||||
|
|
||||||
@@ -75,7 +76,7 @@ public final class FixedWidthFontRenderer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void drawQuad(QuadEmitter emitter, float x, float y, float z, float width, float height, byte[] colour, int light) {
|
public static void drawQuad(QuadEmitter emitter, float x, float y, float z, float width, float height, int colour, int light) {
|
||||||
quad(emitter, x, y, x + width, y + height, z, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, light);
|
quad(emitter, x, y, x + width, y + height, z, colour, BACKGROUND_START, BACKGROUND_START, BACKGROUND_END, BACKGROUND_END, light);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,10 +217,10 @@ public final class FixedWidthFontRenderer {
|
|||||||
return new QuadEmitter(transform.last().pose(), consumer);
|
return new QuadEmitter(transform.last().pose(), consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void quad(QuadEmitter c, float x1, float y1, float x2, float y2, float z, byte[] rgba, float u1, float v1, float u2, float v2, int light) {
|
private static void quad(QuadEmitter c, float x1, float y1, float x2, float y2, float z, int colour, float u1, float v1, float u2, float v2, int light) {
|
||||||
var poseMatrix = c.poseMatrix();
|
var poseMatrix = c.poseMatrix();
|
||||||
var consumer = c.consumer();
|
var consumer = c.consumer();
|
||||||
byte r = rgba[0], g = rgba[1], b = rgba[2], a = rgba[3];
|
int r = FastColor.ARGB32.red(colour), g = FastColor.ARGB32.green(colour), b = FastColor.ARGB32.blue(colour), a = FastColor.ARGB32.alpha(colour);
|
||||||
|
|
||||||
consumer.addVertex(poseMatrix, x1, y1, z).setColor(r, g, b, a).setUv(u1, v1).setLight(light);
|
consumer.addVertex(poseMatrix, x1, y1, z).setColor(r, g, b, a).setUv(u1, v1).setLight(light);
|
||||||
consumer.addVertex(poseMatrix, x1, y2, z).setColor(r, g, b, a).setUv(u1, v2).setLight(light);
|
consumer.addVertex(poseMatrix, x1, y2, z).setColor(r, g, b, a).setUv(u1, v2).setLight(light);
|
||||||
|
@@ -1,48 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.data.client;
|
|
||||||
|
|
||||||
import dan200.computercraft.client.gui.GuiSprites;
|
|
||||||
import dan200.computercraft.data.DataProviders;
|
|
||||||
import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
|
|
||||||
import net.minecraft.client.renderer.texture.atlas.SpriteSource;
|
|
||||||
import net.minecraft.client.renderer.texture.atlas.SpriteSources;
|
|
||||||
import net.minecraft.client.renderer.texture.atlas.sources.SingleFile;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.packs.PackType;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A version of {@link DataProviders} which relies on client-side classes.
|
|
||||||
* <p>
|
|
||||||
* This is called from {@link DataProviders#add(DataProviders.GeneratorSink)}.
|
|
||||||
*/
|
|
||||||
public final class ClientDataProviders {
|
|
||||||
private ClientDataProviders() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void add(DataProviders.GeneratorSink generator) {
|
|
||||||
generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
|
|
||||||
out.accept(ResourceLocation.withDefaultNamespace("blocks"), List.of(
|
|
||||||
new SingleFile(UpgradeSlot.LEFT_UPGRADE, Optional.empty()),
|
|
||||||
new SingleFile(UpgradeSlot.RIGHT_UPGRADE, Optional.empty())
|
|
||||||
));
|
|
||||||
out.accept(GuiSprites.SPRITE_SHEET, Stream.of(
|
|
||||||
// Buttons
|
|
||||||
GuiSprites.TURNED_OFF.textures(),
|
|
||||||
GuiSprites.TURNED_ON.textures(),
|
|
||||||
GuiSprites.TERMINATE.textures(),
|
|
||||||
// Computers
|
|
||||||
GuiSprites.COMPUTER_NORMAL.textures(),
|
|
||||||
GuiSprites.COMPUTER_ADVANCED.textures(),
|
|
||||||
GuiSprites.COMPUTER_COMMAND.textures(),
|
|
||||||
GuiSprites.COMPUTER_COLOUR.textures()
|
|
||||||
).flatMap(x -> x).<SpriteSource>map(x -> new SingleFile(x, Optional.empty())).toList());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@@ -23,6 +23,7 @@ import net.minecraft.data.models.BlockModelGenerators;
|
|||||||
import net.minecraft.data.models.blockstates.*;
|
import net.minecraft.data.models.blockstates.*;
|
||||||
import net.minecraft.data.models.model.*;
|
import net.minecraft.data.models.model.*;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
@@ -96,10 +97,17 @@ class BlockModelProvider {
|
|||||||
|
|
||||||
registerCable(generators);
|
registerCable(generators);
|
||||||
|
|
||||||
|
registerRedstoneControl(generators);
|
||||||
|
|
||||||
registerTurtleUpgrade(generators, "block/turtle_crafting_table", "block/turtle_crafty_face");
|
registerTurtleUpgrade(generators, "block/turtle_crafting_table", "block/turtle_crafty_face");
|
||||||
registerTurtleUpgrade(generators, "block/turtle_speaker", "block/turtle_speaker_face");
|
registerTurtleUpgrade(generators, "block/turtle_speaker", "block/turtle_speaker_face");
|
||||||
registerTurtleModem(generators, "block/turtle_modem_normal", "block/wireless_modem_normal_face");
|
registerTurtleModem(generators, "block/turtle_modem_normal", "block/wireless_modem_normal_face");
|
||||||
registerTurtleModem(generators, "block/turtle_modem_advanced", "block/wireless_modem_advanced_face");
|
registerTurtleModem(generators, "block/turtle_modem_advanced", "block/wireless_modem_advanced_face");
|
||||||
|
|
||||||
|
generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(
|
||||||
|
ModRegistry.Blocks.LECTERN.get(),
|
||||||
|
Variant.variant().with(VariantProperties.MODEL, ModelLocationUtils.getModelLocation(Blocks.LECTERN))
|
||||||
|
).with(createHorizontalFacingDispatch()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void registerDiskDrive(BlockModelGenerators generators) {
|
private static void registerDiskDrive(BlockModelGenerators generators) {
|
||||||
@@ -349,6 +357,18 @@ class BlockModelProvider {
|
|||||||
generators.blockStateOutput.accept(generator);
|
generators.blockStateOutput.accept(generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void registerRedstoneControl(BlockModelGenerators generators) {
|
||||||
|
var redstoneControl = ModRegistry.Blocks.REDSTONE_RELAY.get();
|
||||||
|
var model = ModelTemplates.CUBE_ORIENTABLE_TOP_BOTTOM.create(
|
||||||
|
redstoneControl, TextureMapping.orientableCube(redstoneControl), generators.modelOutput
|
||||||
|
);
|
||||||
|
generators.blockStateOutput.accept(
|
||||||
|
MultiVariantGenerator.multiVariant(redstoneControl, Variant.variant().with(VariantProperties.MODEL, model))
|
||||||
|
.with(createHorizontalFacingDispatch())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final BooleanProperty[] CABLE_DIRECTIONS = { CableBlock.DOWN, CableBlock.UP, CableBlock.NORTH, CableBlock.SOUTH, CableBlock.WEST, CableBlock.EAST };
|
private static final BooleanProperty[] CABLE_DIRECTIONS = { CableBlock.DOWN, CableBlock.UP, CableBlock.NORTH, CableBlock.SOUTH, CableBlock.WEST, CableBlock.EAST };
|
||||||
private static final boolean[] BOOLEANS = new boolean[]{ false, true };
|
private static final boolean[] BOOLEANS = new boolean[]{ false, true };
|
||||||
|
|
@@ -7,7 +7,15 @@ package dan200.computercraft.data;
|
|||||||
import com.mojang.serialization.Codec;
|
import com.mojang.serialization.Codec;
|
||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.client.gui.GuiSprites;
|
||||||
|
import dan200.computercraft.client.model.LecternPrintoutModel;
|
||||||
|
import dan200.computercraft.data.client.ExtraModelsProvider;
|
||||||
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
|
import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.renderer.texture.atlas.SpriteSource;
|
||||||
|
import net.minecraft.client.renderer.texture.atlas.SpriteSources;
|
||||||
|
import net.minecraft.client.renderer.texture.atlas.sources.SingleFile;
|
||||||
import net.minecraft.core.HolderLookup;
|
import net.minecraft.core.HolderLookup;
|
||||||
import net.minecraft.core.RegistrySetBuilder;
|
import net.minecraft.core.RegistrySetBuilder;
|
||||||
import net.minecraft.data.DataProvider;
|
import net.minecraft.data.DataProvider;
|
||||||
@@ -19,10 +27,15 @@ import net.minecraft.server.packs.PackType;
|
|||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All data providers for ComputerCraft. We require a mod-loader abstraction {@link GeneratorSink} (instead of
|
* All data providers for ComputerCraft. We require a mod-loader abstraction {@link GeneratorSink} (instead of
|
||||||
@@ -38,6 +51,7 @@ public final class DataProviders {
|
|||||||
Util.make(new RegistrySetBuilder(), builder -> {
|
Util.make(new RegistrySetBuilder(), builder -> {
|
||||||
builder.add(ITurtleUpgrade.REGISTRY, TurtleUpgradeProvider::addUpgrades);
|
builder.add(ITurtleUpgrade.REGISTRY, TurtleUpgradeProvider::addUpgrades);
|
||||||
builder.add(IPocketUpgrade.REGISTRY, PocketUpgradeProvider::addUpgrades);
|
builder.add(IPocketUpgrade.REGISTRY, PocketUpgradeProvider::addUpgrades);
|
||||||
|
builder.add(TurtleOverlay.REGISTRY, TurtleOverlays::register);
|
||||||
}));
|
}));
|
||||||
var fullRegistries = fullRegistryPatch.thenApply(RegistrySetBuilder.PatchedRegistries::full);
|
var fullRegistries = fullRegistryPatch.thenApply(RegistrySetBuilder.PatchedRegistries::full);
|
||||||
|
|
||||||
@@ -53,14 +67,37 @@ public final class DataProviders {
|
|||||||
|
|
||||||
generator.add(out -> new LanguageProvider(out, fullRegistries));
|
generator.add(out -> new LanguageProvider(out, fullRegistries));
|
||||||
|
|
||||||
// Unfortunately we rely on some client-side classes in this code. We just load in the client side data provider
|
generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
|
||||||
// and invoke that.
|
out.accept(ResourceLocation.withDefaultNamespace("blocks"), makeSprites(Stream.of(
|
||||||
try {
|
UpgradeSlot.LEFT_UPGRADE,
|
||||||
Class.forName("dan200.computercraft.data.client.ClientDataProviders")
|
UpgradeSlot.RIGHT_UPGRADE,
|
||||||
.getMethod("add", GeneratorSink.class).invoke(null, generator);
|
LecternPrintoutModel.TEXTURE
|
||||||
} catch (ReflectiveOperationException e) {
|
)));
|
||||||
throw new RuntimeException(e);
|
out.accept(GuiSprites.SPRITE_SHEET, makeSprites(
|
||||||
}
|
// Buttons
|
||||||
|
GuiSprites.TURNED_OFF.textures(),
|
||||||
|
GuiSprites.TURNED_ON.textures(),
|
||||||
|
GuiSprites.TERMINATE.textures(),
|
||||||
|
// Computers
|
||||||
|
GuiSprites.COMPUTER_NORMAL.textures(),
|
||||||
|
GuiSprites.COMPUTER_ADVANCED.textures(),
|
||||||
|
GuiSprites.COMPUTER_COMMAND.textures(),
|
||||||
|
GuiSprites.COMPUTER_COLOUR.textures()
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
generator.add(pack -> new ExtraModelsProvider(pack, fullRegistries) {
|
||||||
|
@Override
|
||||||
|
public Stream<ResourceLocation> getModels(HolderLookup.Provider registries) {
|
||||||
|
return registries.lookupOrThrow(TurtleOverlay.REGISTRY).listElements().map(x -> x.value().model());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@SafeVarargs
|
||||||
|
@SuppressWarnings("varargs")
|
||||||
|
private static List<SpriteSource> makeSprites(final Stream<ResourceLocation>... files) {
|
||||||
|
return Arrays.stream(files).flatMap(Function.identity()).<SpriteSource>map(x -> new SingleFile(x, Optional.empty())).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface GeneratorSink {
|
public interface GeneratorSink {
|
@@ -82,6 +82,7 @@ public final class LanguageProvider implements DataProvider {
|
|||||||
add(ModRegistry.Items.WIRED_MODEM.get(), "Wired Modem");
|
add(ModRegistry.Items.WIRED_MODEM.get(), "Wired Modem");
|
||||||
add(ModRegistry.Items.CABLE.get(), "Networking Cable");
|
add(ModRegistry.Items.CABLE.get(), "Networking Cable");
|
||||||
add(ModRegistry.Items.WIRED_MODEM_FULL.get(), "Wired Modem");
|
add(ModRegistry.Items.WIRED_MODEM_FULL.get(), "Wired Modem");
|
||||||
|
add(ModRegistry.Items.REDSTONE_RELAY.get(), "Redstone Relay");
|
||||||
|
|
||||||
add(ModRegistry.Items.TURTLE_NORMAL.get(), "Turtle");
|
add(ModRegistry.Items.TURTLE_NORMAL.get(), "Turtle");
|
||||||
add(ModRegistry.Blocks.TURTLE_NORMAL.get().getDescriptionId() + ".upgraded", "%s Turtle");
|
add(ModRegistry.Blocks.TURTLE_NORMAL.get().getDescriptionId() + ".upgraded", "%s Turtle");
|
||||||
@@ -164,8 +165,6 @@ public final class LanguageProvider implements DataProvider {
|
|||||||
add("commands.computercraft.queue.synopsis", "Send a computer_command event to a command computer");
|
add("commands.computercraft.queue.synopsis", "Send a computer_command event to a command computer");
|
||||||
add("commands.computercraft.queue.desc", "Send a computer_command event to a command computer, passing through the additional arguments. This is mostly designed for map makers, acting as a more computer-friendly version of /trigger. Any player can run the command, which would most likely be done through a text component's click event.");
|
add("commands.computercraft.queue.desc", "Send a computer_command event to a command computer, passing through the additional arguments. This is mostly designed for map makers, acting as a more computer-friendly version of /trigger. Any player can run the command, which would most likely be done through a text component's click event.");
|
||||||
|
|
||||||
add("commands.computercraft.generic.no_position", "<no pos>");
|
|
||||||
add("commands.computercraft.generic.position", "%s, %s, %s");
|
|
||||||
add("commands.computercraft.generic.yes", "Y");
|
add("commands.computercraft.generic.yes", "Y");
|
||||||
add("commands.computercraft.generic.no", "N");
|
add("commands.computercraft.generic.no", "N");
|
||||||
add("commands.computercraft.generic.exception", "Unhandled exception (%s)");
|
add("commands.computercraft.generic.exception", "Unhandled exception (%s)");
|
||||||
@@ -288,7 +287,9 @@ public final class LanguageProvider implements DataProvider {
|
|||||||
return Stream.of(
|
return Stream.of(
|
||||||
BuiltInRegistries.BLOCK.holders()
|
BuiltInRegistries.BLOCK.holders()
|
||||||
.filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID))
|
.filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID))
|
||||||
.map(x -> x.value().getDescriptionId()),
|
.map(x -> x.value().getDescriptionId())
|
||||||
|
// Exclude blocks that just reuse vanilla translations, such as the lectern.
|
||||||
|
.filter(x -> !x.startsWith("block.minecraft.")),
|
||||||
BuiltInRegistries.ITEM.holders()
|
BuiltInRegistries.ITEM.holders()
|
||||||
.filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID))
|
.filter(x -> x.key().location().getNamespace().equals(ComputerCraftAPI.MOD_ID))
|
||||||
.map(x -> x.value().getDescriptionId()),
|
.map(x -> x.value().getDescriptionId()),
|
@@ -14,6 +14,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
|
|||||||
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
|
import net.minecraft.advancements.critereon.StatePropertiesPredicate;
|
||||||
import net.minecraft.data.loot.LootTableProvider.SubProviderEntry;
|
import net.minecraft.data.loot.LootTableProvider.SubProviderEntry;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.storage.loot.LootPool;
|
import net.minecraft.world.level.storage.loot.LootPool;
|
||||||
import net.minecraft.world.level.storage.loot.LootTable;
|
import net.minecraft.world.level.storage.loot.LootTable;
|
||||||
@@ -49,6 +50,7 @@ class LootTableProvider {
|
|||||||
selfDrop(add, ModRegistry.Blocks.WIRED_MODEM_FULL);
|
selfDrop(add, ModRegistry.Blocks.WIRED_MODEM_FULL);
|
||||||
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_NORMAL);
|
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_NORMAL);
|
||||||
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED);
|
selfDrop(add, ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED);
|
||||||
|
selfDrop(add, ModRegistry.Blocks.REDSTONE_RELAY);
|
||||||
|
|
||||||
computerDrop(add, ModRegistry.Blocks.COMPUTER_NORMAL);
|
computerDrop(add, ModRegistry.Blocks.COMPUTER_NORMAL);
|
||||||
computerDrop(add, ModRegistry.Blocks.COMPUTER_ADVANCED);
|
computerDrop(add, ModRegistry.Blocks.COMPUTER_ADVANCED);
|
||||||
@@ -56,6 +58,8 @@ class LootTableProvider {
|
|||||||
computerDrop(add, ModRegistry.Blocks.TURTLE_NORMAL);
|
computerDrop(add, ModRegistry.Blocks.TURTLE_NORMAL);
|
||||||
computerDrop(add, ModRegistry.Blocks.TURTLE_ADVANCED);
|
computerDrop(add, ModRegistry.Blocks.TURTLE_ADVANCED);
|
||||||
|
|
||||||
|
blockDrop(add, ModRegistry.Blocks.LECTERN, LootItem.lootTableItem(Items.LECTERN), ExplosionCondition.survivesExplosion());
|
||||||
|
|
||||||
add.accept(ModRegistry.Blocks.CABLE.get().getLootTable(), LootTable
|
add.accept(ModRegistry.Blocks.CABLE.get().getLootTable(), LootTable
|
||||||
.lootTable()
|
.lootTable()
|
||||||
.withPool(LootPool.lootPool()
|
.withPool(LootPool.lootPool()
|
@@ -7,6 +7,7 @@ package dan200.computercraft.data;
|
|||||||
import com.google.common.hash.HashCode;
|
import com.google.common.hash.HashCode;
|
||||||
import com.google.common.hash.HashFunction;
|
import com.google.common.hash.HashFunction;
|
||||||
import com.google.common.hash.Hashing;
|
import com.google.common.hash.Hashing;
|
||||||
|
import dan200.computercraft.shared.util.PrettyJsonWriter;
|
||||||
import net.minecraft.data.CachedOutput;
|
import net.minecraft.data.CachedOutput;
|
||||||
import net.minecraft.data.DataProvider;
|
import net.minecraft.data.DataProvider;
|
||||||
|
|
@@ -28,6 +28,7 @@ import dan200.computercraft.shared.recipe.ImpostorShapelessRecipe;
|
|||||||
import dan200.computercraft.shared.recipe.TransformShapedRecipe;
|
import dan200.computercraft.shared.recipe.TransformShapedRecipe;
|
||||||
import dan200.computercraft.shared.recipe.TransformShapelessRecipe;
|
import dan200.computercraft.shared.recipe.TransformShapelessRecipe;
|
||||||
import dan200.computercraft.shared.recipe.function.CopyComponents;
|
import dan200.computercraft.shared.recipe.function.CopyComponents;
|
||||||
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||||
import dan200.computercraft.shared.util.ColourUtils;
|
import dan200.computercraft.shared.util.ColourUtils;
|
||||||
@@ -45,6 +46,7 @@ import net.minecraft.data.recipes.RecipeCategory;
|
|||||||
import net.minecraft.data.recipes.RecipeOutput;
|
import net.minecraft.data.recipes.RecipeOutput;
|
||||||
import net.minecraft.data.recipes.ShapedRecipeBuilder;
|
import net.minecraft.data.recipes.ShapedRecipeBuilder;
|
||||||
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
|
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.tags.ItemTags;
|
import net.minecraft.tags.ItemTags;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
@@ -96,7 +98,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
diskColours(add);
|
diskColours(add);
|
||||||
pocketUpgrades(add, registries);
|
pocketUpgrades(add, registries);
|
||||||
turtleUpgrades(add, registries);
|
turtleUpgrades(add, registries);
|
||||||
turtleOverlays(add);
|
turtleOverlays(add, registries);
|
||||||
|
|
||||||
addSpecial(add, new DiskRecipe(CraftingBookCategory.MISC));
|
addSpecial(add, new DiskRecipe(CraftingBookCategory.MISC));
|
||||||
addSpecial(add, new ColourableRecipe(CraftingBookCategory.MISC));
|
addSpecial(add, new ColourableRecipe(CraftingBookCategory.MISC));
|
||||||
@@ -189,8 +191,8 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void turtleOverlays(RecipeOutput add) {
|
private void turtleOverlays(RecipeOutput add, HolderLookup.Provider registries) {
|
||||||
turtleOverlay(add, "turtle_trans_overlay", x -> x
|
turtleOverlay(add, registries, TurtleOverlays.TRANS_FLAG, x -> x
|
||||||
.unlockedBy("has_dye", inventoryChange(itemPredicate(ingredients.dye())))
|
.unlockedBy("has_dye", inventoryChange(itemPredicate(ingredients.dye())))
|
||||||
.requires(ColourUtils.getDyeTag(DyeColor.LIGHT_BLUE))
|
.requires(ColourUtils.getDyeTag(DyeColor.LIGHT_BLUE))
|
||||||
.requires(ColourUtils.getDyeTag(DyeColor.PINK))
|
.requires(ColourUtils.getDyeTag(DyeColor.PINK))
|
||||||
@@ -198,7 +200,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
.requires(Items.STICK)
|
.requires(Items.STICK)
|
||||||
);
|
);
|
||||||
|
|
||||||
turtleOverlay(add, "turtle_rainbow_overlay", x -> x
|
turtleOverlay(add, registries, TurtleOverlays.RAINBOW_FLAG, x -> x
|
||||||
.unlockedBy("has_dye", inventoryChange(itemPredicate(ingredients.dye())))
|
.unlockedBy("has_dye", inventoryChange(itemPredicate(ingredients.dye())))
|
||||||
.requires(ColourUtils.getDyeTag(DyeColor.RED))
|
.requires(ColourUtils.getDyeTag(DyeColor.RED))
|
||||||
.requires(ColourUtils.getDyeTag(DyeColor.ORANGE))
|
.requires(ColourUtils.getDyeTag(DyeColor.ORANGE))
|
||||||
@@ -210,14 +212,14 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void turtleOverlay(RecipeOutput add, String overlay, Consumer<ShapelessSpecBuilder> build) {
|
private void turtleOverlay(RecipeOutput add, HolderLookup.Provider registries, ResourceKey<TurtleOverlay> overlay, Consumer<ShapelessSpecBuilder> build) {
|
||||||
var overlayId = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/" + overlay);
|
var holder = registries.lookupOrThrow(overlay.registryKey()).getOrThrow(overlay);
|
||||||
|
|
||||||
for (var turtleItem : turtleItems()) {
|
for (var turtleItem : turtleItems()) {
|
||||||
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem);
|
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem);
|
||||||
|
|
||||||
var builder = ShapelessSpecBuilder
|
var builder = ShapelessSpecBuilder
|
||||||
.shapeless(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.OVERLAY.get(), overlayId))
|
.shapeless(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.OVERLAY.get(), holder))
|
||||||
.group(name.withSuffix("_overlay").toString())
|
.group(name.withSuffix("_overlay").toString())
|
||||||
.unlockedBy("has_turtle", inventoryChange(turtleItem));
|
.unlockedBy("has_turtle", inventoryChange(turtleItem));
|
||||||
build.accept(builder);
|
build.accept(builder);
|
||||||
@@ -226,7 +228,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
.build(s -> new TransformShapelessRecipe(s, List.of(
|
.build(s -> new TransformShapelessRecipe(s, List.of(
|
||||||
CopyComponents.builder(turtleItem).exclude(ModRegistry.DataComponents.OVERLAY.get()).build()
|
CopyComponents.builder(turtleItem).exclude(ModRegistry.DataComponents.OVERLAY.get()).build()
|
||||||
)))
|
)))
|
||||||
.save(add, name.withSuffix("_overlays/" + overlay));
|
.save(add, name.withSuffix("_overlays/" + overlay.location().getPath()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,6 +491,17 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
|||||||
.unlockedBy("has_printer", inventoryChange(ModRegistry.Items.PRINTER.get()))
|
.unlockedBy("has_printer", inventoryChange(ModRegistry.Items.PRINTER.get()))
|
||||||
.build(x -> new PrintoutRecipe(x, pages, 1))
|
.build(x -> new PrintoutRecipe(x, pages, 1))
|
||||||
.save(add);
|
.save(add);
|
||||||
|
|
||||||
|
ShapedRecipeBuilder
|
||||||
|
.shaped(RecipeCategory.REDSTONE, ModRegistry.Blocks.REDSTONE_RELAY.get())
|
||||||
|
.pattern("SRS")
|
||||||
|
.pattern("RCR")
|
||||||
|
.pattern("SRS")
|
||||||
|
.define('S', Items.STONE)
|
||||||
|
.define('R', ingredients.redstone())
|
||||||
|
.define('C', ModRegistry.Blocks.CABLE.get())
|
||||||
|
.unlockedBy("has_cable", inventoryChange(ModRegistry.Blocks.CABLE.get()))
|
||||||
|
.save(add);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DyeColor ofColour(Colour colour) {
|
private static DyeColor ofColour(Colour colour) {
|
@@ -5,9 +5,9 @@
|
|||||||
package dan200.computercraft.data;
|
package dan200.computercraft.data;
|
||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftTags;
|
import dan200.computercraft.api.ComputerCraftTags;
|
||||||
import dan200.computercraft.shared.util.RegistryHelper;
|
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.integration.ExternalModTags;
|
import dan200.computercraft.shared.integration.ExternalModTags;
|
||||||
|
import dan200.computercraft.shared.util.RegistryHelper;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.data.tags.ItemTagsProvider;
|
import net.minecraft.data.tags.ItemTagsProvider;
|
||||||
import net.minecraft.data.tags.TagsProvider;
|
import net.minecraft.data.tags.TagsProvider;
|
||||||
@@ -60,10 +60,7 @@ class TagProvider {
|
|||||||
|
|
||||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_SWORD_BREAKABLE).addTag(BlockTags.WOOL).add(Blocks.COBWEB);
|
tags.tag(ComputerCraftTags.Blocks.TURTLE_SWORD_BREAKABLE).addTag(BlockTags.WOOL).add(Blocks.COBWEB);
|
||||||
|
|
||||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_CAN_USE)
|
tags.tag(ComputerCraftTags.Blocks.TURTLE_CAN_USE);
|
||||||
.addTag(BlockTags.BEEHIVES)
|
|
||||||
.addTag(BlockTags.CAULDRONS)
|
|
||||||
.add(Blocks.COMPOSTER);
|
|
||||||
|
|
||||||
// Make all blocks aside from command computer mineable.
|
// Make all blocks aside from command computer mineable.
|
||||||
tags.tag(BlockTags.MINEABLE_WITH_PICKAXE).add(
|
tags.tag(BlockTags.MINEABLE_WITH_PICKAXE).add(
|
||||||
@@ -79,9 +76,12 @@ class TagProvider {
|
|||||||
ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get(),
|
ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get(),
|
||||||
ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get(),
|
ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get(),
|
||||||
ModRegistry.Blocks.WIRED_MODEM_FULL.get(),
|
ModRegistry.Blocks.WIRED_MODEM_FULL.get(),
|
||||||
ModRegistry.Blocks.CABLE.get()
|
ModRegistry.Blocks.CABLE.get(),
|
||||||
|
ModRegistry.Blocks.REDSTONE_RELAY.get()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
tags.tag(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.Blocks.LECTERN.get());
|
||||||
|
|
||||||
tags.tag(BlockTags.WITHER_IMMUNE).add(ModRegistry.Blocks.COMPUTER_COMMAND.get());
|
tags.tag(BlockTags.WITHER_IMMUNE).add(ModRegistry.Blocks.COMPUTER_COMMAND.get());
|
||||||
|
|
||||||
tags.tag(ExternalModTags.Blocks.CREATE_BRITTLE).add(
|
tags.tag(ExternalModTags.Blocks.CREATE_BRITTLE).add(
|
||||||
@@ -107,6 +107,7 @@ class TagProvider {
|
|||||||
ModRegistry.Items.MONITOR_ADVANCED.get()
|
ModRegistry.Items.MONITOR_ADVANCED.get()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Allow printed books to be placed in bookshelves.
|
||||||
tags.tag(ItemTags.BOOKSHELF_BOOKS).add(ModRegistry.Items.PRINTED_BOOK.get());
|
tags.tag(ItemTags.BOOKSHELF_BOOKS).add(ModRegistry.Items.PRINTED_BOOK.get());
|
||||||
|
|
||||||
tags.tag(ComputerCraftTags.Items.TURTLE_CAN_PLACE)
|
tags.tag(ComputerCraftTags.Items.TURTLE_CAN_PLACE)
|
||||||
@@ -144,7 +145,7 @@ class TagProvider {
|
|||||||
/**
|
/**
|
||||||
* A wrapper over {@link ItemTagsProvider}.
|
* A wrapper over {@link ItemTagsProvider}.
|
||||||
*/
|
*/
|
||||||
interface ItemTagConsumer extends TagConsumer<Item> {
|
public interface ItemTagConsumer extends TagConsumer<Item> {
|
||||||
void copy(TagKey<Block> block, TagKey<Item> item);
|
void copy(TagKey<Block> block, TagKey<Item> item);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,38 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.data;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||||
|
import net.minecraft.data.worldgen.BootstrapContext;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Built-in turtle overlays.
|
||||||
|
*/
|
||||||
|
final class TurtleOverlays {
|
||||||
|
public static final ResourceKey<TurtleOverlay> RAINBOW_FLAG = create("rainbow_flag");
|
||||||
|
public static final ResourceKey<TurtleOverlay> TRANS_FLAG = create("trans_flag");
|
||||||
|
|
||||||
|
private static ResourceKey<TurtleOverlay> create(String name) {
|
||||||
|
return ResourceKey.create(TurtleOverlay.REGISTRY, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name));
|
||||||
|
}
|
||||||
|
|
||||||
|
private TurtleOverlays() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register(BootstrapContext<TurtleOverlay> registry) {
|
||||||
|
registry.register(RAINBOW_FLAG, new TurtleOverlay(
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_rainbow_overlay"),
|
||||||
|
true
|
||||||
|
));
|
||||||
|
|
||||||
|
registry.register(TRANS_FLAG, new TurtleOverlay(
|
||||||
|
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_trans_overlay"),
|
||||||
|
true
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,52 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.data.client;
|
||||||
|
|
||||||
|
import com.mojang.serialization.JsonOps;
|
||||||
|
import dan200.computercraft.client.model.ExtraModels;
|
||||||
|
import net.minecraft.core.HolderLookup;
|
||||||
|
import net.minecraft.data.CachedOutput;
|
||||||
|
import net.minecraft.data.DataProvider;
|
||||||
|
import net.minecraft.data.PackOutput;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data provider to generate {@link ExtraModels}.
|
||||||
|
*/
|
||||||
|
public abstract class ExtraModelsProvider implements DataProvider {
|
||||||
|
private final Path path;
|
||||||
|
private final CompletableFuture<HolderLookup.Provider> registries;
|
||||||
|
|
||||||
|
public ExtraModelsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
|
||||||
|
path = output.getOutputFolder(PackOutput.Target.RESOURCE_PACK).resolve(ExtraModels.PATH.getNamespace()).resolve(ExtraModels.PATH.getPath());
|
||||||
|
this.registries = registries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a stream of models to load.
|
||||||
|
*
|
||||||
|
* @param registries The current registries.
|
||||||
|
* @return The collection of extra models to load.
|
||||||
|
*/
|
||||||
|
public abstract Stream<ResourceLocation> getModels(HolderLookup.Provider registries);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final CompletableFuture<?> run(CachedOutput output) {
|
||||||
|
return registries.thenCompose(registries -> {
|
||||||
|
var models = new ExtraModels(getModels(registries).sorted().toList());
|
||||||
|
var json = ExtraModels.CODEC.encodeStart(JsonOps.INSTANCE, models).getOrThrow(IllegalStateException::new);
|
||||||
|
return DataProvider.saveStable(output, json, path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String getName() {
|
||||||
|
return "Extra Models";
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"type": "examplemod:example_turtle_upgrade",
|
||||||
|
"item": "minecraft:compass"
|
||||||
|
}
|
@@ -0,0 +1,75 @@
|
|||||||
|
package com.example.examplemod;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.api.component.ComputerComponents;
|
||||||
|
import dan200.computercraft.api.lua.Coerced;
|
||||||
|
import dan200.computercraft.api.lua.ILuaAPI;
|
||||||
|
import dan200.computercraft.api.lua.LuaFunction;
|
||||||
|
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An example API that will be available on every turtle. This demonstrates both registering an API, and how to write
|
||||||
|
* Lua-facing functions.
|
||||||
|
* <p>
|
||||||
|
* This API is not available as a global (as {@link #getNames() returns nothing}), but is instead accessible via
|
||||||
|
* {@code require} (see {@link #getModuleName()}).
|
||||||
|
*
|
||||||
|
* <h2>Example</h2>
|
||||||
|
* <pre class="language language-lua">{@code
|
||||||
|
* local my_api = require("example.my_api")
|
||||||
|
* print("Turtle is facing " .. my_api.getDirection())
|
||||||
|
* }</pre>
|
||||||
|
*/
|
||||||
|
public class ExampleAPI implements ILuaAPI {
|
||||||
|
private final ITurtleAccess turtle;
|
||||||
|
|
||||||
|
public ExampleAPI(ITurtleAccess turtle) {
|
||||||
|
this.turtle = turtle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void register() {
|
||||||
|
// @start region=register
|
||||||
|
ComputerCraftAPI.registerAPIFactory(computer -> {
|
||||||
|
// Read the turtle component.
|
||||||
|
var turtle = computer.getComponent(ComputerComponents.TURTLE);
|
||||||
|
// If present then add our API.
|
||||||
|
return turtle == null ? null : new ExampleAPI(turtle);
|
||||||
|
});
|
||||||
|
// @end region=register
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getNames() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable String getModuleName() {
|
||||||
|
return "example.my_api";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Lua-facing function function that returns the direction the turtle is facing.
|
||||||
|
*
|
||||||
|
* @return The turtle's direction.
|
||||||
|
*/
|
||||||
|
@LuaFunction
|
||||||
|
public final String getDirection() {
|
||||||
|
return turtle.getDirection().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Lua-facing function using {@link Coerced}. Unlike a {@link LuaFunction} taking a raw {@link String}, this will
|
||||||
|
* accept any value, and convert it to a string.
|
||||||
|
*
|
||||||
|
* @param myString The value to write.
|
||||||
|
*/
|
||||||
|
// @start region=coerced
|
||||||
|
@LuaFunction
|
||||||
|
public final void writeString(Coerced<String> myString) {
|
||||||
|
String contents = myString.value();
|
||||||
|
System.out.println("Got " + contents);
|
||||||
|
}
|
||||||
|
// @end region=coerced
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user