mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-15 14:07:38 +00:00
Compare commits
267 Commits
v1.20.1-1.
...
v1.20.1-1.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d24984c1d5 | ||
![]() |
8080dcdd9e | ||
![]() |
d7cea55e2a | ||
![]() |
9b2f974a81 | ||
![]() |
43770fa9bd | ||
![]() |
80c7a54ad4 | ||
![]() |
e57b6fede2 | ||
![]() |
34a2fd039f | ||
![]() |
3299d0e72a | ||
![]() |
b89e2615db | ||
![]() |
cdcd82679c | ||
![]() |
cdfa866760 | ||
![]() |
aa8078ddeb | ||
![]() |
7e53c19d74 | ||
![]() |
b7a8432cfb | ||
![]() |
356c8e8aeb | ||
![]() |
ed283155f7 | ||
![]() |
87dfad026e | ||
![]() |
bb97c465d9 | ||
![]() |
9484315d37 | ||
![]() |
be59f1a875 | ||
![]() |
bfb28b4710 | ||
![]() |
216f0adb3c | ||
![]() |
77af4bc213 | ||
![]() |
5abab982c7 | ||
![]() |
764e1aa332 | ||
![]() |
c47718b09d | ||
![]() |
08d4f91c8b | ||
![]() |
b9eac4e509 | ||
![]() |
dc3d8ea198 | ||
![]() |
cbe075b001 | ||
![]() |
ed0b156e05 | ||
![]() |
4dd0735066 | ||
![]() |
38e516d7c7 | ||
![]() |
70a31855ac | ||
![]() |
6c8e64ffcd | ||
![]() |
7285c32d58 | ||
![]() |
99c60ac54b | ||
![]() |
63e40cf3cb | ||
![]() |
1d45935a25 | ||
![]() |
f80373e7a2 | ||
![]() |
63185629b7 | ||
![]() |
4bfb9ac323 | ||
![]() |
5926b6c994 | ||
![]() |
f5ed43584d | ||
![]() |
d77f5f135f | ||
![]() |
7744d2663b | ||
![]() |
4566cb8273 | ||
![]() |
052e7a7ae5 | ||
![]() |
0895200681 | ||
![]() |
09d0f563b7 | ||
![]() |
e188f1d3fa | ||
![]() |
819a4f7231 | ||
![]() |
898cb2a95d | ||
![]() |
03a8f83191 | ||
![]() |
aef92c8ebc | ||
![]() |
571ea794a8 | ||
![]() |
e81af93043 | ||
![]() |
25b8a65c5c | ||
![]() |
e4236824d7 | ||
![]() |
cfd11ffa92 | ||
![]() |
ce133a5e66 | ||
![]() |
038fbc1ed1 | ||
![]() |
c582fb521c | ||
![]() |
af21792844 | ||
![]() |
9fbb1070ef | ||
![]() |
1944995c33 | ||
![]() |
ac851a795b | ||
![]() |
334761788a | ||
![]() |
5af3e15dd5 | ||
![]() |
209b1ddbf9 | ||
![]() |
0c9f9a8652 | ||
![]() |
862d92785e | ||
![]() |
d48b85d50c | ||
![]() |
4d619de357 | ||
![]() |
57c289f173 | ||
![]() |
f63f85921f | ||
![]() |
c7e49d1929 | ||
![]() |
d9b0cc7075 | ||
![]() |
1e214f329e | ||
![]() |
de930c8d09 | ||
![]() |
735e7ce09b | ||
![]() |
6e9799316a | ||
![]() |
4e90240922 | ||
![]() |
1a87d1bf45 | ||
![]() |
00e2e2bd2d | ||
![]() |
7c1f40031b | ||
![]() |
929debd382 | ||
![]() |
4980b7355d | ||
![]() |
925092add3 | ||
![]() |
550296edc5 | ||
![]() |
0771c4891b | ||
![]() |
776fa00b94 | ||
![]() |
03bb279206 | ||
![]() |
fabd77132d | ||
![]() |
95be0a25bf | ||
![]() |
ad49325376 | ||
![]() |
825d45eb26 | ||
![]() |
8b2516abb5 | ||
![]() |
bce099ef32 | ||
![]() |
6d14ce625f | ||
![]() |
c8eadf4011 | ||
![]() |
0c1ab780bb | ||
![]() |
0f623c2cca | ||
![]() |
b9ba2534a4 | ||
![]() |
c764981a40 | ||
![]() |
6363164f2b | ||
![]() |
63580b4acb | ||
![]() |
9af1aa1ecf | ||
![]() |
ad0f551204 | ||
![]() |
0d3e00cc41 | ||
![]() |
836d6b939e | ||
![]() |
0e5248e5e6 | ||
![]() |
e154b0db2a | ||
![]() |
ae767eb5be | ||
![]() |
777aa34bb0 | ||
![]() |
286f969f94 | ||
![]() |
57c72711bb | ||
![]() |
cbafbca86b | ||
![]() |
c9caffb10f | ||
![]() |
4675583e1c | ||
![]() |
afe16cc593 | ||
![]() |
0abd107348 | ||
![]() |
cef4b4906b | ||
![]() |
04900dc82f | ||
![]() |
9b63cc81b1 | ||
![]() |
9eead7a0ec | ||
![]() |
ad97b2922b | ||
![]() |
52986f8d73 | ||
![]() |
ab00580389 | ||
![]() |
128ac2f109 | ||
![]() |
5d8c46c7e6 | ||
![]() |
1a5dc92bd4 | ||
![]() |
98b2d3f310 | ||
![]() |
e92c2d02f8 | ||
![]() |
f8ef40d378 | ||
![]() |
61f9b1d0c6 | ||
![]() |
ffb62dfa02 | ||
![]() |
6fb291112d | ||
![]() |
7ee821e9c9 | ||
![]() |
b7df91349a | ||
![]() |
cb8e06af2a | ||
![]() |
6478fca7a2 | ||
![]() |
3493159a05 | ||
![]() |
eead67e314 | ||
![]() |
3b8813cf8f | ||
![]() |
a9191a4d4e | ||
![]() |
451a2593ce | ||
![]() |
d38b1da974 | ||
![]() |
6e374579a4 | ||
![]() |
4daa2a2b6a | ||
![]() |
84b6edab82 | ||
![]() |
31aaf46d09 | ||
![]() |
2d11b51c62 | ||
![]() |
a0f759527d | ||
![]() |
385e4210fa | ||
![]() |
d2896473f2 | ||
![]() |
f14cb2a3d1 | ||
![]() |
8db5c6bc3a | ||
![]() |
f26e443e81 | ||
![]() |
033378333f | ||
![]() |
ebeaa757a9 | ||
![]() |
57b1a65db3 | ||
![]() |
27c72a4571 | ||
![]() |
f284328656 | ||
![]() |
6b83c63991 | ||
![]() |
b27526bd21 | ||
![]() |
cb25f6c08a | ||
![]() |
d38b1d04e7 | ||
![]() |
9ccee75a99 | ||
![]() |
359c8d6652 | ||
![]() |
1788afacfc | ||
![]() |
f695f22d8a | ||
![]() |
bc03090ca4 | ||
![]() |
a617d0d566 | ||
![]() |
36599b321e | ||
![]() |
1d6e3f4fc0 | ||
![]() |
30dc4cb38c | ||
![]() |
be4512d1c3 | ||
![]() |
e6ee292850 | ||
![]() |
9d36f72bad | ||
![]() |
b5923c4462 | ||
![]() |
4d1e689719 | ||
![]() |
9d4af07568 | ||
![]() |
89294f4a22 | ||
![]() |
133b51b092 | ||
![]() |
272010e945 | ||
![]() |
e0889c613a | ||
![]() |
f115d43d07 | ||
![]() |
8be6b1b772 | ||
![]() |
104d5e70de | ||
![]() |
e3bda2f763 | ||
![]() |
234f69e8e5 | ||
![]() |
ed3a17f9b9 | ||
![]() |
0349c2b1f9 | ||
![]() |
03f9e6bd6d | ||
![]() |
9d8c933a14 | ||
![]() |
78bb3da58c | ||
![]() |
39a5e40c92 | ||
![]() |
763ba51919 | ||
![]() |
cf6ec8c28f | ||
![]() |
95d3b646b2 | ||
![]() |
488f66eead | ||
![]() |
1f7d245876 | ||
![]() |
af12b3a0ea | ||
![]() |
eb3e8ba677 | ||
![]() |
2043939531 | ||
![]() |
84a799d27a | ||
![]() |
fe826f5c9c | ||
![]() |
f8b7422294 | ||
![]() |
b343c01216 | ||
![]() |
76968f2f28 | ||
![]() |
1d365f5a0b | ||
![]() |
7b240cbf7e | ||
![]() |
d272a327c7 | ||
![]() |
0c0556a5bc | ||
![]() |
87345c6b2e | ||
![]() |
784e623776 | ||
![]() |
bcb3e9bd53 | ||
![]() |
c30bffbd0f | ||
![]() |
91c41856c5 | ||
![]() |
18c9723308 | ||
![]() |
aee382ed70 | ||
![]() |
6656da5877 | ||
![]() |
09e521727f | ||
![]() |
cab66a2d6e | ||
![]() |
8eabd4f303 | ||
![]() |
e3ced84885 | ||
![]() |
0929ab577d | ||
![]() |
2228733abc | ||
![]() |
e67c94d1bd | ||
![]() |
ae5a661a47 | ||
![]() |
0ff58cdc3e | ||
![]() |
1747c74770 | ||
![]() |
71669cf49c | ||
![]() |
bd327e37eb | ||
![]() |
bdce9a8170 | ||
![]() |
7e5598d084 | ||
![]() |
440fca6535 | ||
![]() |
6635edd35c | ||
![]() |
93ad40efbb | ||
![]() |
27dc8b5b2c | ||
![]() |
3ebdf7ef5e | ||
![]() |
905d4cb091 | ||
![]() |
e7ab05d064 | ||
![]() |
6ec34b42e5 | ||
![]() |
ab785a0906 | ||
![]() |
4541decd40 | ||
![]() |
747a5a53b4 | ||
![]() |
c0643fadca | ||
![]() |
0a31de43c2 | ||
![]() |
96b6947ef2 | ||
![]() |
e7a1065bfc | ||
![]() |
663eecff0c | ||
![]() |
e6125bcf60 | ||
![]() |
0d6c6e7ae7 | ||
![]() |
ae71eb3cae | ||
![]() |
3188197447 | ||
![]() |
6c8b391dab | ||
![]() |
b1248e4901 | ||
![]() |
56d97630e8 | ||
![]() |
e660192f08 | ||
![]() |
4e82bd352d | ||
![]() |
07113c3e9b | ||
![]() |
d562a051c7 | ||
![]() |
6ac09742fc | ||
![]() |
5dd6b9a637 |
6
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -8,10 +8,8 @@ body:
|
||||
label: Minecraft Version
|
||||
description: What version of Minecraft are you using?
|
||||
options:
|
||||
- 1.16.x
|
||||
- 1.18.x
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.20.1
|
||||
- 1.21.x
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
|
30
.github/workflows/main-ci.yml
vendored
30
.github/workflows/main-ci.yml
vendored
@@ -9,16 +9,16 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 📥 Clone repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: 📥 Set up Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: 📥 Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||
|
||||
@@ -58,13 +58,13 @@ jobs:
|
||||
find projects/forge/build/libs projects/fabric/build/libs -type f -regex '.*[0-9.]+\(-SNAPSHOT\)?\.jar$' -exec bash -c 'cp {} "jars/$(basename {} .jar)-$(git rev-parse HEAD).jar"' \;
|
||||
|
||||
- name: 📤 Upload Jar
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: CC-Tweaked
|
||||
path: ./jars
|
||||
|
||||
- name: 📤 Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
uses: codecov/codecov-action@v4
|
||||
|
||||
build-core:
|
||||
strategy:
|
||||
@@ -81,24 +81,28 @@ jobs:
|
||||
runs-on: ${{ matrix.uses }}
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
- name: 📥 Clone repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v3
|
||||
- name: 📥 Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
- name: 📥 Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||
|
||||
- name: Run tests
|
||||
- name: ⚒️ Build
|
||||
run: |
|
||||
./gradlew --configure-on-demand :core:assemble
|
||||
|
||||
- name: 🧪 Run tests
|
||||
run: |
|
||||
./gradlew --configure-on-demand :core:test
|
||||
|
||||
- name: Parse test reports
|
||||
- name: 🧪 Parse test reports
|
||||
run: python3 ./tools/parse-reports.py
|
||||
if: ${{ failure() }}
|
||||
|
19
.github/workflows/make-doc.sh
vendored
19
.github/workflows/make-doc.sh
vendored
@@ -1,19 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eu
|
||||
|
||||
DEST="${GITHUB_REF#refs/*/}"
|
||||
echo "Uploading docs to https://tweaked.cc/$DEST"
|
||||
|
||||
# Setup ssh key
|
||||
mkdir -p "$HOME/.ssh/"
|
||||
echo "$SSH_KEY" > "$HOME/.ssh/key"
|
||||
chmod 600 "$HOME/.ssh/key"
|
||||
|
||||
# And upload
|
||||
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
|
||||
"$GITHUB_WORKSPACE/projects/web/build/site/" \
|
||||
"$SSH_USER@$SSH_HOST:/$DEST"
|
||||
rsync -avc -e "ssh -i $HOME/.ssh/key -o StrictHostKeyChecking=no -p $SSH_PORT" \
|
||||
"$GITHUB_WORKSPACE/projects/common-api/build/docs/javadoc/" \
|
||||
"$SSH_USER@$SSH_HOST:/$DEST/javadoc"
|
34
.github/workflows/make-doc.yml
vendored
34
.github/workflows/make-doc.yml
vendored
@@ -3,8 +3,7 @@ name: Build documentation
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- mc-1.19.x
|
||||
- mc-1.20.x
|
||||
- mc-*
|
||||
|
||||
jobs:
|
||||
make_doc:
|
||||
@@ -12,30 +11,25 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
- name: 📥 Clone repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Java
|
||||
uses: actions/setup-java@v1
|
||||
- name: 📥 Set up Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
- name: 📥 Setup Gradle
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew compileJava --no-daemon || ./gradlew compileJava --no-daemon
|
||||
- name: ⚒️ Generate documentation
|
||||
run: ./gradlew docWebsite --no-daemon
|
||||
|
||||
- name: Generate documentation
|
||||
run: ./gradlew docWebsite :common-api:javadoc --no-daemon
|
||||
|
||||
- name: Upload documentation
|
||||
run: .github/workflows/make-doc.sh 2> /dev/null
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.SSH_KEY }}
|
||||
SSH_USER: ${{ secrets.SSH_USER }}
|
||||
SSH_HOST: ${{ secrets.SSH_HOST }}
|
||||
SSH_PORT: ${{ secrets.SSH_PORT }}
|
||||
- name: 📤 Upload Jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Documentation
|
||||
path: ./projects/web/build/site/
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,7 +7,9 @@
|
||||
/logs
|
||||
/build
|
||||
/projects/*/logs
|
||||
/projects/fabric/fabricloader.log
|
||||
/projects/*/build
|
||||
/projects/*/src/test/generated_tests/
|
||||
/buildSrc/build
|
||||
/out
|
||||
/buildSrc/out
|
||||
|
26
.gitpod.yml
26
.gitpod.yml
@@ -1,26 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
image:
|
||||
file: config/gitpod/Dockerfile
|
||||
|
||||
ports:
|
||||
- port: 25565
|
||||
onOpen: notify
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
- eamodio.gitlens
|
||||
- github.vscode-pull-request-github
|
||||
- ms-azuretools.vscode-docker
|
||||
- redhat.java
|
||||
- richardwillis.vscode-gradle
|
||||
- vscjava.vscode-java-debug
|
||||
- vscode.github
|
||||
|
||||
tasks:
|
||||
- name: Setup pre-commit hool
|
||||
init: pre-commit install --allow-missing-config
|
||||
- name: Install npm packages
|
||||
init: npm ci
|
@@ -27,7 +27,7 @@ repos:
|
||||
exclude: "^(.*\\.(bat)|LICENSE)$"
|
||||
|
||||
- repo: https://github.com/fsfe/reuse-tool
|
||||
rev: v2.1.0
|
||||
rev: v4.0.3
|
||||
hooks:
|
||||
- id: reuse
|
||||
|
||||
@@ -44,7 +44,7 @@ repos:
|
||||
name: Check Java codestyle
|
||||
files: ".*\\.java$"
|
||||
language: system
|
||||
entry: ./gradlew checkstyleMain checkstyleTest
|
||||
entry: ./gradlew checkstyle
|
||||
pass_filenames: false
|
||||
require_serial: true
|
||||
- id: illuaminate
|
||||
|
87
.reuse/dep5
87
.reuse/dep5
@@ -1,87 +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_upgrades/*
|
||||
projects/common/src/testMod/resources/data/cctest/structures/*
|
||||
projects/fabric/src/generated/*
|
||||
projects/forge/src/generated/*
|
||||
projects/web/src/export/index.json
|
||||
projects/web/src/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/web/src/mount/.settings
|
||||
projects/web/src/mount/example.nfp
|
||||
projects/web/src/mount/example.nft
|
||||
projects/web/src/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/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/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/*
|
||||
Comment: Community-contributed license files
|
||||
Copyright: 2017 The CC: Tweaked Developers
|
||||
License: LicenseRef-CCPL
|
||||
|
||||
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
|
@@ -12,7 +12,6 @@ If you've any other questions, [just ask the community][community] or [open an i
|
||||
|
||||
## Table of Contents
|
||||
- [Reporting issues](#reporting-issues)
|
||||
- [Translations](#translations)
|
||||
- [Setting up a development environment](#setting-up-a-development-environment)
|
||||
- [Developing CC: Tweaked](#developing-cc-tweaked)
|
||||
- [Writing documentation](#writing-documentation)
|
||||
@@ -21,17 +20,13 @@ If you've any other questions, [just ask the community][community] or [open an i
|
||||
If you have a bug, suggestion, or other feedback, the best thing to do is [file an issue][new-issue]. When doing so, do
|
||||
use the issue templates - they provide a useful hint on what information to provide.
|
||||
|
||||
## Translations
|
||||
Translations are managed through [Weblate], an online interface for managing language strings. This is synced
|
||||
automatically with GitHub, so please don't submit PRs adding/changing translations!
|
||||
|
||||
## Setting up a development environment
|
||||
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
|
||||
|
||||
- Make sure you've got the following software installed:
|
||||
- Java Development Kit (JDK) installed. This can be downloaded from [Adoptium].
|
||||
- Java Development Kit 17 (JDK). This can be downloaded from [Adoptium].
|
||||
- [Git](https://git-scm.com/).
|
||||
- If you want to work on documentation, [NodeJS][node].
|
||||
- [NodeJS 20 or later][node].
|
||||
|
||||
- Download CC: Tweaked's source code:
|
||||
```
|
||||
@@ -100,9 +95,7 @@ about how you can build on that until you've covered everything!
|
||||
[new-issue]: https://github.com/cc-tweaked/CC-Tweaked/issues/new/choose "Create a new issue"
|
||||
[community]: README.md#community "Get in touch with the community."
|
||||
[Adoptium]: https://adoptium.net/temurin/releases?version=17 "Download OpenJDK 17"
|
||||
[checkstyle]: https://checkstyle.org/
|
||||
[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"
|
||||
[ldoc]: http://stevedonovan.github.io/ldoc/ "ldoc, a Lua documentation generator."
|
||||
[mc-test]: https://www.youtube.com/watch?v=vXaWOJTCYNg
|
||||
|
16
README.md
16
README.md
@@ -26,8 +26,9 @@ developing the mod, [check out the instructions here](CONTRIBUTING.md#developing
|
||||
|
||||
## 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 [forum] and [GitHub discussions page][GitHub discussions]! There's also a fairly
|
||||
populated, albeit quiet [IRC channel][irc], if that's more your cup of tea.
|
||||
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].
|
||||
|
||||
We also host fairly comprehensive documentation at [tweaked.cc](https://tweaked.cc/ "The CC: Tweaked website").
|
||||
|
||||
@@ -39,10 +40,9 @@ on is present.
|
||||
```groovy
|
||||
repositories {
|
||||
maven {
|
||||
url "https://squiddev.cc/maven/"
|
||||
url "https://maven.squiddev.cc"
|
||||
content {
|
||||
includeGroup("cc.tweaked")
|
||||
includeModule("org.squiddev", "Cobalt")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,8 +76,8 @@ minecraft {
|
||||
```
|
||||
|
||||
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, file an issue, and we can look into
|
||||
exposing more features.
|
||||
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!
|
||||
|
||||
We bundle the API sources with the jar, so documentation should be easily viewable within your editor. Alternatively,
|
||||
the generated documentation [can be browsed online](https://tweaked.cc/javadoc/).
|
||||
@@ -87,6 +87,6 @@ the generated documentation [can be browsed online](https://tweaked.cc/javadoc/)
|
||||
[modrinth]: https://modrinth.com/mod/gu7yAYhd "Download CC: Tweaked from Modrinth"
|
||||
[Minecraft Forge]: https://files.minecraftforge.net/ "Download Minecraft Forge."
|
||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
||||
[forum]: https://forums.computercraft.cc/
|
||||
[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"
|
||||
|
110
REUSE.toml
Normal file
110
REUSE.toml
Normal file
@@ -0,0 +1,110 @@
|
||||
# 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]]
|
||||
# Generated/data files are CC0.
|
||||
SPDX-FileCopyrightText = "The CC: Tweaked Developers"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
path = [
|
||||
"gradle/gradle-daemon-jvm.properties",
|
||||
"projects/common/src/main/resources/assets/computercraft/sounds.json",
|
||||
"projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg",
|
||||
"projects/common/src/testMod/resources/data/cctest/computercraft/turtle_upgrades/**",
|
||||
"projects/common/src/testMod/resources/data/cctest/structures/**",
|
||||
"projects/**/src/generated/**",
|
||||
"projects/web/src/htmlTransform/export/index.json",
|
||||
"projects/web/src/htmlTransform/export/items/minecraft/**",
|
||||
]
|
||||
|
||||
[[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/common/src/client/resources/computercraft-client.mixins.json",
|
||||
"projects/common/src/main/resources/assets/minecraft/shaders/core/computercraft/monitor_tbo.json",
|
||||
"projects/common/src/main/resources/computercraft.mixins.json",
|
||||
"projects/common/src/testMod/resources/computercraft-gametest.mixins.json",
|
||||
"projects/common/src/testMod/resources/data/computercraft/loot_tables/treasure_disk.json",
|
||||
"projects/common/src/testMod/resources/pack.mcmeta",
|
||||
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/command/.ignoreme",
|
||||
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/.ignoreme",
|
||||
"projects/core/src/main/resources/data/computercraft/lua/rom/modules/turtle/.ignoreme",
|
||||
"projects/core/src/main/resources/data/computercraft/lua/rom/motd.txt",
|
||||
"projects/fabric-api/src/main/modJson/fabric.mod.json",
|
||||
"projects/fabric/src/client/resources/computercraft-client.fabric.mixins.json",
|
||||
"projects/fabric/src/main/resources/computercraft.fabric.mixins.json",
|
||||
"projects/fabric/src/main/resources/fabric.mod.json",
|
||||
"projects/fabric/src/testMod/resources/computercraft-gametest.fabric.mixins.json",
|
||||
"projects/fabric/src/testMod/resources/fabric.mod.json",
|
||||
"projects/forge/src/client/resources/computercraft-client.forge.mixins.json",
|
||||
"projects/web/src/frontend/mount/.settings",
|
||||
"projects/web/src/frontend/mount/example.nfp",
|
||||
"projects/web/src/frontend/mount/example.nft",
|
||||
"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 license 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 license files
|
||||
SPDX-FileCopyrightText = "2017 The CC: Tweaked Developers"
|
||||
SPDX-License-Identifier = "MPL-2.0"
|
||||
path = "projects/common/src/main/resources/assets/computercraft/lang/**"
|
||||
|
||||
[[annotations]]
|
||||
# GitHub build scripts are CC0. While we could add a header to each file,
|
||||
# it's unclear if it will break actions or issue templates in some way.
|
||||
SPDX-FileCopyrightText = "Jonathan Coates <git@squiddev.cc>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
path = ".github/**"
|
||||
|
||||
[[annotations]]
|
||||
path = ["gradle/wrapper/**"]
|
||||
SPDX-FileCopyrightText = "Gradle Inc"
|
||||
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"
|
@@ -2,13 +2,18 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import org.jetbrains.gradle.ext.compiler
|
||||
import org.jetbrains.gradle.ext.settings
|
||||
import cc.tweaked.gradle.JUnitExt
|
||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI
|
||||
import net.fabricmc.loom.util.gradle.SourceSetHelper
|
||||
import org.jetbrains.gradle.ext.*
|
||||
import org.jetbrains.gradle.ext.Application
|
||||
|
||||
plugins {
|
||||
publishing
|
||||
alias(libs.plugins.taskTree)
|
||||
alias(libs.plugins.githubRelease)
|
||||
alias(libs.plugins.gradleVersions)
|
||||
alias(libs.plugins.versionCatalogUpdate)
|
||||
id("org.jetbrains.gradle.plugin.idea-ext")
|
||||
id("cc-tweaked")
|
||||
}
|
||||
@@ -38,6 +43,63 @@ githubRelease {
|
||||
|
||||
tasks.publish { dependsOn(tasks.githubRelease) }
|
||||
|
||||
idea.project.settings.runConfigurations {
|
||||
register<JUnitExt>("Core Tests") {
|
||||
vmParameters = "-ea"
|
||||
moduleName = "${idea.project.name}.core.test"
|
||||
packageName = ""
|
||||
}
|
||||
|
||||
register<JUnitExt>("CraftOS Tests") {
|
||||
vmParameters = "-ea"
|
||||
moduleName = "${idea.project.name}.core.test"
|
||||
className = "dan200.computercraft.core.ComputerTestDelegate"
|
||||
}
|
||||
|
||||
register<JUnitExt>("CraftOS Tests (Fast)") {
|
||||
vmParameters = "-ea -Dcc.skip_keywords=slow"
|
||||
moduleName = "${idea.project.name}.core.test"
|
||||
className = "dan200.computercraft.core.ComputerTestDelegate"
|
||||
}
|
||||
|
||||
register<JUnitExt>("Common Tests") {
|
||||
vmParameters = "-ea"
|
||||
moduleName = "${idea.project.name}.common.test"
|
||||
packageName = ""
|
||||
}
|
||||
|
||||
register<JUnitExt>("Fabric Tests") {
|
||||
val fabricProject = evaluationDependsOn(":fabric")
|
||||
val classPathGroup = fabricProject.extensions.getByType<LoomGradleExtensionAPI>().mods
|
||||
.joinToString(File.pathSeparator + File.pathSeparator) { modSettings ->
|
||||
SourceSetHelper.getClasspath(modSettings, project).joinToString(File.pathSeparator) { it.absolutePath }
|
||||
}
|
||||
|
||||
vmParameters = "-ea -Dfabric.classPathGroups=$classPathGroup"
|
||||
moduleName = "${idea.project.name}.fabric.test"
|
||||
packageName = ""
|
||||
}
|
||||
|
||||
register<JUnitExt>("Forge Tests") {
|
||||
vmParameters = "-ea"
|
||||
moduleName = "${idea.project.name}.forge.test"
|
||||
packageName = ""
|
||||
}
|
||||
|
||||
register<Application>("Standalone") {
|
||||
moduleName = "${idea.project.name}.standalone.main"
|
||||
mainClass = "cc.tweaked.standalone.Main"
|
||||
programParameters = "--resources=projects/core/src/main/resources --term=80x30 --allow-local-domains"
|
||||
}
|
||||
}
|
||||
|
||||
// Build with the IntelliJ, rather than through Gradle. This may require setting the "Compiler Output" option in
|
||||
// "Project Structure".
|
||||
idea.project.settings.delegateActions {
|
||||
delegateBuildRunToGradle = false
|
||||
testRunner = ActionDelegationConfig.TestRunner.PLATFORM
|
||||
}
|
||||
|
||||
idea.project.settings.compiler.javac {
|
||||
// We want ErrorProne to be present when compiling via IntelliJ, as it offers some helpful warnings
|
||||
// and errors. Loop through our source sets and find the appropriate flags.
|
||||
@@ -54,3 +116,9 @@ idea.project.settings.compiler.javac {
|
||||
}
|
||||
.toMap()
|
||||
}
|
||||
|
||||
versionCatalogUpdate {
|
||||
sortByKey.set(false)
|
||||
pin { versions.addAll("fastutil", "guava", "netty", "slf4j") }
|
||||
keep { keepUnusedLibraries.set(true) }
|
||||
}
|
||||
|
@@ -5,6 +5,8 @@
|
||||
plugins {
|
||||
`java-gradle-plugin`
|
||||
`kotlin-dsl`
|
||||
alias(libs.plugins.gradleVersions)
|
||||
alias(libs.plugins.versionCatalogUpdate)
|
||||
}
|
||||
|
||||
// Duplicated in settings.gradle.kts
|
||||
@@ -27,19 +29,19 @@ repositories {
|
||||
}
|
||||
}
|
||||
|
||||
maven("https://repo.spongepowered.org/repository/maven-public/") {
|
||||
name = "Sponge"
|
||||
content {
|
||||
includeGroup("org.spongepowered")
|
||||
}
|
||||
}
|
||||
|
||||
maven("https://maven.fabricmc.net/") {
|
||||
name = "Fabric"
|
||||
content {
|
||||
includeGroup("net.fabricmc")
|
||||
}
|
||||
}
|
||||
|
||||
maven("https://maven.squiddev.cc") {
|
||||
name = "SquidDev"
|
||||
content {
|
||||
includeGroup("cc.tweaked.vanilla-extract")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -50,10 +52,10 @@ dependencies {
|
||||
implementation(libs.curseForgeGradle)
|
||||
implementation(libs.fabric.loom)
|
||||
implementation(libs.forgeGradle)
|
||||
implementation(libs.ideaExt)
|
||||
implementation(libs.librarian)
|
||||
implementation(libs.minotaur)
|
||||
implementation(libs.quiltflower)
|
||||
implementation(libs.vanillaGradle)
|
||||
implementation(libs.vanillaExtract)
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
@@ -74,3 +76,9 @@ gradlePlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
versionCatalogUpdate {
|
||||
sortByKey.set(false)
|
||||
keep { keepUnusedLibraries.set(true) }
|
||||
catalogFile.set(file("../gradle/libs.versions.toml"))
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ import cc.tweaked.gradle.MinecraftConfigurations
|
||||
plugins {
|
||||
`java-library`
|
||||
id("fabric-loom")
|
||||
id("io.github.juuxel.loom-quiltflower")
|
||||
id("cc-tweaked.java-convention")
|
||||
}
|
||||
|
||||
|
@@ -38,12 +38,8 @@ java {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
val mainMaven = maven("https://squiddev.cc/maven") {
|
||||
val mainMaven = maven("https://maven.squiddev.cc/mirror") {
|
||||
name = "SquidDev"
|
||||
content {
|
||||
// Until https://github.com/SpongePowered/Mixin/pull/593 is merged
|
||||
includeModule("org.spongepowered", "mixin")
|
||||
}
|
||||
}
|
||||
|
||||
exclusiveContent {
|
||||
@@ -57,8 +53,8 @@ repositories {
|
||||
|
||||
filter {
|
||||
includeGroup("cc.tweaked")
|
||||
includeModule("org.squiddev", "Cobalt")
|
||||
// Things we mirror
|
||||
includeGroup("com.simibubi.create")
|
||||
includeGroup("commoble.morered")
|
||||
includeGroup("dev.architectury")
|
||||
includeGroup("dev.emi")
|
||||
@@ -66,6 +62,7 @@ repositories {
|
||||
includeGroup("me.shedaniel.cloth")
|
||||
includeGroup("me.shedaniel")
|
||||
includeGroup("mezz.jei")
|
||||
includeGroup("org.teavm")
|
||||
includeModule("com.terraformersmc", "modmenu")
|
||||
includeModule("me.lucko", "fabric-permissions-api")
|
||||
}
|
||||
@@ -76,6 +73,12 @@ dependencies {
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
checkstyle(libs.findLibrary("checkstyle").get())
|
||||
|
||||
constraints {
|
||||
checkstyle("org.codehaus.plexus:plexus-container-default:2.1.1") {
|
||||
because("2.1.0 depends on deprecated Google collections module")
|
||||
}
|
||||
}
|
||||
|
||||
errorprone(libs.findLibrary("errorProne-core").get())
|
||||
errorprone(libs.findLibrary("nullAway").get())
|
||||
}
|
||||
@@ -92,18 +95,22 @@ sourceSets.all {
|
||||
check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
|
||||
// Too many false positives right now. Maybe we need an indirection for it later on.
|
||||
check("ReferenceEquality", CheckSeverity.OFF)
|
||||
check("UnusedVariable", CheckSeverity.OFF) // Too many false positives with records.
|
||||
check("EnumOrdinal", CheckSeverity.OFF) // For now. We could replace most of these with EnumMap.
|
||||
check("OperatorPrecedence", CheckSeverity.OFF) // For now.
|
||||
check("AlreadyChecked", CheckSeverity.OFF) // Seems to be broken?
|
||||
check("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
|
||||
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
|
||||
|
||||
check("NullAway", CheckSeverity.ERROR)
|
||||
option("NullAway:AnnotatedPackages", listOf("dan200.computercraft", "net.fabricmc.fabric.api").joinToString(","))
|
||||
option(
|
||||
"NullAway:AnnotatedPackages",
|
||||
listOf("dan200.computercraft", "cc.tweaked", "net.fabricmc.fabric.api").joinToString(","),
|
||||
)
|
||||
option("NullAway:ExcludedFieldAnnotations", listOf("org.spongepowered.asm.mixin.Shadow").joinToString(","))
|
||||
option("NullAway:CastToNonNullMethod", "dan200.computercraft.core.util.Nullability.assertNonNull")
|
||||
option("NullAway:CheckOptionalEmptiness")
|
||||
option("NullAway:AcknowledgeRestrictiveAnnotations")
|
||||
|
||||
excludedPaths = ".*/jmh_generated/.*"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,8 +134,8 @@ tasks.processResources {
|
||||
tasks.withType(AbstractArchiveTask::class.java).configureEach {
|
||||
isPreserveFileTimestamps = false
|
||||
isReproducibleFileOrder = true
|
||||
dirMode = Integer.valueOf("755", 8)
|
||||
fileMode = Integer.valueOf("664", 8)
|
||||
filePermissions {}
|
||||
dirPermissions {}
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
@@ -174,6 +181,12 @@ project.plugins.withType(CCTweakedPlugin::class.java) {
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("checkstyle") {
|
||||
description = "Run Checkstyle on all sources"
|
||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
dependsOn(tasks.withType(Checkstyle::class.java))
|
||||
}
|
||||
|
||||
spotless {
|
||||
encoding = StandardCharsets.UTF_8
|
||||
lineEndings = LineEnding.UNIX
|
||||
@@ -191,6 +204,8 @@ spotless {
|
||||
|
||||
val ktlintConfig = mapOf(
|
||||
"ktlint_standard_no-wildcard-imports" to "disabled",
|
||||
"ktlint_standard_class-naming" to "disabled",
|
||||
"ktlint_standard_function-naming" to "disabled",
|
||||
"ij_kotlin_allow_trailing_comma" to "true",
|
||||
"ij_kotlin_allow_trailing_comma_on_call_site" to "true",
|
||||
)
|
||||
|
@@ -32,7 +32,7 @@ val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
|
||||
apiToken = findProperty("curseForgeApiKey") ?: ""
|
||||
enabled = apiToken != ""
|
||||
|
||||
val mainFile = upload("282001", modPublishing.output.get().archiveFile)
|
||||
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"
|
||||
|
@@ -38,7 +38,7 @@ publishing {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://squiddev.cc/maven") {
|
||||
maven("https://maven.squiddev.cc") {
|
||||
name = "SquidDev"
|
||||
|
||||
credentials(PasswordCredentials::class)
|
||||
|
@@ -10,25 +10,31 @@ import cc.tweaked.gradle.MinecraftConfigurations
|
||||
|
||||
plugins {
|
||||
id("cc-tweaked.java-convention")
|
||||
id("org.spongepowered.gradle.vanilla")
|
||||
id("cc.tweaked.vanilla-extract")
|
||||
}
|
||||
|
||||
plugins.apply(CCTweakedPlugin::class.java)
|
||||
|
||||
val mcVersion: String by extra
|
||||
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
|
||||
minecraft {
|
||||
version(mcVersion)
|
||||
|
||||
mappings {
|
||||
parchment(libs.findVersion("parchmentMc").get().toString(), libs.findVersion("parchment").get().toString())
|
||||
}
|
||||
|
||||
unpick(libs.findLibrary("yarn").get())
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs")
|
||||
|
||||
// Depend on error prone annotations to silence a lot of compile warnings.
|
||||
compileOnlyApi(libs.findLibrary("errorProne.annotations").get())
|
||||
compileOnly(libs.findLibrary("errorProne.annotations").get())
|
||||
}
|
||||
|
||||
MinecraftConfigurations.setup(project)
|
||||
MinecraftConfigurations.setupBasic(project)
|
||||
|
||||
extensions.configure(CCTweakedExtension::class.java) {
|
||||
linters(minecraft = true, loader = null)
|
||||
|
@@ -10,9 +10,11 @@ import org.gradle.api.GradleException
|
||||
import org.gradle.api.NamedDomainObjectProvider
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.attributes.TestSuiteType
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.reporting.ReportingExtension
|
||||
@@ -20,7 +22,6 @@ import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.configurationcache.extensions.capitalized
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.gradle.process.JavaForkOptions
|
||||
@@ -33,7 +34,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.net.URI
|
||||
import java.net.URL
|
||||
import java.util.regex.Pattern
|
||||
|
||||
abstract class CCTweakedExtension(
|
||||
@@ -73,11 +73,17 @@ abstract class CCTweakedExtension(
|
||||
*/
|
||||
val sourceDirectories: SetProperty<SourceSetReference> = project.objects.setProperty(SourceSetReference::class.java)
|
||||
|
||||
/**
|
||||
* Dependencies excluded from published artifacts.
|
||||
*/
|
||||
private val excludedDeps: ListProperty<Dependency> = project.objects.listProperty(Dependency::class.java)
|
||||
|
||||
/** All source sets referenced by this project. */
|
||||
val sourceSets = sourceDirectories.map { x -> x.map { it.sourceSet } }
|
||||
|
||||
init {
|
||||
sourceDirectories.finalizeValueOnRead()
|
||||
excludedDeps.finalizeValueOnRead()
|
||||
project.afterEvaluate { sourceDirectories.disallowChanges() }
|
||||
}
|
||||
|
||||
@@ -173,8 +179,8 @@ abstract class CCTweakedExtension(
|
||||
}
|
||||
|
||||
fun <T> jacoco(task: NamedDomainObjectProvider<T>) where T : Task, T : JavaForkOptions {
|
||||
val classDump = project.buildDir.resolve("jacocoClassDump/${task.name}")
|
||||
val reportTaskName = "jacoco${task.name.capitalized()}Report"
|
||||
val classDump = project.layout.buildDirectory.dir("jacocoClassDump/${task.name}")
|
||||
val reportTaskName = "jacoco${task.name.capitalise()}Report"
|
||||
|
||||
val jacoco = project.extensions.getByType(JacocoPluginExtension::class.java)
|
||||
task.configure {
|
||||
@@ -185,7 +191,7 @@ abstract class CCTweakedExtension(
|
||||
jacoco.applyTo(this)
|
||||
extensions.configure(JacocoTaskExtension::class.java) {
|
||||
includes = listOf("dan200.computercraft.*")
|
||||
classDumpDir = classDump
|
||||
classDumpDir = classDump.get().asFile
|
||||
|
||||
// Older versions of modlauncher don't include a protection domain (and thus no code
|
||||
// source). Jacoco skips such classes by default, so we need to explicitly include them.
|
||||
@@ -218,12 +224,12 @@ abstract class CCTweakedExtension(
|
||||
* where possible.
|
||||
*/
|
||||
fun downloadFile(label: String, url: String): File {
|
||||
val url = URL(url)
|
||||
val path = File(url.path)
|
||||
val uri = URI(url)
|
||||
val path = File(uri.path)
|
||||
|
||||
project.repositories.ivy {
|
||||
name = label
|
||||
setUrl(URI(url.protocol, url.userInfo, url.host, url.port, path.parent, null, null))
|
||||
setUrl(URI(uri.scheme, uri.userInfo, uri.host, uri.port, path.parent, null, null))
|
||||
patternLayout {
|
||||
artifact("[artifact].[ext]")
|
||||
}
|
||||
@@ -246,6 +252,20 @@ abstract class CCTweakedExtension(
|
||||
).resolve().single()
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude a dependency from being published in Maven.
|
||||
*/
|
||||
fun exclude(dep: Dependency) {
|
||||
excludedDeps.add(dep)
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a [MavenDependencySpec].
|
||||
*/
|
||||
fun configureExcludes(spec: MavenDependencySpec) {
|
||||
for (dep in excludedDeps.get()) spec.exclude(dep)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val COMMIT_COUNTS = Pattern.compile("""^\s*[0-9]+\s+(.*)$""")
|
||||
private val IGNORED_USERS = setOf(
|
||||
|
@@ -9,6 +9,10 @@ import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||
import org.gradle.plugins.ide.idea.model.IdeaModel
|
||||
import org.jetbrains.gradle.ext.IdeaExtPlugin
|
||||
import org.jetbrains.gradle.ext.runConfigurations
|
||||
import org.jetbrains.gradle.ext.settings
|
||||
|
||||
/**
|
||||
* Configures projects to match a shared configuration.
|
||||
@@ -21,6 +25,20 @@ class CCTweakedPlugin : Plugin<Project> {
|
||||
val sourceSets = project.extensions.getByType(JavaPluginExtension::class.java).sourceSets
|
||||
cct.sourceDirectories.add(SourceSetReference.internal(sourceSets.getByName("main")))
|
||||
}
|
||||
|
||||
project.plugins.withType(IdeaExtPlugin::class.java) { extendIdea(project) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the [IdeaExtPlugin] plugin's `runConfiguration` container to also support [JUnitExt].
|
||||
*/
|
||||
private fun extendIdea(project: Project) {
|
||||
val ideaModel = project.extensions.findByName("idea") as IdeaModel? ?: return
|
||||
val ideaProject = ideaModel.project ?: return
|
||||
|
||||
ideaProject.settings.runConfigurations {
|
||||
registerFactory(JUnitExt::class.java) { name -> project.objects.newInstance(JUnitExt::class.java, name) }
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@@ -0,0 +1,92 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||
import org.gradle.api.artifacts.component.ModuleComponentSelector
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||
import org.gradle.api.artifacts.result.DependencyResult
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
|
||||
abstract class DependencyCheck : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val configuration: ListProperty<Configuration>
|
||||
|
||||
/**
|
||||
* A mapping of module coordinates (`group:module`) to versions, overriding the requested version.
|
||||
*/
|
||||
@get:Input
|
||||
abstract val overrides: MapProperty<String, String>
|
||||
|
||||
init {
|
||||
description = "Check :core's dependencies are consistent with Minecraft's."
|
||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
|
||||
configuration.finalizeValueOnRead()
|
||||
overrides.finalizeValueOnRead()
|
||||
}
|
||||
|
||||
/**
|
||||
* Override a module with a different version.
|
||||
*/
|
||||
fun override(module: Provider<MinimalExternalModuleDependency>, version: String) {
|
||||
overrides.putAll(project.provider { mutableMapOf(module.get().module.toString() to version) })
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
var ok = true
|
||||
for (configuration in configuration.get()) {
|
||||
configuration.incoming.resolutionResult.allDependencies {
|
||||
if (!check(this@allDependencies)) ok = false
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
throw GradleException("Mismatched versions in Minecraft dependencies. gradle/libs.versions.toml may need updating.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun check(dependency: DependencyResult): Boolean {
|
||||
if (dependency !is ResolvedDependencyResult) {
|
||||
logger.warn("Found unexpected dependency result {}", dependency)
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip dependencies on non-modules.
|
||||
val requested = dependency.requested
|
||||
if (requested !is ModuleComponentSelector) return true
|
||||
|
||||
// If this dependency is specified within some project (so is non-transitive), or is pulled in via Minecraft,
|
||||
// then check for consistency.
|
||||
// It would be nice to be smarter about transitive dependencies, but avoiding false positives is hard.
|
||||
val from = dependency.from.id
|
||||
if (
|
||||
from is ProjectComponentIdentifier ||
|
||||
from is ModuleComponentIdentifier && (from.group == "net.minecraft" || from.group == "io.netty")
|
||||
) {
|
||||
// If the version is different between the requested and selected version, report an error.
|
||||
val selected = dependency.selected.moduleVersion!!.version
|
||||
val requestedVersion = overrides.get()["${requested.group}:${requested.module}"] ?: requested.version
|
||||
if (requestedVersion != selected) {
|
||||
logger.error("Requested dependency {} (via {}) but got version {}", requested, from, selected)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
@@ -4,6 +4,7 @@
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.AbstractExecTask
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
@@ -11,5 +12,5 @@ import java.io.File
|
||||
|
||||
abstract class ExecToDir : AbstractExecTask<ExecToDir>(ExecToDir::class.java) {
|
||||
@get:OutputDirectory
|
||||
abstract val output: Property<File>
|
||||
abstract val output: DirectoryProperty
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.api.file.FileSystemLocation
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.JavaExec
|
||||
@@ -124,3 +125,45 @@ class CloseScope : AutoCloseable {
|
||||
|
||||
/** Proxy method to avoid overload ambiguity. */
|
||||
fun <T> Property<T>.setProvider(provider: Provider<out T>) = set(provider)
|
||||
|
||||
/** Short-cut method to get the absolute path of a [FileSystemLocation] provider. */
|
||||
fun Provider<out FileSystemLocation>.getAbsolutePath(): String = get().asFile.absolutePath
|
||||
|
||||
/**
|
||||
* Get the version immediately after the provided version.
|
||||
*
|
||||
* For example, given "1.2.3", this will return "1.2.4".
|
||||
*/
|
||||
fun getNextVersion(version: String): String {
|
||||
// Split a version like x.y.z-SNAPSHOT into x.y.z and -SNAPSHOT
|
||||
val dashIndex = version.indexOf('-')
|
||||
val mainVersion = if (dashIndex < 0) version else version.substring(0, dashIndex)
|
||||
|
||||
// Find the last component in x.y.z and increment it.
|
||||
val lastIndex = mainVersion.lastIndexOf('.')
|
||||
if (lastIndex < 0) throw IllegalArgumentException("Cannot parse version format \"$version\"")
|
||||
val lastVersion = try {
|
||||
mainVersion.substring(lastIndex + 1).toInt()
|
||||
} catch (e: NumberFormatException) {
|
||||
throw IllegalArgumentException("Cannot parse version format \"$version\"", e)
|
||||
}
|
||||
|
||||
// Then append all components together.
|
||||
val out = StringBuilder()
|
||||
out.append(version, 0, lastIndex + 1)
|
||||
out.append(lastVersion + 1)
|
||||
if (dashIndex >= 0) out.append(version, dashIndex, version.length)
|
||||
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)
|
||||
}
|
||||
|
23
buildSrc/src/main/kotlin/cc/tweaked/gradle/IdeaExt.kt
Normal file
23
buildSrc/src/main/kotlin/cc/tweaked/gradle/IdeaExt.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import org.jetbrains.gradle.ext.JUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A version of [JUnit] with a functional [className].
|
||||
*
|
||||
* See [#92](https://github.com/JetBrains/gradle-idea-ext-plugin/issues/92).
|
||||
*/
|
||||
open class JUnitExt @Inject constructor(nameParam: String) : JUnit(nameParam) {
|
||||
override fun toMap(): MutableMap<String, *> {
|
||||
val map = HashMap(super.toMap())
|
||||
// Should be "class" instead of "className".
|
||||
// See https://github.com/JetBrains/intellij-community/blob/9ba394021dc73a3926f13d6d6cdf434f9ee7046d/plugins/junit/src/com/intellij/execution/junit/JUnitRunConfigurationImporter.kt#L39
|
||||
map["class"] = className
|
||||
return map
|
||||
}
|
||||
}
|
@@ -6,6 +6,8 @@ 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
|
||||
|
||||
@@ -26,8 +28,13 @@ class MavenDependencySpec {
|
||||
|
||||
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) &&
|
||||
(dep.name.isNullOrEmpty() || dep.name == it.artifactId) &&
|
||||
(name.isNullOrEmpty() || name == it.artifactId) &&
|
||||
(dep.version.isNullOrEmpty() || dep.version == it.version)
|
||||
}
|
||||
}
|
||||
|
120
buildSrc/src/main/kotlin/cc/tweaked/gradle/MergeTrees.kt
Normal file
120
buildSrc/src/main/kotlin/cc/tweaked/gradle/MergeTrees.kt
Normal file
@@ -0,0 +1,120 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import cc.tweaked.vanillaextract.core.util.MoreFiles
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.*
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.tasks.*
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Merge common files across multiple directories into one destination directory.
|
||||
*
|
||||
* This is intended for merging the generated resources from the Forge and Fabric projects. Files common between the two
|
||||
* are written to the global [output] directory, while distinct files are written to the per-source
|
||||
* [MergeTrees.Source.output] directory.
|
||||
*/
|
||||
abstract class MergeTrees : DefaultTask() {
|
||||
/**
|
||||
* A source directory to read from.
|
||||
*/
|
||||
interface Source {
|
||||
/**
|
||||
* The folder contianing all input files.
|
||||
*/
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
val input: ConfigurableFileTree
|
||||
|
||||
fun input(configure: Action<ConfigurableFileTree>) {
|
||||
configure.execute(input)
|
||||
}
|
||||
|
||||
/**
|
||||
* The folder to write files unique to this folder to.
|
||||
*/
|
||||
@get:OutputDirectory
|
||||
val output: DirectoryProperty
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of sources.
|
||||
*/
|
||||
@get:Nested
|
||||
abstract val sources: ListProperty<Source>
|
||||
|
||||
/**
|
||||
* Add and configure a new source.
|
||||
*/
|
||||
fun source(configure: Action<Source>) {
|
||||
val instance = objectFactory.newInstance(Source::class.java)
|
||||
configure.execute(instance)
|
||||
instance.output.disallowChanges()
|
||||
sources.add(instance)
|
||||
}
|
||||
|
||||
/**
|
||||
* The directory to write common files to.
|
||||
*/
|
||||
@get:OutputDirectory
|
||||
abstract val output: DirectoryProperty
|
||||
|
||||
@get:Inject
|
||||
protected abstract val objectFactory: ObjectFactory
|
||||
|
||||
@get:Inject
|
||||
protected abstract val fsOperations: FileSystemOperations
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val sources = this.sources.get()
|
||||
if (sources.isEmpty()) throw GradleException("Cannot have an empty list of sources")
|
||||
|
||||
val files = mutableMapOf<String, SharedFile>()
|
||||
for (source in sources) {
|
||||
source.input.visit(
|
||||
object : FileVisitor {
|
||||
override fun visitDir(dirDetails: FileVisitDetails) = Unit
|
||||
override fun visitFile(fileDetails: FileVisitDetails) {
|
||||
val path = fileDetails.file.toRelativeString(source.input.dir)
|
||||
val hash = MoreFiles.computeSha1(fileDetails.file.toPath())
|
||||
|
||||
val existing = files[path]
|
||||
if (existing == null) {
|
||||
files[path] = SharedFile(hash, 1)
|
||||
} else if (existing.hash == hash) {
|
||||
existing.found++
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val sharedFiles = files.entries.asSequence().filter { (_, v) -> v.found == sources.size }.map { (k, _) -> k }.toList()
|
||||
|
||||
// Copy shared files to the common directory
|
||||
fsOperations.sync {
|
||||
from(sources[0].input)
|
||||
into(output)
|
||||
include(sharedFiles)
|
||||
}
|
||||
|
||||
// And all other files to their per-source directory
|
||||
for (source in sources) {
|
||||
fsOperations.sync {
|
||||
from(source.input)
|
||||
into(source.output)
|
||||
exclude(sharedFiles)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SharedFile(val hash: String, var found: Int)
|
||||
}
|
@@ -4,23 +4,17 @@
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import cc.tweaked.vanillaextract.configurations.Capabilities
|
||||
import cc.tweaked.vanillaextract.configurations.MinecraftSetup
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ModuleDependency
|
||||
import org.gradle.api.artifacts.dsl.DependencyHandler
|
||||
import org.gradle.api.attributes.Bundling
|
||||
import org.gradle.api.attributes.Category
|
||||
import org.gradle.api.attributes.LibraryElements
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.attributes.java.TargetJvmVersion
|
||||
import org.gradle.api.capabilities.Capability
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.kotlin.dsl.get
|
||||
import org.gradle.kotlin.dsl.named
|
||||
|
||||
/**
|
||||
* This sets up a separate client-only source set, and extends that and the main/common source set with additional
|
||||
@@ -59,31 +53,13 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
}
|
||||
configurations.named(client.implementationConfigurationName) { extendsFrom(clientApi) }
|
||||
|
||||
/*
|
||||
Now add outgoing variants for the main and common source sets that we can consume downstream. This is possibly
|
||||
the worst way to do things, but unfortunately the alternatives don't actually work very well:
|
||||
|
||||
- Just using source set outputs: This means dependencies don't propagate, which means when :fabric depends
|
||||
on :fabric-api, we don't inherit the fake :common-api in IDEA.
|
||||
|
||||
- Having separate common/main jars: Nice in principle, but unfortunately Forge needs a separate deobf jar
|
||||
task (as the original jar is obfuscated), and IDEA is not able to map its output back to a source set.
|
||||
|
||||
This works for now, but is incredibly brittle. It's part of the reason we can't use testFixtures inside our
|
||||
MC projects, as that adds a project(self) -> test dependency, which would pull in the jar instead.
|
||||
|
||||
Note we register a fake client jar here. It's not actually needed, but is there to make sure IDEA has
|
||||
a way to tell that client classes are needed at runtime.
|
||||
|
||||
I'm so sorry, deeply aware how cursed this is.
|
||||
*/
|
||||
setupOutgoing(main, "CommonOnly")
|
||||
project.tasks.register(client.jarTaskName, Jar::class.java) {
|
||||
description = "An empty jar standing in for the client classes."
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
archiveClassifier.set("client")
|
||||
}
|
||||
setupOutgoing(client)
|
||||
|
||||
MinecraftSetup(project).setupOutgoingConfigurations()
|
||||
|
||||
// Reset the client classpath (Loom configures it slightly differently to this) and add a main -> client
|
||||
// dependency. Here we /can/ use source set outputs as we add transitive deps by patching the classpath. Nasty,
|
||||
@@ -106,88 +82,39 @@ class MinecraftConfigurations private constructor(private val project: Project)
|
||||
project.tasks.named("jar", Jar::class.java) { from(client.output) }
|
||||
project.tasks.named("sourcesJar", Jar::class.java) { from(client.allSource) }
|
||||
|
||||
setupBasic()
|
||||
}
|
||||
|
||||
private fun setupBasic() {
|
||||
val client = sourceSets["client"]
|
||||
|
||||
project.extensions.configure(CCTweakedExtension::class.java) {
|
||||
sourceDirectories.add(SourceSetReference.internal(client))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupOutgoing(sourceSet: SourceSet, suffix: String = "") {
|
||||
setupOutgoing("${sourceSet.apiElementsConfigurationName}$suffix", sourceSet, objects.named(Usage.JAVA_API)) {
|
||||
description = "API elements for ${sourceSet.name}"
|
||||
extendsFrom(configurations[sourceSet.apiConfigurationName])
|
||||
}
|
||||
|
||||
setupOutgoing("${sourceSet.runtimeElementsConfigurationName}$suffix", sourceSet, objects.named(Usage.JAVA_RUNTIME)) {
|
||||
description = "Runtime elements for ${sourceSet.name}"
|
||||
extendsFrom(configurations[sourceSet.implementationConfigurationName], configurations[sourceSet.runtimeOnlyConfigurationName])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up an outgoing configuration for a specific source set. We set an additional "main" or "client" capability
|
||||
* (depending on the source set name) which allows downstream projects to consume them separately (see
|
||||
* [DependencyHandler.commonClasses] and [DependencyHandler.clientClasses]).
|
||||
*/
|
||||
private fun setupOutgoing(name: String, sourceSet: SourceSet, usage: Usage, configure: Configuration.() -> Unit) {
|
||||
configurations.register(name) {
|
||||
isVisible = false
|
||||
isCanBeConsumed = true
|
||||
isCanBeResolved = false
|
||||
|
||||
configure(this)
|
||||
|
||||
attributes {
|
||||
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
||||
attribute(Usage.USAGE_ATTRIBUTE, usage)
|
||||
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
|
||||
attributeProvider(
|
||||
TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE,
|
||||
java.toolchain.languageVersion.map { it.asInt() },
|
||||
)
|
||||
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR))
|
||||
// Register a task to check there are no conflicts with the core project.
|
||||
val checkDependencyConsistency =
|
||||
project.tasks.register("checkDependencyConsistency", DependencyCheck::class.java) {
|
||||
// We need to check both the main and client classpath *configurations*, as the actual configuration
|
||||
configuration.add(configurations.named(main.runtimeClasspathConfigurationName))
|
||||
configuration.add(configurations.named(client.runtimeClasspathConfigurationName))
|
||||
}
|
||||
|
||||
outgoing {
|
||||
capability(BasicOutgoingCapability(project, sourceSet.name))
|
||||
|
||||
// We have two outgoing variants here: the original jar and the classes.
|
||||
artifact(project.tasks.named(sourceSet.jarTaskName))
|
||||
|
||||
variants.create("classes") {
|
||||
attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES))
|
||||
sourceSet.output.classesDirs.forEach { artifact(it) { builtBy(sourceSet.output) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
project.tasks.named("check") { dependsOn(checkDependencyConsistency) }
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun setupBasic(project: Project) {
|
||||
MinecraftConfigurations(project).setupBasic()
|
||||
}
|
||||
|
||||
fun setup(project: Project) {
|
||||
MinecraftConfigurations(project).setup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class BasicIncomingCapability(private val module: ModuleDependency, private val name: String) : Capability {
|
||||
override fun getGroup(): String = module.group!!
|
||||
override fun getName(): String = "${module.name}-$name"
|
||||
override fun getVersion(): String? = null
|
||||
}
|
||||
fun DependencyHandler.clientClasses(notation: Any): ModuleDependency =
|
||||
Capabilities.clientClasses(create(notation) as ModuleDependency)
|
||||
|
||||
private class BasicOutgoingCapability(private val project: Project, private val name: String) : Capability {
|
||||
override fun getGroup(): String = project.group.toString()
|
||||
override fun getName(): String = "${project.name}-$name"
|
||||
override fun getVersion(): String = project.version.toString()
|
||||
}
|
||||
|
||||
fun DependencyHandler.clientClasses(notation: Any): ModuleDependency {
|
||||
val dep = create(notation) as ModuleDependency
|
||||
dep.capabilities { requireCapability(BasicIncomingCapability(dep, "client")) }
|
||||
return dep
|
||||
}
|
||||
|
||||
fun DependencyHandler.commonClasses(notation: Any): ModuleDependency {
|
||||
val dep = create(notation) as ModuleDependency
|
||||
dep.capabilities { requireCapability(BasicIncomingCapability(dep, "main")) }
|
||||
return dep
|
||||
}
|
||||
fun DependencyHandler.commonClasses(notation: Any): ModuleDependency =
|
||||
Capabilities.commonClasses(create(notation) as ModuleDependency)
|
||||
|
@@ -58,7 +58,7 @@ abstract class ClientJavaExec : JavaExec() {
|
||||
if (!clientDebug) systemProperty("cctest.client", "")
|
||||
if (renderdoc) environment("LD_PRELOAD", "/usr/lib/librenderdoc.so")
|
||||
systemProperty("cctest.gametest-report", testResults.get().asFile.absoluteFile)
|
||||
workingDir(project.buildDir.resolve("gametest").resolve(name))
|
||||
workingDir(project.layout.buildDirectory.dir("gametest/$name"))
|
||||
}
|
||||
|
||||
init {
|
||||
|
@@ -46,7 +46,7 @@ abstract class NpmInstall : DefaultTask() {
|
||||
@TaskAction
|
||||
fun install() {
|
||||
project.exec {
|
||||
commandLine("npm", "ci")
|
||||
commandLine(ProcessHelpers.getExecutable("npm"), "ci")
|
||||
workingDir = projectRoot.get().asFile
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,6 @@ abstract class NpmInstall : DefaultTask() {
|
||||
abstract class NpxExecToDir : ExecToDir() {
|
||||
init {
|
||||
dependsOn(NpmInstall.TASK_NAME)
|
||||
executable = "npx"
|
||||
executable = ProcessHelpers.getExecutable("npx")
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ import org.gradle.api.GradleException
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
internal object ProcessHelpers {
|
||||
fun startProcess(vararg command: String): Process {
|
||||
@@ -34,7 +35,7 @@ internal object ProcessHelpers {
|
||||
val process = startProcess(*command)
|
||||
process.outputStream.close()
|
||||
|
||||
val out = BufferedReader(InputStreamReader(process.inputStream)).use { reader ->
|
||||
val out = BufferedReader(InputStreamReader(process.inputStream, StandardCharsets.UTF_8)).use { reader ->
|
||||
reader.lines().filter { it.isNotEmpty() }.toList()
|
||||
}
|
||||
ProcessGroovyMethods.closeStreams(process)
|
||||
@@ -46,6 +47,28 @@ internal object ProcessHelpers {
|
||||
val path = System.getenv("PATH") ?: return false
|
||||
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for an executable on the `PATH` if required.
|
||||
*
|
||||
* [Process]/[ProcessBuilder] does not handle all executable file extensions on Windows (such as `.com). When on
|
||||
* Windows, this function searches `PATH` and `PATHEXT` for an executable matching [name].
|
||||
*/
|
||||
fun getExecutable(name: String): String {
|
||||
if (!System.getProperty("os.name").lowercase().contains("windows")) return name
|
||||
|
||||
val path = (System.getenv("PATH") ?: return name).split(File.pathSeparator)
|
||||
val pathExt = (System.getenv("PATHEXT") ?: return name).split(File.pathSeparator)
|
||||
|
||||
for (pathEntry in path) {
|
||||
for (ext in pathExt) {
|
||||
val resolved = File(pathEntry, name + ext)
|
||||
if (resolved.exists()) return resolved.getAbsolutePath()
|
||||
}
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Process.waitForOrThrow(message: String) {
|
||||
|
@@ -13,8 +13,12 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<property name="tabWidth" value="4"/>
|
||||
<property name="charset" value="UTF-8" />
|
||||
|
||||
<module name="BeforeExecutionExclusionFileFilter">
|
||||
<property name="fileNamePattern" value="module\-info\.java$"/>
|
||||
</module>
|
||||
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="${config_loc}/suppressions.xml" />
|
||||
<property name="file" value="${config_loc}/suppressions.xml" />
|
||||
</module>
|
||||
|
||||
<module name="BeforeExecutionExclusionFileFilter">
|
||||
@@ -112,7 +116,9 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<module name="LambdaParameterName" />
|
||||
<module name="LocalFinalVariableName" />
|
||||
<module name="LocalVariableName" />
|
||||
<module name="MemberName" />
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^\$?[a-z][a-zA-Z0-9]*$" />
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
<property name="format" value="^(computercraft\$)?[a-z][a-zA-Z0-9]*$" />
|
||||
</module>
|
||||
@@ -122,7 +128,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
</module>
|
||||
<module name="ParameterName" />
|
||||
<module name="StaticVariableName">
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*|CAPABILITY(_[A-Z_]+)?$" />
|
||||
<property name="format" value="^[a-z][a-zA-Z0-9]*$" />
|
||||
</module>
|
||||
<module name="TypeName" />
|
||||
|
||||
|
@@ -16,4 +16,10 @@ SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
<!-- The commands API is documented in Lua. -->
|
||||
<suppress checks="SummaryJavadocCheck" files=".*[\\/]CommandAPI.java" />
|
||||
|
||||
<!-- Allow putting files in other packages if they look like our TeaVM stubs. -->
|
||||
<suppress checks="PackageName" files=".*[\\/]T[A-Za-z]+.java" />
|
||||
|
||||
<!-- Allow underscores in our test classes. -->
|
||||
<suppress checks="MethodName" files=".*(Contract|Test).java" />
|
||||
</suppressions>
|
||||
|
@@ -1,12 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
FROM gitpod/workspace-base
|
||||
|
||||
USER gitpod
|
||||
|
||||
RUN sudo apt-get -q update \
|
||||
&& sudo apt-get install -yq openjdk-16-jdk python3-pip npm \
|
||||
&& sudo pip3 install pre-commit \
|
||||
&& sudo update-java-alternatives --set java-1.16.0-openjdk-amd64
|
@@ -6,7 +6,7 @@ see: key To listen to any key press.
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-CCPL
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
The [`char`] event is fired when a character is typed on the keyboard.
|
||||
|
@@ -12,7 +12,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
The [`file_transfer`] event is queued when a user drags-and-drops a file on an open computer.
|
||||
|
||||
This event contains a single argument of type [`TransferredFiles`], which can be used to [get the files to be
|
||||
transferred][`TransferredFiles.getFiles`]. Each file returned is a [binary file handle][`fs.BinaryReadHandle`] with an
|
||||
transferred][`TransferredFiles.getFiles`]. Each file returned is a [binary file handle][`fs.ReadHandle`] with an
|
||||
additional [getName][`TransferredFile.getName`] method.
|
||||
|
||||
## Return values
|
||||
@@ -29,7 +29,7 @@ for _, file in ipairs(files.getFiles()) do
|
||||
local size = file.seek("end")
|
||||
file.seek("set", 0)
|
||||
|
||||
print(file.getName() .. " " .. file.getSize())
|
||||
print(file.getName() .. " " .. size)
|
||||
end
|
||||
```
|
||||
|
||||
|
@@ -5,7 +5,7 @@ module: [kind=event] key
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-CCPL
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
This event is fired when any key is pressed while the terminal is focused.
|
||||
|
@@ -6,7 +6,7 @@ see: keys For a lookup table of the given keys.
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-CCPL
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
Fired whenever a key is released (or the terminal is closed while a key was being pressed).
|
||||
|
@@ -5,7 +5,7 @@ module: [kind=event] mouse_click
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-CCPL
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
This event is fired when the terminal is clicked with a mouse. This event is only fired on advanced computers (including
|
||||
|
@@ -6,7 +6,7 @@ see: mouse_click For when a mouse button is initially pressed.
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-CCPL
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
This event is fired every time the mouse is moved while a mouse button is being held.
|
||||
|
@@ -5,7 +5,7 @@ module: [kind=event] mouse_scroll
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-CCPL
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
This event is fired when a mouse wheel is scrolled in the terminal.
|
||||
|
@@ -5,7 +5,7 @@ module: [kind=event] mouse_up
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: LicenseRef-CCPL
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
This event is fired when a mouse button is released or a held mouse leaves the computer's terminal.
|
||||
|
@@ -19,7 +19,7 @@ In order to give the best results, a GPS constellation needs at least four compu
|
||||
constellation is redundant, but it does not cause problems.
|
||||
|
||||
## Building a GPS constellation
|
||||
<img alt="An example GPS constellation." src="/images/gps-constellation-example.png" class="big-image" />
|
||||
<img alt="An example GPS constellation." src="../images/gps-constellation-example.png" class="big-image" />
|
||||
|
||||
We are going to build our GPS constellation as shown in the image above. You will need 4 computers and either 4 wireless
|
||||
modems or 4 ender modems. Try not to mix ender and wireless modems together as you might get some odd behavior when your
|
||||
|
@@ -131,10 +131,10 @@ different.
|
||||
First, we require the dfpwm module and call [`cc.audio.dfpwm.make_decoder`] to construct a new decoder. This decoder
|
||||
accepts blocks of DFPWM data and converts it to a list of 8-bit amplitudes, which we can then play with our speaker.
|
||||
|
||||
As mentioned above, [`speaker.playAudio`] accepts at most 128×1024 samples in one go. DFPMW uses a single bit for each
|
||||
As mentioned above, [`speaker.playAudio`] accepts at most 128×1024 samples in one go. DFPWM uses a single bit for each
|
||||
sample, which means we want to process our audio in chunks of 16×1024 bytes (16KiB). In order to do this, we use
|
||||
[`io.lines`], which provides a nice way to loop over chunks of a file. You can of course just use [`fs.open`] and
|
||||
[`fs.BinaryReadHandle.read`] if you prefer.
|
||||
[`fs.ReadHandle.read`] if you prefer.
|
||||
|
||||
## Processing audio
|
||||
As mentioned near the beginning of this guide, PCM audio is pretty easy to work with as it's just a list of amplitudes.
|
||||
@@ -191,7 +191,7 @@ end
|
||||
|
||||
> [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
|
||||
> 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
|
||||
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"
|
||||
[Ring Buffer]: https://en.wikipedia.org/wiki/Circular_buffer "Circular buffer - Wikipedia"
|
||||
[Sine Wave]: https://en.wikipedia.org/wiki/Sine_wave "Sine wave - Wikipedia"
|
||||
[GitHub Discussions]: https://github.com/cc-tweaked/CC-Tweaked/discussions
|
||||
[IRC]: https://webchat.esper.net/?channels=computercraft "#computercraft on EsperNet"
|
||||
[Community]: /#community
|
||||
|
BIN
doc/images/computercraft-dump.png
Normal file
BIN
doc/images/computercraft-dump.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 254 KiB |
BIN
doc/images/computercraft-track.png
Normal file
BIN
doc/images/computercraft-track.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 304 KiB |
20
doc/index.md
20
doc/index.md
@@ -4,7 +4,14 @@ SPDX-FileCopyrightText: 2020 The CC: Tweaked Developers
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
# 
|
||||
<h1>
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="logo-darkmode.png">
|
||||
<source media="(prefers-color-scheme: light)" srcset="logo.png">
|
||||
<img alt="CC: Tweaked" src="logo.png">
|
||||
</picture>
|
||||
</h1>
|
||||
|
||||
CC: Tweaked is a mod for Minecraft which adds programmable computers, turtles and more to the game. A fork of the
|
||||
much-beloved [ComputerCraft], it continues its legacy with improved performance and stability, along with a wealth of
|
||||
new features.
|
||||
@@ -38,12 +45,16 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
|
||||
|
||||
- [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
|
||||
- [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
|
||||
- [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
||||
- [Lyqyd's Computer Basics 1](https://ccf.squiddev.cc/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please do [create an issue][bug].
|
||||
@@ -58,4 +69,5 @@ CC: Tweaked lives on [GitHub]. If you've got any ideas, feedback or bugs please
|
||||
[Fabric]: https://fabricmc.net/use/installer/ "Download Fabric."
|
||||
[lua]: https://www.lua.org/ "Lua's main website"
|
||||
[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"
|
||||
|
@@ -45,12 +45,16 @@ little daunting getting started. Thankfully, there's several fantastic tutorials
|
||||
|
||||
- [Direwolf20's ComputerCraft tutorials](https://www.youtube.com/watch?v=wrUHUhfCY5A "ComputerCraft Tutorial Episode 1 - HELP! and Hello World")
|
||||
- [Sethbling's ComputerCraft series](https://www.youtube.com/watch?v=DSsx4VSe-Uk "Programming Tutorial with Minecraft Turtles -- Ep. 1: Intro to Turtles and If-Then-Else_End")
|
||||
- [Lyqyd's Computer Basics 1](http://www.computercraft.info/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
||||
- [Lyqyd's Computer Basics 1](https://ccf.squiddev.cc/forums2/index.php?/topic/15033-computer-basics-i/ "Computer Basics I")
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
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"
|
||||
[lua]: https://www.lua.org/ "Lua's main website"
|
||||
[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"
|
||||
|
81
doc/reference/breaking_changes.md
Normal file
81
doc/reference/breaking_changes.md
Normal file
@@ -0,0 +1,81 @@
|
||||
---
|
||||
module: [kind=reference] breaking_changes
|
||||
---
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2019 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
# Incompatibilities between versions
|
||||
|
||||
CC: Tweaked tries to remain as compatible between versions as possible, meaning most programs written for older version
|
||||
of the mod should run fine on later versions.
|
||||
|
||||
> [External peripherals][!WARNING]
|
||||
>
|
||||
> While CC: Tweaked is relatively stable across versions, this may not be true for other mods which add their own
|
||||
> peripherals. Older programs which interact with external blocks may not work on newer versions of the game.
|
||||
|
||||
However, some changes to the underlying game, or CC: Tweaked's own internals may break some programs. This page serves
|
||||
as documentation for breaking changes and "gotchas" one should look out for between versions.
|
||||
|
||||
## CC: Tweaked 1.109.0 to 1.109.3 {#cct-1.109}
|
||||
|
||||
- Update to Lua 5.2:
|
||||
- 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`]
|
||||
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.
|
||||
- [`load`]/[`loadstring`] defaults to using the global environment (`_G`) rather than the current coroutine's
|
||||
environment.
|
||||
- Support for dumping functions ([`string.dump`]) and loading binary chunks has been removed.
|
||||
- [`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.
|
||||
|
||||
## Minecraft 1.13 {#mc-1.13}
|
||||
- The "key code" for [`key`] and [`key_up`] events has changed, due to Minecraft updating to LWJGL 3. Make sure you're
|
||||
using the constants provided by the [`keys`] API, rather than hard-coding numerical values.
|
||||
|
||||
Related to this change, the numpad enter key now has a different key code to the enter key. You may need to adjust
|
||||
your programs to handle both. (Note, the `keys.numpadEnter` constant was defined in pre-1.13 versions of CC, but the
|
||||
`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
|
||||
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
|
||||
more understandable format.
|
||||
|
||||
- Item and block names now represent a unique item type. For instance, wool is split into 16 separate items
|
||||
(`minecraft:white_wool`, etc...) rather than a single `minecraft:wool` with each meta/damage value specifying the
|
||||
colour.
|
||||
|
||||
- Custom ROMs are now provided using data packs rather than resource packs. This should mostly be a matter of renaming
|
||||
the "assets" folder to "data", and placing it in "datapacks", but there are a couple of other gotchas to look out
|
||||
for:
|
||||
|
||||
- Data packs [impose some restrictions on file names][legal_data_pack]. As a result, your programs and directories
|
||||
must all be lower case.
|
||||
- Due to how data packs are read by CC: Tweaked, you may need to use the `/reload` command to see changes to your
|
||||
pack show up on the computer.
|
||||
|
||||
See [the example datapack][datapack-example] for how to get started.
|
||||
|
||||
- Turtles can now be waterlogged and move "through" water sources rather than breaking them.
|
||||
|
||||
## CC: Tweaked 1.88.0 {#cc-1.88}
|
||||
- Unlabelled computers and turtles now keep their ID when broken, meaning that unlabelled computers/items do not stack.
|
||||
|
||||
## 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
|
||||
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,
|
||||
you can no longer type `turtle/excavate` to run `/rom/programs/turtle/excavate.lua`.
|
||||
|
||||
[flattening]: https://minecraft.wiki/w/Java_Edition_1.13/Flattening
|
||||
[legal_data_pack]: https://minecraft.wiki/w/Tutorials/Creating_a_data_pack#Legal_characters
|
||||
[datapack-example]: https://github.com/cc-tweaked/datapack-example "An example datapack for CC: Tweaked"
|
140
doc/reference/command.md
Normal file
140
doc/reference/command.md
Normal file
@@ -0,0 +1,140 @@
|
||||
---
|
||||
module: [kind=reference] computercraft_command
|
||||
---
|
||||
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
# The `/computercraft` command
|
||||
CC: Tweaked provides a `/computercraft` command for server owners to manage running computers on a server.
|
||||
|
||||
## Permissions {#permissions}
|
||||
As the `/computercraft` command is mostly intended for debugging and administrative purposes, its sub-commands typically
|
||||
require you to have op (or similar).
|
||||
|
||||
- All players have access to the [`queue`] sub-command.
|
||||
- On a multi-player server, all other commands require op.
|
||||
- On a single-player world, the player can run the [`dump`], [`turn-on`]/[`shutdown`], and [`track`] sub-commands, even
|
||||
when cheats are not enabled. The [`tp`] and [`view`] commands require cheats.
|
||||
|
||||
If a permission mod such as [LuckPerms] is installed[^permission], you can configure access to the individual
|
||||
sub-commands. Each sub-command creates a `computercraft.command.NAME` permission node to control which players can
|
||||
execute it.
|
||||
|
||||
[LuckPerms]: https://github.com/LuckPerms/LuckPerms/ "A permissions plugin for Minecraft servers."
|
||||
[fabric-permission-api]: https://github.com/lucko/fabric-permissions-api "A simple permissions API for Fabric"
|
||||
|
||||
[^permission]: This supports any mod which uses Forge's permission API or [fabric-permission-api].
|
||||
|
||||
## Computer selectors {#computer-selectors}
|
||||
Some commands (such as [`tp`] or [`turn-on`]) target a specific computer, or a list of computers. To specify which
|
||||
computers to operate on, you must use "computer selectors".
|
||||
|
||||
Computer selectors are similar to Minecraft's [entity target selectors], but targeting computers instead. They allow
|
||||
you to select one or more computers, based on a set of predicates.
|
||||
|
||||
The following predicates are supported:
|
||||
- `id=<id>`: Select computer(s) with a specific id.
|
||||
- `instance=<id>`: Select the computer with the given instance id.
|
||||
- `family=<normal|advanced|command>`: Select computers based on their type.
|
||||
- `label=<label>`: Select computers with the given label.
|
||||
- `distance=<distance>`: Select computers within a specific distance of the player executing the command. This uses
|
||||
Minecraft's [float range] syntax.
|
||||
|
||||
`#<id>` may also be used as a shorthand for `@c[id=<id>]`, to select computer(s) with a specific id.
|
||||
|
||||
### Examples:
|
||||
- `/computercraft turn-on #12`: Turn on the computer(s) with an id of 12.
|
||||
- `/computercraft shutdown @c[distance=..100]`: Shut down all computers with 100 blocks of the player.
|
||||
|
||||
[entity target selectors]: https://minecraft.wiki/w/Target_selectors "Target Selectors on the Minecraft wiki"
|
||||
[Float range]: https://minecraft.wiki/w/Argument_types#minecraft:float_range
|
||||
|
||||
## Commands {#commands}
|
||||
### `/computercraft dump` {#dump}
|
||||
`/computercraft dump` prints a table of currently loaded computers, including their id, position, and whether they're
|
||||
running. It can also be run with a single computer argument to dump more detailed information about a computer.
|
||||
|
||||

|
||||
|
||||
Next to the computer id, there are several buttons to either [teleport][`tp`] to the computer, or [open its terminal
|
||||
][`view`].
|
||||
|
||||
Computers are sorted by distance to the player, so nearby computers will appear earlier.
|
||||
|
||||
### `/computercraft turn-on [computers...]` {#turn-on}
|
||||
Turn on one or more computers or, if no run with no arguments, all loaded computers.
|
||||
|
||||
#### Examples
|
||||
- `/computercraft turn-on #0 #2`: Turn on computers with id 0 and 2.
|
||||
- `/computercraft turn-on @c[family=command]`: Turn on all command computers.
|
||||
|
||||
### `/computercraft shutdown [computers...]` {#shutdown}
|
||||
Shutdown one or more computers or, if no run with no arguments, all loaded computers.
|
||||
|
||||
This is sometimes useful when dealing with lag, as a way to ensure that ComputerCraft is not causing problems.
|
||||
|
||||
#### Examples
|
||||
- `/computercraft shutdown`: Shut down all loaded computers.
|
||||
- `/computercraft shutdown @c[distance=..10]`: Shut down all computers in a block radius.
|
||||
|
||||
### `/computercraft tp [computer]` {#tp}
|
||||
Teleport to the given computer.
|
||||
|
||||
This is normally used from via the [`dump`] command interface rather than being invoked directly.
|
||||
|
||||
### `/computercraft view [computer]` {#view}
|
||||
Open a terminal for the specified computer. This allows remotely viewing computers without having to interact with the
|
||||
block.
|
||||
|
||||
This is normally used from via the [`dump`] command interface rather than being invoked directly.
|
||||
|
||||
### `/computercraft track` {#track}
|
||||
The `/computercraft track` command allows you to enable profiling of computers. When a computer runs code, or interacts
|
||||
with the Minecraft world, we time how long that takes. This timing information may then be queried, and used to find
|
||||
computers which may be causing lag.
|
||||
|
||||
To enable the profiler, run `/computercraft track start`. Computers will then start recording metrics. Once enough data
|
||||
has been gathered, run `/computercraft track stop` to stop profiling and display the recorded data.
|
||||
|
||||

|
||||
|
||||
The table by default shows the number of times each computer has run, and how long it ran for (in total, and on
|
||||
average). In the above screenshot, we can see one computer was particularly badly behaved, and ran for 7 seconds. The
|
||||
buttons may be used to [teleport][`tp`] to the computer, or [open its terminal ][`view`], and inspect it further.
|
||||
|
||||
`/computercraft track dump` can be used to display this table at any point (including while profiling is still running).
|
||||
|
||||
Computers also record other information, such as how much server-thread time they consume, or their HTTP bandwidth
|
||||
usage. The `dump` subcommand accepts a list of other fields to display, instead of the default timings.
|
||||
|
||||
#### Examples
|
||||
- `/computercraft track dump server_tasks_count server_tasks`: Print the number of server-thread tasks each computer
|
||||
executed, and how long they took in total.
|
||||
- `/computercraft track dump http_upload http_download`: Print the number of bytes uploaded and downloaded by each
|
||||
computer.
|
||||
|
||||
|
||||
### `/computercraft queue` {#queue}
|
||||
The queue subcommand allows non-operator players to queue a `computer_command` event on *command* computers.
|
||||
|
||||
This has a similar purpose to vanilla's [`/trigger`] command. Command computers may choose to listen to this event, and
|
||||
then perform some action.
|
||||
|
||||
[`/trigger`]: https://minecraft.wiki/w/Commands/trigger "/trigger on the Minecraft wiki"
|
||||
|
||||
|
||||
[`dump`]: #dump "/computercraft dump"
|
||||
[`queue`]: #queue "/computercraft queue"
|
||||
[`shutdown`]: #shutdown "/computercraft shutdown"
|
||||
[`tp`]: #tp "/computercraft tp"
|
||||
[`track`]: #track "/computercraft track"
|
||||
[`turn-on`]: #turn-on "/computercraft turn-on"
|
||||
[`view`]: #view "/computercraft view"
|
||||
[computer selectors]: #computer-selectors "Computer selectors"
|
@@ -9,17 +9,19 @@ SPDX-License-Identifier: MPL-2.0
|
||||
-->
|
||||
|
||||
# Lua 5.2/5.3 features in CC: Tweaked
|
||||
CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, Cobalt and CC:T implement additional features from Lua 5.2 and 5.3 (as well as some deprecated 5.0 features) that are not available in base 5.1. This page lists all of the compatibility for these newer versions.
|
||||
CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.2. However, Cobalt and CC:T implement additional
|
||||
features from Lua 5.2 and 5.3 (as well as some deprecated 5.0 and 5.1 features). This page lists all of the
|
||||
compatibility for these newer versions.
|
||||
|
||||
## Lua 5.2
|
||||
| Feature | Supported? | Notes |
|
||||
|---------------------------------------------------------------|------------|-------------------------------------------------------------------|
|
||||
| `goto`/labels | ❌ | |
|
||||
| `_ENV` | 🔶 | The `_ENV` global points to `getfenv()`, but it cannot be set. |
|
||||
| `goto`/labels | ✔ | |
|
||||
| `_ENV` | ✔ | |
|
||||
| `\z` escape | ✔ | |
|
||||
| `\xNN` escape | ✔ | |
|
||||
| Hex literal fractional/exponent parts | ✔ | |
|
||||
| Empty statements | ❌ | |
|
||||
| Empty statements | ✔ | |
|
||||
| `__len` metamethod | ✔ | |
|
||||
| `__ipairs` metamethod | ❌ | Deprecated in Lua 5.3. `ipairs` uses `__len`/`__index` instead. |
|
||||
| `__pairs` metamethod | ✔ | |
|
||||
@@ -27,12 +29,12 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However,
|
||||
| `collectgarbage` isrunning, generational, incremental options | ❌ | `collectgarbage` does not exist in CC:T. |
|
||||
| New `load` syntax | ✔ | |
|
||||
| `loadfile` mode parameter | ✔ | Supports both 5.1 and 5.2+ syntax. |
|
||||
| Removed `loadstring` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
||||
| Removed `getfenv`, `setfenv` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
||||
| Removed `loadstring` | ❌ | |
|
||||
| Removed `getfenv`, `setfenv` | 🔶 | Only supports closures with an `_ENV` upvalue. |
|
||||
| `rawlen` function | ✔ | |
|
||||
| Negative index to `select` | ✔ | |
|
||||
| Removed `unpack` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
||||
| Arguments to `xpcall` | ✔ | |
|
||||
| Removed `unpack` | ❌ | |
|
||||
| Arguments to `xpcall` | ✔ | |
|
||||
| Second return value from `coroutine.running` | ✔ | |
|
||||
| Removed `module` | ✔ | |
|
||||
| `package.loaders` -> `package.searchers` | ❌ | |
|
||||
@@ -40,14 +42,14 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However,
|
||||
| `package.config` | ✔ | |
|
||||
| `package.searchpath` | ✔ | |
|
||||
| Removed `package.seeall` | ✔ | |
|
||||
| `string.dump` on functions with upvalues (blanks them out) | ✔ | |
|
||||
| `string.rep` separator | ✔ | |
|
||||
| `string.dump` on functions with upvalues (blanks them out) | ❌ | `string.dump` is not supported |
|
||||
| `string.rep` separator | ✔ | |
|
||||
| `%g` match group | ❌ | |
|
||||
| Removal of `%z` match group | ❌ | |
|
||||
| Removed `table.maxn` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
||||
| Removed `table.maxn` | ❌ | |
|
||||
| `table.pack`/`table.unpack` | ✔ | |
|
||||
| `math.log` base argument | ✔ | |
|
||||
| Removed `math.log10` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. |
|
||||
| Removed `math.log10` | ❌ | |
|
||||
| `*L` mode to `file:read` | ✔ | |
|
||||
| `os.execute` exit type + return value | ❌ | `os.execute` does not exist in CC:T. |
|
||||
| `os.exit` close argument | ❌ | `os.exit` does not exist in CC:T. |
|
||||
@@ -61,7 +63,7 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However,
|
||||
| Tail call hooks | ❌ | |
|
||||
| `=` prefix for chunks | ✔ | |
|
||||
| Yield across C boundary | ✔ | |
|
||||
| Removal of ambiguity error | ❌ | |
|
||||
| Removal of ambiguity error | ✔ | |
|
||||
| Identifiers may no longer use locale-dependent letters | ✔ | |
|
||||
| Ephemeron tables | ❌ | |
|
||||
| Identical functions may be reused | ❌ | Removed in Lua 5.4 |
|
||||
|
@@ -95,10 +95,10 @@ function pullEventRaw(filter) end
|
||||
-- nearest multiple of 0.05.
|
||||
function sleep(time) end
|
||||
|
||||
--- Get the current CraftOS version (for example, `CraftOS 1.8`).
|
||||
--- Get the current CraftOS version (for example, `CraftOS 1.9`).
|
||||
--
|
||||
-- This is defined by `bios.lua`. For the current version of CC:Tweaked, this
|
||||
-- should return `CraftOS 1.8`.
|
||||
-- should return `CraftOS 1.9`.
|
||||
--
|
||||
-- @treturn string The current CraftOS version.
|
||||
-- @usage os.version()
|
||||
|
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
org.gradle.jvmargs=-Xmx3G
|
||||
org.gradle.jvmargs=-Xmx3G -Dfile.encoding=UTF-8
|
||||
org.gradle.parallel=true
|
||||
|
||||
kotlin.stdlib.default.dependency=false
|
||||
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
|
||||
|
||||
# Mod properties
|
||||
isUnstable=false
|
||||
modVersion=1.108.0
|
||||
modVersion=1.113.0
|
||||
|
||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||
mcVersion=1.20.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=17
|
@@ -10,27 +10,30 @@
|
||||
fabric-api = "0.86.1+1.20.1"
|
||||
fabric-loader = "0.14.21"
|
||||
forge = "47.1.0"
|
||||
forgeSpi = "6.0.0"
|
||||
forgeSpi = "7.0.1"
|
||||
mixin = "0.8.5"
|
||||
parchment = "2023.06.26"
|
||||
parchmentMc = "1.19.4"
|
||||
parchment = "2023.08.20"
|
||||
parchmentMc = "1.20.1"
|
||||
yarn = "1.20.1+build.10"
|
||||
|
||||
# Normal dependencies
|
||||
asm = "9.3"
|
||||
autoService = "1.0.1"
|
||||
checkerFramework = "3.32.0"
|
||||
cobalt = "0.7.3"
|
||||
cobalt-next = "0.7.4" # Not a real version, used to constrain the version we accept.
|
||||
# Core dependencies (these versions are tied to the version Minecraft uses)
|
||||
fastutil = "8.5.9"
|
||||
guava = "31.1-jre"
|
||||
jetbrainsAnnotations = "24.0.1"
|
||||
netty = "4.1.82.Final"
|
||||
slf4j = "2.0.1"
|
||||
|
||||
# Core dependencies (independent of Minecraft)
|
||||
asm = "9.6"
|
||||
autoService = "1.1.1"
|
||||
checkerFramework = "3.42.0"
|
||||
cobalt = "0.9.3"
|
||||
commonsCli = "1.6.0"
|
||||
jetbrainsAnnotations = "24.1.0"
|
||||
jsr305 = "3.0.2"
|
||||
jzlib = "1.1.3"
|
||||
kotlin = "1.8.10"
|
||||
kotlin-coroutines = "1.6.4"
|
||||
netty = "4.1.82.Final"
|
||||
nightConfig = "3.6.5"
|
||||
slf4j = "1.7.36"
|
||||
kotlin = "1.9.21"
|
||||
kotlin-coroutines = "1.7.3"
|
||||
nightConfig = "3.6.7"
|
||||
|
||||
# Minecraft mods
|
||||
emi = "1.0.8+1.20.1"
|
||||
@@ -43,39 +46,45 @@ oculus = "1.2.5"
|
||||
rei = "12.0.626"
|
||||
rubidium = "0.6.1"
|
||||
sodium = "mc1.20-0.4.10"
|
||||
create-forge = "0.5.1.f-33"
|
||||
create-fabric = "0.5.1-f-build.1467+mc1.20.1"
|
||||
|
||||
# Testing
|
||||
byteBuddy = "1.14.2"
|
||||
hamcrest = "2.2"
|
||||
jqwik = "1.7.2"
|
||||
junit = "5.9.2"
|
||||
jqwik = "1.8.2"
|
||||
junit = "5.10.1"
|
||||
jmh = "1.37"
|
||||
|
||||
# Build tools
|
||||
cctJavadoc = "1.8.0"
|
||||
checkstyle = "10.3.4"
|
||||
cctJavadoc = "1.8.2"
|
||||
checkstyle = "10.14.1"
|
||||
curseForgeGradle = "1.0.14"
|
||||
errorProne-core = "2.18.0"
|
||||
errorProne-plugin = "3.0.1"
|
||||
fabric-loom = "1.3.7"
|
||||
forgeGradle = "6.0.8"
|
||||
githubRelease = "2.2.12"
|
||||
ideaExt = "1.1.6"
|
||||
illuaminate = "0.1.0-40-g975cbc3"
|
||||
errorProne-core = "2.27.0"
|
||||
errorProne-plugin = "3.1.0"
|
||||
fabric-loom = "1.7.1"
|
||||
forgeGradle = "6.0.21"
|
||||
githubRelease = "2.5.2"
|
||||
gradleVersions = "0.50.0"
|
||||
ideaExt = "1.1.7"
|
||||
illuaminate = "0.1.0-73-g43ee16c"
|
||||
librarian = "1.+"
|
||||
lwjgl = "3.3.3"
|
||||
minotaur = "2.+"
|
||||
mixinGradle = "0.7.+"
|
||||
nullAway = "0.9.9"
|
||||
quiltflower = "1.10.0"
|
||||
spotless = "6.17.0"
|
||||
nullAway = "0.10.25"
|
||||
spotless = "6.23.3"
|
||||
taskTree = "2.1.1"
|
||||
vanillaGradle = "0.2.1-SNAPSHOT"
|
||||
teavm = "0.11.0-SQUID.1"
|
||||
vanillaExtract = "0.1.3"
|
||||
versionCatalogUpdate = "0.8.1"
|
||||
|
||||
[libraries]
|
||||
# Normal dependencies
|
||||
asm = { module = "org.ow2.asm:asm", version.ref = "asm" }
|
||||
asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" }
|
||||
autoService = { module = "com.google.auto.service:auto-service", version.ref = "autoService" }
|
||||
checkerFramework = { module = "org.checkerframework:checker-qual", version.ref = "checkerFramework" }
|
||||
cobalt = { module = "org.squiddev:Cobalt", version.ref = "cobalt" }
|
||||
cobalt = { module = "cc.tweaked:cobalt", version.ref = "cobalt" }
|
||||
commonsCli = { module = "commons-cli:commons-cli", version.ref = "commonsCli" }
|
||||
fastutil = { module = "it.unimi.dsi:fastutil", version.ref = "fastutil" }
|
||||
forgeSpi = { module = "net.minecraftforge:forgespi", version.ref = "forgeSpi" }
|
||||
guava = { module = "com.google.guava:guava", version.ref = "guava" }
|
||||
@@ -93,10 +102,13 @@ nightConfig-toml = { module = "com.electronwill.night-config:toml", version.ref
|
||||
slf4j = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" }
|
||||
|
||||
# Minecraft mods
|
||||
create-fabric = { module = "com.simibubi.create:create-fabric-1.20.1", version.ref = "create-fabric" }
|
||||
create-forge = { module = "com.simibubi.create:create-1.20.1", version.ref = "create-forge" }
|
||||
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
|
||||
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" }
|
||||
emi = { module = "dev.emi:emi-xplat-mojmap", version.ref = "emi" }
|
||||
iris = { module = "maven.modrinth:iris", version.ref = "iris" }
|
||||
jei-api = { module = "mezz.jei:jei-1.20.1-common-api", version.ref = "jei" }
|
||||
jei-fabric = { module = "mezz.jei:jei-1.20.1-fabric", version.ref = "jei" }
|
||||
@@ -112,8 +124,6 @@ rubidium = { module = "maven.modrinth:rubidium", version.ref = "rubidium" }
|
||||
sodium = { module = "maven.modrinth:sodium", version.ref = "sodium" }
|
||||
|
||||
# Testing
|
||||
byteBuddyAgent = { module = "net.bytebuddy:byte-buddy-agent", version.ref = "byteBuddy" }
|
||||
byteBuddy = { module = "net.bytebuddy:byte-buddy", version.ref = "byteBuddy" }
|
||||
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
|
||||
jqwik-api = { module = "net.jqwik:jqwik-api", version.ref = "jqwik" }
|
||||
jqwik-engine = { module = "net.jqwik:jqwik-engine", version.ref = "jqwik" }
|
||||
@@ -121,6 +131,14 @@ junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.re
|
||||
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" }
|
||||
slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4j" }
|
||||
jmh = { module = "org.openjdk.jmh:jmh-core", version.ref = "jmh" }
|
||||
jmh-processor = { module = "org.openjdk.jmh:jmh-generator-annprocess", version.ref = "jmh" }
|
||||
|
||||
# LWJGL
|
||||
lwjgl-bom = { module = "org.lwjgl:lwjgl-bom", version.ref = "lwjgl" }
|
||||
lwjgl-core = { module = "org.lwjgl:lwjgl" }
|
||||
lwjgl-opengl = { module = "org.lwjgl:lwjgl-opengl" }
|
||||
lwjgl-glfw = { module = "org.lwjgl:lwjgl-glfw" }
|
||||
|
||||
# Build tools
|
||||
cctJavadoc = { module = "cc.tweaked:cct-javadoc", version.ref = "cctJavadoc" }
|
||||
@@ -133,34 +151,48 @@ errorProne-plugin = { module = "net.ltgt.gradle:gradle-errorprone-plugin", versi
|
||||
errorProne-testHelpers = { module = "com.google.errorprone:error_prone_test_helpers", version.ref = "errorProne-core" }
|
||||
fabric-loom = { module = "net.fabricmc:fabric-loom", version.ref = "fabric-loom" }
|
||||
forgeGradle = { module = "net.minecraftforge.gradle:ForgeGradle", version.ref = "forgeGradle" }
|
||||
ideaExt = { module = "gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext", version.ref = "ideaExt" }
|
||||
kotlin-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
librarian = { module = "org.parchmentmc:librarian", version.ref = "librarian" }
|
||||
minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur" }
|
||||
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
|
||||
quiltflower = { module = "io.github.juuxel:loom-quiltflower", version.ref = "quiltflower" }
|
||||
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
|
||||
vanillaGradle = { module = "org.spongepowered:vanillagradle", version.ref = "vanillaGradle" }
|
||||
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
|
||||
teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
|
||||
teavm-jso = { module = "org.teavm:teavm-jso", version.ref = "teavm" }
|
||||
teavm-jso-apis = { module = "org.teavm:teavm-jso-apis", version.ref = "teavm" }
|
||||
teavm-jso-impl = { module = "org.teavm:teavm-jso-impl", version.ref = "teavm" }
|
||||
teavm-metaprogramming-api = { module = "org.teavm:teavm-metaprogramming-api", version.ref = "teavm" }
|
||||
teavm-metaprogramming-impl = { module = "org.teavm:teavm-metaprogramming-impl", version.ref = "teavm" }
|
||||
teavm-platform = { module = "org.teavm:teavm-platform", version.ref = "teavm" }
|
||||
teavm-tooling = { module = "org.teavm:teavm-tooling", version.ref = "teavm" }
|
||||
vanillaExtract = { module = "cc.tweaked.vanilla-extract:plugin", version.ref = "vanillaExtract" }
|
||||
yarn = { module = "net.fabricmc:yarn", version.ref = "yarn" }
|
||||
|
||||
[plugins]
|
||||
forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" }
|
||||
githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "githubRelease" }
|
||||
ideaExt = { id = "org.jetbrains.gradle.plugin.idea-ext", version.ref = "ideaExt" }
|
||||
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
|
||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
librarian = { id = "org.parchmentmc.librarian.forgegradle", version.ref = "librarian" }
|
||||
mixinGradle = { id = "org.spongepowered.mixin", version.ref = "mixinGradle" }
|
||||
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
|
||||
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
|
||||
|
||||
[bundles]
|
||||
annotations = ["jsr305", "checkerFramework", "jetbrainsAnnotations"]
|
||||
kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
||||
|
||||
# Minecraft
|
||||
externalMods-common = ["jei-api", "nightConfig-core", "nightConfig-toml"]
|
||||
externalMods-forge-compile = ["moreRed", "oculus", "jei-api"]
|
||||
externalMods-forge-runtime = ["jei-forge"]
|
||||
externalMods-fabric = ["nightConfig-core", "nightConfig-toml"]
|
||||
externalMods-fabric-compile = ["fabricPermissions", "iris", "jei-api", "rei-api", "rei-builtin"]
|
||||
externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
|
||||
|
||||
# Testing
|
||||
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
||||
testRuntime = ["junit-jupiter-engine", "jqwik-engine"]
|
||||
|
||||
# Build tools
|
||||
teavm-api = ["teavm-jso", "teavm-jso-apis", "teavm-platform", "teavm-classlib", "teavm-metaprogramming-api"]
|
||||
teavm-tooling = ["teavm-tooling", "teavm-metaprogramming-impl", "teavm-jso-impl"]
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
27
gradlew
vendored
27
gradlew
vendored
@@ -15,6 +15,8 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
@@ -55,7 +57,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (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.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
@@ -83,7 +85,9 @@ done
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
@@ -130,10 +134,13 @@ location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
@@ -141,7 +148,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
@@ -149,7 +156,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC3045
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
@@ -198,11 +205,11 @@ fi
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
|
22
gradlew.bat
vendored
22
gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@@ -2,15 +2,15 @@
|
||||
|
||||
; SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
;
|
||||
; SPDX-License-Identifier: LicenseRef-CCPL
|
||||
; SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
(sources
|
||||
/doc/
|
||||
/projects/forge/build/docs/luaJavadoc/
|
||||
/projects/common/build/docs/luaJavadoc/
|
||||
/projects/core/src/main/resources/data/computercraft/lua/bios.lua
|
||||
/projects/core/src/main/resources/data/computercraft/lua/rom/
|
||||
/projects/core/src/test/resources/test-rom
|
||||
/projects/web/src/mount)
|
||||
/projects/web/src/frontend/mount)
|
||||
|
||||
(doc
|
||||
; Also defined in projects/web/build.gradle.kts
|
||||
@@ -23,7 +23,7 @@
|
||||
(url https://tweaked.cc/)
|
||||
(source-link https://github.com/cc-tweaked/CC-Tweaked/blob/${commit}/${path}#L${line})
|
||||
|
||||
(styles /projects/web/src/styles.css)
|
||||
(styles /projects/web/build/rollup/index.css)
|
||||
(scripts /projects/web/build/rollup/index.js)
|
||||
(head doc/head.html))
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
(library-path
|
||||
/doc/stub/
|
||||
/projects/forge/build/docs/luaJavadoc/
|
||||
/projects/common/build/docs/luaJavadoc/
|
||||
|
||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/
|
||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/command/
|
||||
@@ -77,7 +77,6 @@
|
||||
(globals
|
||||
:max
|
||||
_CC_DEFAULT_SETTINGS
|
||||
_CC_DISABLE_LUA51_FEATURES
|
||||
_HOST
|
||||
;; Ideally we'd pick these up from bios.lua, but illuaminate currently
|
||||
;; isn't smart enough.
|
||||
@@ -89,7 +88,7 @@
|
||||
(/doc/stub/
|
||||
/projects/core/src/main/resources/data/computercraft/lua/bios.lua
|
||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/
|
||||
/projects/forge/build/docs/luaJavadoc/)
|
||||
/projects/common/build/docs/luaJavadoc/)
|
||||
(linters -var:unused-global)
|
||||
(lint (allow-toplevel-global true)))
|
||||
|
||||
@@ -106,6 +105,10 @@
|
||||
/projects/core/src/main/resources/data/computercraft/lua/rom/apis/turtle/turtle.lua)
|
||||
(linters -var:deprecated))
|
||||
|
||||
;; Suppress unused variable warnings in the parser.
|
||||
(at /projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/internal/syntax/parser.lua
|
||||
(linters -var:unused))
|
||||
|
||||
(at /projects/core/src/test/resources/test-rom
|
||||
; We should still be able to test deprecated members.
|
||||
(linters -var:deprecated)
|
||||
@@ -115,4 +118,4 @@
|
||||
:max sleep write
|
||||
cct_test describe expect howlci fail it pending stub before_each)))
|
||||
|
||||
(at /projects/web/src/mount/expr_template.lua (lint (globals :max __expr__)))
|
||||
(at /projects/web/src/frontend/mount/expr_template.lua (lint (globals :max __expr__)))
|
||||
|
4091
package-lock.json
generated
4091
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
26
package.json
26
package.json
@@ -6,24 +6,24 @@
|
||||
"license": "BSD-3-Clause",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@squid-dev/cc-web-term": "^2.0.0",
|
||||
"preact": "^10.5.5",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tslib": "^2.0.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-terser": "^0.4.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.1",
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@rollup/plugin-url": "^8.0.1",
|
||||
"@types/glob": "^8.1.0",
|
||||
"@types/react-dom": "^18.0.5",
|
||||
"glob": "^9.3.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"react": "^18.1.0",
|
||||
"rehype-highlight": "^6.0.0",
|
||||
"rehype-react": "^7.1.1",
|
||||
"rehype": "^12.0.1",
|
||||
"requirejs": "^2.3.6",
|
||||
"rollup": "^3.19.1",
|
||||
"ts-node": "^10.8.0",
|
||||
"typescript": "^4.0.5"
|
||||
"@swc/core": "^1.3.92",
|
||||
"@types/node": "^20.8.3",
|
||||
"lightningcss": "^1.22.0",
|
||||
"preact-render-to-string": "^6.2.1",
|
||||
"rehype": "^13.0.0",
|
||||
"rehype-highlight": "^7.0.0",
|
||||
"rehype-react": "^8.0.0",
|
||||
"rollup": "^4.0.0",
|
||||
"tsx": "^4.7.0",
|
||||
"typescript": "^5.2.2"
|
||||
}
|
||||
}
|
||||
|
@@ -62,6 +62,9 @@ mentioning:
|
||||
- `lints`: This defines an [ErrorProne] plugin which adds a couple of compile-time checks to our code. This is what
|
||||
enforces that no client-specific code is used inside the `main` source set (and a couple of other things!).
|
||||
|
||||
- `standalone`: This contains a standalone UI for computers, allowing debugging and development of CraftOS without
|
||||
launching Minecraft.
|
||||
|
||||
- `web`: This contains the additional tooling for building [the documentation website][tweaked.cc], such as support for
|
||||
rendering recipes
|
||||
|
||||
|
@@ -27,8 +27,13 @@ public final class ComputerCraftAPIClient {
|
||||
* @param serialiser The turtle upgrade serialiser.
|
||||
* @param modeller The upgrade modeller.
|
||||
* @param <T> The type of the turtle upgrade.
|
||||
* @deprecated This method can lead to confusing load behaviour on Forge. Use
|
||||
* {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} on Fabric, or
|
||||
* {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} on Forge.
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public static <T extends ITurtleUpgrade> void registerTurtleUpgradeModeller(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller) {
|
||||
// TODO(1.20.4): Remove this
|
||||
getInstance().registerTurtleUpgradeModeller(serialiser, modeller);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,26 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.api.client.turtle;
|
||||
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||
|
||||
/**
|
||||
* A functional interface to register a {@link TurtleUpgradeModeller} for a class of turtle upgrades.
|
||||
* <p>
|
||||
* This interface is largely intended to be used from multi-loader code, to allow sharing registration code between
|
||||
* multiple loaders.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RegisterTurtleUpgradeModeller {
|
||||
/**
|
||||
* Register a {@link TurtleUpgradeModeller}.
|
||||
*
|
||||
* @param serialiser The turtle upgrade serialiser.
|
||||
* @param modeller The upgrade modeller.
|
||||
* @param <T> The type of the turtle upgrade.
|
||||
*/
|
||||
<T extends ITurtleUpgrade> void register(TurtleUpgradeSerialiser<T> serialiser, TurtleUpgradeModeller<T> modeller);
|
||||
}
|
@@ -4,12 +4,10 @@
|
||||
|
||||
package dan200.computercraft.api.client.turtle;
|
||||
|
||||
import dan200.computercraft.api.client.ComputerCraftAPIClient;
|
||||
import dan200.computercraft.api.client.TransformedModel;
|
||||
import dan200.computercraft.api.turtle.ITurtleAccess;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||
import net.minecraft.client.resources.model.ModelResourceLocation;
|
||||
import net.minecraft.client.resources.model.UnbakedModel;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -21,9 +19,13 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides models for a {@link ITurtleUpgrade}.
|
||||
* <p>
|
||||
* Use {@code dan200.computercraft.api.client.FabricComputerCraftAPIClient#registerTurtleUpgradeModeller} to register a
|
||||
* modeller on Fabric and {@code dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent} to register one
|
||||
* on Forge
|
||||
*
|
||||
* @param <T> The type of turtle upgrade this modeller applies to.
|
||||
* @see ComputerCraftAPIClient#registerTurtleUpgradeModeller(TurtleUpgradeSerialiser, TurtleUpgradeModeller) To register a modeller.
|
||||
* @see RegisterTurtleUpgradeModeller For multi-loader registration support.
|
||||
*/
|
||||
public interface TurtleUpgradeModeller<T extends ITurtleUpgrade> {
|
||||
/**
|
||||
|
@@ -17,7 +17,7 @@ import org.joml.Matrix4f;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
class TurtleUpgradeModellers {
|
||||
final class TurtleUpgradeModellers {
|
||||
private static final Transformation leftTransform = getMatrixFor(-0.4065f);
|
||||
private static final Transformation rightTransform = getMatrixFor(0.4065f);
|
||||
|
||||
@@ -35,7 +35,7 @@ class TurtleUpgradeModellers {
|
||||
|
||||
static final TurtleUpgradeModeller<ITurtleUpgrade> UPGRADE_ITEM = new UpgradeItemModeller();
|
||||
|
||||
private static class UpgradeItemModeller implements TurtleUpgradeModeller<ITurtleUpgrade> {
|
||||
private static final class UpgradeItemModeller implements TurtleUpgradeModeller<ITurtleUpgrade> {
|
||||
@Override
|
||||
public TransformedModel getModel(ITurtleUpgrade upgrade, @Nullable ITurtleAccess turtle, TurtleSide side) {
|
||||
return getModel(turtle == null ? upgrade.getCraftingItem() : upgrade.getUpgradeItem(turtle.getUpgradeNBTData(side)), side);
|
||||
|
@@ -4,9 +4,11 @@
|
||||
|
||||
package dan200.computercraft.api;
|
||||
|
||||
import dan200.computercraft.api.component.ComputerComponent;
|
||||
import dan200.computercraft.api.filesystem.Mount;
|
||||
import dan200.computercraft.api.filesystem.WritableMount;
|
||||
import dan200.computercraft.api.lua.GenericSource;
|
||||
import dan200.computercraft.api.lua.IComputerSystem;
|
||||
import dan200.computercraft.api.lua.ILuaAPI;
|
||||
import dan200.computercraft.api.lua.ILuaAPIFactory;
|
||||
import dan200.computercraft.api.media.IMedia;
|
||||
@@ -165,7 +167,20 @@ public final class ComputerCraftAPI {
|
||||
* Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
|
||||
* <p>
|
||||
* 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 an additional API just to turtles with the following code:
|
||||
*
|
||||
* <pre>{@code
|
||||
* ComputerCraftAPI.registerAPIFactory(computer -> {
|
||||
* // Read the turtle component.
|
||||
* var turtle = computer.getComponent(ComputerComponents.TURTLE);
|
||||
* // If present then add our API.
|
||||
* return turtle == null ? null : new MyCustomTurtleApi(turtle);
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
* @param factory The factory for your API subclass.
|
||||
* @see ILuaAPIFactory
|
||||
|
@@ -46,6 +46,14 @@ public class ComputerCraftTags {
|
||||
public static final TagKey<Block> WIRED_MODEM = make("wired_modem");
|
||||
public static final TagKey<Block> MONITOR = make("monitor");
|
||||
|
||||
/**
|
||||
* Blocks which should be ignored by a {@code peripheral_hub} peripheral.
|
||||
* <p>
|
||||
* This should include blocks which themselves expose a peripheral hub (such as {@linkplain #WIRED_MODEM wired
|
||||
* modems}).
|
||||
*/
|
||||
public static final TagKey<Block> PERIPHERAL_HUB_IGNORE = make("peripheral_hub_ignore");
|
||||
|
||||
/**
|
||||
* Blocks which can be broken by any turtle tool.
|
||||
*/
|
||||
|
@@ -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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@@ -22,7 +22,7 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
||||
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 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.
|
||||
*/
|
||||
@@ -53,21 +53,18 @@ public abstract class BasicItemDetailProvider<T> implements DetailProvider<ItemS
|
||||
* @param stack The item stack to provide details for.
|
||||
* @param item The item to provide details for.
|
||||
*/
|
||||
public abstract void provideDetails(
|
||||
Map<? super String, Object> data, ItemStack stack, T item
|
||||
);
|
||||
public abstract void provideDetails(Map<? super String, Object> data, ItemStack stack, T item);
|
||||
|
||||
@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();
|
||||
if (!itemType.isInstance(item)) return;
|
||||
|
||||
// If `namespace` is specified, insert into a new data map instead of the existing one.
|
||||
Map<? super String, Object> child = namespace == null ? data : new HashMap<>();
|
||||
|
||||
provideDetails(child, stack, itemType.cast(item));
|
||||
|
||||
if (namespace != null) {
|
||||
if (namespace == null) {
|
||||
provideDetails(data, stack, itemType.cast(item));
|
||||
} else {
|
||||
Map<? super String, Object> child = new HashMap<>();
|
||||
provideDetails(child, stack, itemType.cast(item));
|
||||
data.put(namespace, child);
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ public interface DetailRegistry<T> {
|
||||
* @param provider The detail provider to register.
|
||||
* @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
|
||||
|
@@ -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;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Construct an {@link ILuaAPI} for a specific computer.
|
||||
* Construct an {@link ILuaAPI} for a computer.
|
||||
*
|
||||
* @see ILuaAPI
|
||||
* @see dan200.computercraft.api.ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
||||
* @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory)
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ILuaAPIFactory {
|
@@ -5,6 +5,7 @@
|
||||
package dan200.computercraft.api.network.wired;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -22,6 +23,7 @@ import java.util.Map;
|
||||
*
|
||||
* @see WiredNode#getNetwork()
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
public interface WiredNetwork {
|
||||
/**
|
||||
* Create a connection between two nodes.
|
||||
@@ -35,7 +37,9 @@ public interface WiredNetwork {
|
||||
* @throws IllegalArgumentException If {@code left} and {@code right} are equal.
|
||||
* @see WiredNode#connectTo(WiredNode)
|
||||
* @see WiredNetwork#connect(WiredNode, WiredNode)
|
||||
* @deprecated Use {@link WiredNode#connectTo(WiredNode)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean connect(WiredNode left, WiredNode right);
|
||||
|
||||
/**
|
||||
@@ -50,7 +54,9 @@ public interface WiredNetwork {
|
||||
* @throws IllegalArgumentException If {@code left} and {@code right} are equal.
|
||||
* @see WiredNode#disconnectFrom(WiredNode)
|
||||
* @see WiredNetwork#connect(WiredNode, WiredNode)
|
||||
* @deprecated Use {@link WiredNode#disconnectFrom(WiredNode)}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean disconnect(WiredNode left, WiredNode right);
|
||||
|
||||
/**
|
||||
@@ -64,7 +70,9 @@ public interface WiredNetwork {
|
||||
* only element.
|
||||
* @throws IllegalArgumentException If the node is not in the network.
|
||||
* @see WiredNode#remove()
|
||||
* @deprecated Use {@link WiredNode#remove()}
|
||||
*/
|
||||
@Deprecated
|
||||
boolean remove(WiredNode node);
|
||||
|
||||
/**
|
||||
@@ -77,6 +85,8 @@ public interface WiredNetwork {
|
||||
* @param peripherals The new peripherals for this node.
|
||||
* @throws IllegalArgumentException If the node is not in the network.
|
||||
* @see WiredNode#updatePeripherals(Map)
|
||||
* @deprecated Use {@link WiredNode#updatePeripherals(Map)}
|
||||
*/
|
||||
@Deprecated
|
||||
void updatePeripherals(WiredNode node, Map<String, IPeripheral> peripherals);
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ package dan200.computercraft.api.network.wired;
|
||||
|
||||
import dan200.computercraft.api.network.PacketNetwork;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -22,6 +23,7 @@ import java.util.Map;
|
||||
* Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever
|
||||
* be used on the main server thread.
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
public interface WiredNode extends PacketNetwork {
|
||||
/**
|
||||
* The associated element for this network node.
|
||||
@@ -37,7 +39,9 @@ public interface WiredNode extends PacketNetwork {
|
||||
* This should only be used on the server thread.
|
||||
*
|
||||
* @return This node's network.
|
||||
* @deprecated Use the connect/disconnect/remove methods on {@link WiredNode}.
|
||||
*/
|
||||
@Deprecated
|
||||
WiredNetwork getNetwork();
|
||||
|
||||
/**
|
||||
@@ -47,12 +51,9 @@ public interface WiredNode extends PacketNetwork {
|
||||
*
|
||||
* @param node The other node to connect to.
|
||||
* @return {@code true} if a connection was created or {@code false} if the connection already exists.
|
||||
* @see WiredNetwork#connect(WiredNode, WiredNode)
|
||||
* @see WiredNode#disconnectFrom(WiredNode)
|
||||
*/
|
||||
default boolean connectTo(WiredNode node) {
|
||||
return getNetwork().connect(this, node);
|
||||
}
|
||||
boolean connectTo(WiredNode node);
|
||||
|
||||
/**
|
||||
* Destroy a connection between this node and another.
|
||||
@@ -61,13 +62,9 @@ public interface WiredNode extends PacketNetwork {
|
||||
*
|
||||
* @param node The other node to disconnect from.
|
||||
* @return {@code true} if a connection was destroyed or {@code false} if no connection exists.
|
||||
* @throws IllegalArgumentException If {@code node} is not on the same network.
|
||||
* @see WiredNetwork#disconnect(WiredNode, WiredNode)
|
||||
* @see WiredNode#connectTo(WiredNode)
|
||||
*/
|
||||
default boolean disconnectFrom(WiredNode node) {
|
||||
return getNetwork().disconnect(this, node);
|
||||
}
|
||||
boolean disconnectFrom(WiredNode node);
|
||||
|
||||
/**
|
||||
* Sever all connections this node has, removing it from this network.
|
||||
@@ -78,11 +75,8 @@ public interface WiredNode extends PacketNetwork {
|
||||
* @return Whether this node was removed from the network. One cannot remove a node from a network where it is the
|
||||
* only element.
|
||||
* @throws IllegalArgumentException If the node is not in the network.
|
||||
* @see WiredNetwork#remove(WiredNode)
|
||||
*/
|
||||
default boolean remove() {
|
||||
return getNetwork().remove(this);
|
||||
}
|
||||
boolean remove();
|
||||
|
||||
/**
|
||||
* Mark this node's peripherals as having changed.
|
||||
@@ -91,9 +85,6 @@ public interface WiredNode extends PacketNetwork {
|
||||
* that your network element owns.
|
||||
*
|
||||
* @param peripherals The new peripherals for this node.
|
||||
* @see WiredNetwork#updatePeripherals(WiredNode, Map)
|
||||
*/
|
||||
default void updatePeripherals(Map<String, IPeripheral> peripherals) {
|
||||
getNetwork().updatePeripherals(this, peripherals);
|
||||
}
|
||||
void updatePeripherals(Map<String, IPeripheral> peripherals);
|
||||
}
|
||||
|
@@ -6,10 +6,14 @@ package dan200.computercraft.api.pocket;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
@@ -17,7 +21,22 @@ import java.util.Map;
|
||||
/**
|
||||
* Wrapper class for pocket computers.
|
||||
*/
|
||||
@ApiStatus.NonExtendable
|
||||
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.
|
||||
* <p>
|
||||
@@ -64,6 +83,26 @@ public interface IPocketAccess {
|
||||
*/
|
||||
void setLight(int colour);
|
||||
|
||||
/**
|
||||
* Get the currently equipped upgrade.
|
||||
*
|
||||
* @return The currently equipped upgrade.
|
||||
* @see #getUpgradeNBTData()
|
||||
* @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.
|
||||
* <p>
|
||||
@@ -73,6 +112,7 @@ public interface IPocketAccess {
|
||||
* @see #updateUpgradeNBTData()
|
||||
* @see UpgradeBase#getUpgradeItem(CompoundTag)
|
||||
* @see UpgradeBase#getUpgradeData(ItemStack)
|
||||
* @see #getUpgrade()
|
||||
*/
|
||||
CompoundTag getUpgradeNBTData();
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
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 {
|
||||
/**
|
||||
|
@@ -48,13 +48,8 @@ import java.util.function.Function;
|
||||
* }
|
||||
* }</pre>
|
||||
* <p>
|
||||
* Finally, we need to register a model for our upgrade. This is done with
|
||||
* {@link dan200.computercraft.api.client.ComputerCraftAPIClient#registerTurtleUpgradeModeller}:
|
||||
*
|
||||
* <pre>{@code
|
||||
* // Register our model inside FMLClientSetupEvent
|
||||
* ComputerCraftAPIClient.registerTurtleUpgradeModeller(MY_UPGRADE.get(), TurtleUpgradeModeller.flatItem())
|
||||
* }</pre>
|
||||
* Finally, we need to register a model for our upgrade. The way to do this varies on mod loader, see
|
||||
* {@link dan200.computercraft.api.client.turtle.TurtleUpgradeModeller} for more information.
|
||||
* <p>
|
||||
* {@link TurtleUpgradeDataProvider} provides a data provider to aid with generating these JSON files.
|
||||
*
|
||||
|
@@ -19,8 +19,6 @@ import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
@@ -36,8 +34,6 @@ import java.util.function.Function;
|
||||
* @param <R> The upgrade serialiser to register for.
|
||||
*/
|
||||
public abstract class UpgradeDataProvider<T extends UpgradeBase, R extends UpgradeSerialiser<? extends T>> implements DataProvider {
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
private final PackOutput output;
|
||||
private final String name;
|
||||
private final String folder;
|
||||
|
@@ -29,7 +29,7 @@ public final class Services {
|
||||
* @throws IllegalStateException When the service cannot be loaded.
|
||||
*/
|
||||
public static <T> T load(Class<T> klass) {
|
||||
var services = ServiceLoader.load(klass).stream().toList();
|
||||
var services = ServiceLoader.load(klass, klass.getClassLoader()).stream().toList();
|
||||
return switch (services.size()) {
|
||||
case 1 -> services.get(0).get();
|
||||
case 0 -> throw new IllegalStateException("Cannot find service for " + klass.getName());
|
||||
|
@@ -2,14 +2,19 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
import cc.tweaked.gradle.annotationProcessorEverywhere
|
||||
import cc.tweaked.gradle.clientClasses
|
||||
import cc.tweaked.gradle.commonClasses
|
||||
import cc.tweaked.gradle.*
|
||||
|
||||
plugins {
|
||||
id("cc-tweaked.publishing")
|
||||
id("cc-tweaked.vanilla")
|
||||
id("cc-tweaked.gametest")
|
||||
id("cc-tweaked.illuaminate")
|
||||
id("cc-tweaked.publishing")
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
resources.srcDir("src/generated/resources")
|
||||
}
|
||||
}
|
||||
|
||||
minecraft {
|
||||
@@ -19,6 +24,18 @@ minecraft {
|
||||
)
|
||||
}
|
||||
|
||||
configurations {
|
||||
register("cctJavadoc")
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://maven.minecraftforge.net/") {
|
||||
content {
|
||||
includeModule("org.spongepowered", "mixin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Pull in our other projects. See comments in MinecraftConfigurations on this nastiness.
|
||||
implementation(project(":core"))
|
||||
@@ -26,9 +43,9 @@ dependencies {
|
||||
clientImplementation(clientClasses(project(":common-api")))
|
||||
|
||||
compileOnly(libs.bundles.externalMods.common)
|
||||
compileOnly(variantOf(libs.create.forge) { classifier("slim") }) { isTransitive = false }
|
||||
clientCompileOnly(variantOf(libs.emi) { classifier("api") })
|
||||
|
||||
compileOnly(libs.mixin)
|
||||
annotationProcessorEverywhere(libs.autoService)
|
||||
testFixturesAnnotationProcessor(libs.autoService)
|
||||
|
||||
@@ -36,7 +53,80 @@ dependencies {
|
||||
testImplementation(libs.bundles.test)
|
||||
testRuntimeOnly(libs.bundles.testRuntime)
|
||||
|
||||
testImplementation(libs.jmh)
|
||||
testAnnotationProcessor(libs.jmh.processor)
|
||||
|
||||
testModCompileOnly(libs.mixin)
|
||||
testModImplementation(testFixtures(project(":core")))
|
||||
testModImplementation(testFixtures(project(":common")))
|
||||
testModImplementation(libs.bundles.kotlin)
|
||||
|
||||
testFixturesImplementation(testFixtures(project(":core")))
|
||||
|
||||
"cctJavadoc"(libs.cctJavadoc)
|
||||
}
|
||||
|
||||
illuaminate {
|
||||
version.set(libs.versions.illuaminate)
|
||||
}
|
||||
|
||||
val luaJavadoc by tasks.registering(Javadoc::class) {
|
||||
description = "Generates documentation for Java-side Lua functions."
|
||||
group = JavaBasePlugin.DOCUMENTATION_GROUP
|
||||
|
||||
val sourceSets = listOf(sourceSets.main.get(), project(":core").sourceSets.main.get())
|
||||
for (sourceSet in sourceSets) {
|
||||
source(sourceSet.java)
|
||||
classpath += sourceSet.compileClasspath
|
||||
}
|
||||
|
||||
destinationDir = layout.buildDirectory.dir("docs/luaJavadoc").get().asFile
|
||||
|
||||
val options = options as StandardJavadocDocletOptions
|
||||
options.docletpath = configurations["cctJavadoc"].files.toList()
|
||||
options.doclet = "cc.tweaked.javadoc.LuaDoclet"
|
||||
options.addStringOption("project-root", rootProject.file(".").absolutePath)
|
||||
options.noTimestamp(false)
|
||||
|
||||
javadocTool.set(
|
||||
javaToolchains.javadocToolFor {
|
||||
languageVersion.set(CCTweakedPlugin.JAVA_VERSION)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val lintLua by tasks.registering(IlluaminateExec::class) {
|
||||
group = JavaBasePlugin.VERIFICATION_GROUP
|
||||
description = "Lint Lua (and Lua docs) with illuaminate"
|
||||
|
||||
// Config files
|
||||
inputs.file(rootProject.file("illuaminate.sexp")).withPropertyName("illuaminate.sexp")
|
||||
// Sources
|
||||
inputs.files(rootProject.fileTree("doc")).withPropertyName("docs")
|
||||
inputs.files(project(":core").fileTree("src/main/resources/data/computercraft/lua")).withPropertyName("lua rom")
|
||||
inputs.files(luaJavadoc)
|
||||
|
||||
args = listOf("lint")
|
||||
workingDir = rootProject.projectDir
|
||||
|
||||
doFirst { if (System.getenv("GITHUB_ACTIONS") != null) println("::add-matcher::.github/matchers/illuaminate.json") }
|
||||
doLast { if (System.getenv("GITHUB_ACTIONS") != null) println("::remove-matcher owner=illuaminate::") }
|
||||
}
|
||||
|
||||
val runData by tasks.registering(MergeTrees::class) {
|
||||
output = layout.projectDirectory.dir("src/generated/resources")
|
||||
|
||||
for (loader in listOf("forge", "fabric")) {
|
||||
mustRunAfter(":$loader:runData")
|
||||
source {
|
||||
input {
|
||||
from(project(":$loader").layout.buildDirectory.dir("generatedResources"))
|
||||
exclude(".cache")
|
||||
}
|
||||
|
||||
output = project(":$loader").layout.projectDirectory.dir("src/generated/resources")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(GenerateModuleMetadata::class).configureEach { isEnabled = false }
|
||||
|
@@ -17,8 +17,6 @@ import dan200.computercraft.client.render.monitor.MonitorRenderState;
|
||||
import dan200.computercraft.client.sound.SpeakerManager;
|
||||
import dan200.computercraft.shared.CommonHooks;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
|
||||
@@ -28,7 +26,6 @@ import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
@@ -43,7 +40,6 @@ import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -71,10 +67,6 @@ public final class ClientHooks {
|
||||
ClientPocketComputers.reset();
|
||||
}
|
||||
|
||||
public static boolean onChatMessage(String message) {
|
||||
return handleOpenComputerCommand(message);
|
||||
}
|
||||
|
||||
public static boolean drawHighlight(PoseStack transform, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) {
|
||||
return CableHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit)
|
||||
|| MonitorHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit);
|
||||
@@ -109,34 +101,6 @@ public final class ClientHooks {
|
||||
SpeakerManager.onPlayStreaming(engine, channel, stream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the {@link CommandComputerCraft#OPEN_COMPUTER} "clientside command". This isn't a true command, as we
|
||||
* don't want it to actually be visible to the user.
|
||||
*
|
||||
* @param message The current chat message.
|
||||
* @return Whether to cancel sending this message.
|
||||
*/
|
||||
private static boolean handleOpenComputerCommand(String message) {
|
||||
if (!message.startsWith(CommandComputerCraft.OPEN_COMPUTER)) return false;
|
||||
|
||||
var server = Minecraft.getInstance().getSingleplayerServer();
|
||||
if (server == null) return false;
|
||||
|
||||
var idStr = message.substring(CommandComputerCraft.OPEN_COMPUTER.length()).trim();
|
||||
int id;
|
||||
try {
|
||||
id = Integer.parseInt(idStr);
|
||||
} catch (NumberFormatException ignore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var file = new File(ServerContext.get(server).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) return false;
|
||||
|
||||
Util.getPlatform().openFile(file);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional information about the currently targeted block to the debug screen.
|
||||
*
|
||||
|
@@ -4,11 +4,16 @@
|
||||
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.ComputerCraftAPIClient;
|
||||
import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller;
|
||||
import dan200.computercraft.api.client.turtle.TurtleUpgradeModeller;
|
||||
import dan200.computercraft.client.gui.*;
|
||||
import dan200.computercraft.client.pocket.ClientPocketComputers;
|
||||
import dan200.computercraft.client.render.CustomLecternRenderer;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||
@@ -16,11 +21,14 @@ import dan200.computercraft.client.turtle.TurtleModemModeller;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.core.util.Colour;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.common.IColouredItem;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
|
||||
import dan200.computercraft.shared.media.items.DiskItem;
|
||||
import dan200.computercraft.shared.media.items.TreasureDiskItem;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
@@ -30,6 +38,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
import net.minecraft.client.renderer.item.ClampedItemPropertyFunction;
|
||||
import net.minecraft.client.renderer.item.ItemProperties;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.server.packs.resources.ResourceProvider;
|
||||
@@ -39,6 +48,7 @@ import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.ItemLike;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
@@ -60,30 +70,20 @@ public final class ClientRegistry {
|
||||
* Register any client-side objects which don't have to be done on the main thread.
|
||||
*/
|
||||
public static void register() {
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right")
|
||||
));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right")
|
||||
));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true));
|
||||
ComputerCraftAPIClient.registerTurtleUpgradeModeller(ModRegistry.TurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
||||
|
||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.MONITOR_NORMAL.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_ADVANCED.get(), TurtleBlockEntityRenderer::new);
|
||||
BlockEntityRenderers.register(ModRegistry.BlockEntities.LECTERN.get(), CustomLecternRenderer::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register any client-side objects which must be done on the main thread.
|
||||
*
|
||||
* @param itemProperties Callback to register item properties.
|
||||
*/
|
||||
public static void registerMainThread() {
|
||||
public static void registerMainThread(RegisterItemProperty itemProperties) {
|
||||
MenuScreens.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.COMPUTER.get(), ComputerScreen::new);
|
||||
MenuScreens.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER.get(), ComputerScreen::new);
|
||||
MenuScreens.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
|
||||
MenuScreens.register(ModRegistry.Menus.TURTLE.get(), TurtleScreen::new);
|
||||
|
||||
@@ -91,22 +91,45 @@ public final class ClientRegistry {
|
||||
MenuScreens.register(ModRegistry.Menus.DISK_DRIVE.get(), DiskDriveScreen::new);
|
||||
MenuScreens.register(ModRegistry.Menus.PRINTOUT.get(), PrintoutScreen::new);
|
||||
|
||||
MenuScreens.<ViewComputerMenu, ComputerScreen<ViewComputerMenu>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), ComputerScreen::new);
|
||||
|
||||
registerItemProperty("state",
|
||||
new UnclampedPropertyFunction((stack, world, player, random) -> ClientPocketComputers.get(stack).getState().ordinal()),
|
||||
registerItemProperty(itemProperties, "state",
|
||||
new UnclampedPropertyFunction((stack, world, player, random) -> {
|
||||
var computer = ClientPocketComputers.get(stack);
|
||||
return (computer == null ? ComputerState.OFF : computer.getState()).ordinal();
|
||||
}),
|
||||
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
||||
);
|
||||
registerItemProperty("coloured",
|
||||
registerItemProperty(itemProperties, "coloured",
|
||||
(stack, world, player, random) -> IColouredItem.getColourBasic(stack) != -1 ? 1 : 0,
|
||||
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
||||
);
|
||||
}
|
||||
|
||||
public static void registerTurtleModellers(RegisterTurtleUpgradeModeller register) {
|
||||
register.register(ModRegistry.TurtleSerialisers.SPEAKER.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_left"),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_speaker_right")
|
||||
));
|
||||
register.register(ModRegistry.TurtleSerialisers.WORKBENCH.get(), TurtleUpgradeModeller.sided(
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_left"),
|
||||
new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/turtle_crafting_table_right")
|
||||
));
|
||||
register.register(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_NORMAL.get(), new TurtleModemModeller(false));
|
||||
register.register(ModRegistry.TurtleSerialisers.WIRELESS_MODEM_ADVANCED.get(), new TurtleModemModeller(true));
|
||||
register.register(ModRegistry.TurtleSerialisers.TOOL.get(), TurtleUpgradeModeller.flatItem());
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static void registerItemProperty(String name, ClampedItemPropertyFunction getter, Supplier<? extends Item>... items) {
|
||||
private static void registerItemProperty(RegisterItemProperty itemProperties, String name, ClampedItemPropertyFunction getter, Supplier<? extends Item>... items) {
|
||||
var id = new ResourceLocation(ComputerCraftAPI.MOD_ID, name);
|
||||
for (var item : items) ItemProperties.register(item.get(), id, getter);
|
||||
for (var item : items) itemProperties.register(item.get(), id, getter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an item property via {@link ItemProperties#register}. Forge and Fabric expose different methods, so we
|
||||
* supply this via mod-loader-specific code.
|
||||
*/
|
||||
public interface RegisterItemProperty {
|
||||
void register(Item item, ResourceLocation name, ClampedItemPropertyFunction property);
|
||||
}
|
||||
|
||||
public static void registerReloadListeners(Consumer<PreparableReloadListener> register, Minecraft minecraft) {
|
||||
@@ -144,17 +167,14 @@ public final class ClientRegistry {
|
||||
}
|
||||
|
||||
private static int getPocketColour(ItemStack stack, int layer) {
|
||||
switch (layer) {
|
||||
case 0:
|
||||
default:
|
||||
return 0xFFFFFF;
|
||||
case 1: // Frame colour
|
||||
return IColouredItem.getColourBasic(stack);
|
||||
case 2: { // Light colour
|
||||
var light = ClientPocketComputers.get(stack).getLightState();
|
||||
return light == -1 ? Colour.BLACK.getHex() : light;
|
||||
return switch (layer) {
|
||||
default -> 0xFFFFFF;
|
||||
case 1 -> IColouredItem.getColourBasic(stack); // Frame colour
|
||||
case 2 -> { // Light colour
|
||||
var computer = ClientPocketComputers.get(stack);
|
||||
yield computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static int getTurtleColour(ItemStack stack, int layer) {
|
||||
@@ -179,4 +199,45 @@ public final class ClientRegistry {
|
||||
return function.unclampedCall(stack, level, entity, layer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register client-side commands.
|
||||
*
|
||||
* @param dispatcher The dispatcher to register the commands to.
|
||||
* @param sendError A function to send an error message.
|
||||
* @param <T> The type of the client-side command context.
|
||||
*/
|
||||
public static <T> void registerClientCommands(CommandDispatcher<T> dispatcher, BiConsumer<T, Component> sendError) {
|
||||
dispatcher.register(LiteralArgumentBuilder.<T>literal(CommandComputerCraft.CLIENT_OPEN_FOLDER)
|
||||
.requires(x -> Minecraft.getInstance().getSingleplayerServer() != null)
|
||||
.then(RequiredArgumentBuilder.<T, Integer>argument("computer_id", IntegerArgumentType.integer(0))
|
||||
.executes(c -> handleOpenComputerCommand(c.getSource(), sendError, c.getArgument("computer_id", Integer.class)))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the {@link CommandComputerCraft#CLIENT_OPEN_FOLDER} command.
|
||||
*
|
||||
* @param context The command context.
|
||||
* @param sendError A function to send an error message.
|
||||
* @param id The computer's id.
|
||||
* @param <T> The type of the client-side command context.
|
||||
* @return {@code 1} if a folder was opened, {@code 0} otherwise.
|
||||
*/
|
||||
private static <T> int handleOpenComputerCommand(T context, BiConsumer<T, Component> sendError, int id) {
|
||||
var server = Minecraft.getInstance().getSingleplayerServer();
|
||||
if (server == null) {
|
||||
sendError.accept(context, Component.literal("Not on a single-player server"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
var file = new File(ServerContext.get(server).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) {
|
||||
sendError.accept(context, Component.literal("Computer's folder does not exist"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Util.getPlatform().openFile(file);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@@ -7,8 +7,9 @@ package dan200.computercraft.client.gui;
|
||||
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
||||
import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
@@ -18,7 +19,9 @@ import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.network.server.UploadFileMessage;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
@@ -33,7 +36,6 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@@ -96,8 +98,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
getTerminal().update();
|
||||
|
||||
if (uploadNagDeadline != Long.MAX_VALUE && Util.getNanos() >= uploadNagDeadline) {
|
||||
new ItemToast(minecraft, displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
|
||||
.showOrReplace(minecraft.getToasts());
|
||||
new ItemToast(minecraft(), displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
|
||||
.showOrReplace(minecraft().getToasts());
|
||||
uploadNagDeadline = Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -145,6 +147,11 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
|| super.mouseDragged(x, y, button, deltaX, deltaY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFocused(@Nullable GuiEventListener listener) {
|
||||
// Don't clear and re-focus if we're already focused.
|
||||
if (listener != getFocused()) super.setFocused(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
|
||||
@@ -202,7 +209,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
return;
|
||||
}
|
||||
|
||||
if (toUpload.size() > 0) UploadFileMessage.send(menu, toUpload, ClientPlatformHelper.get()::sendToServer);
|
||||
if (!toUpload.isEmpty()) UploadFileMessage.send(menu, toUpload, ClientNetworking::sendToServer);
|
||||
}
|
||||
|
||||
public void uploadResult(UploadResult result, @Nullable Component message) {
|
||||
@@ -218,9 +225,13 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
}
|
||||
|
||||
private void alert(Component title, Component message) {
|
||||
OptionScreen.show(minecraft, title, message,
|
||||
Collections.singletonList(OptionScreen.newButton(OK, b -> minecraft.setScreen(this))),
|
||||
() -> minecraft.setScreen(this)
|
||||
OptionScreen.show(minecraft(), title, message,
|
||||
List.of(OptionScreen.newButton(OK, b -> minecraft().setScreen(this))),
|
||||
() -> minecraft().setScreen(this)
|
||||
);
|
||||
}
|
||||
|
||||
private Minecraft minecraft() {
|
||||
return Nullability.assertNonNull(minecraft);
|
||||
}
|
||||
}
|
||||
|
@@ -4,7 +4,7 @@
|
||||
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
import dan200.computercraft.shared.computer.menu.ComputerMenu;
|
||||
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
|
||||
@@ -29,51 +29,51 @@ public final class ClientInputHandler implements InputHandler {
|
||||
|
||||
@Override
|
||||
public void turnOn() {
|
||||
ClientPlatformHelper.get().sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
ClientPlatformHelper.get().sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.SHUTDOWN));
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.SHUTDOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reboot() {
|
||||
ClientPlatformHelper.get().sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueEvent(String event, @Nullable Object[] arguments) {
|
||||
ClientPlatformHelper.get().sendToServer(new QueueEventServerMessage(menu, event, arguments));
|
||||
ClientNetworking.sendToServer(new QueueEventServerMessage(menu, event, arguments));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown(int key, boolean repeat) {
|
||||
ClientPlatformHelper.get().sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key));
|
||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.Action.REPEAT : KeyEventServerMessage.Action.DOWN, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyUp(int key) {
|
||||
ClientPlatformHelper.get().sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.TYPE_UP, key));
|
||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.Action.UP, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClick(int button, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_CLICK, button, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.CLICK, button, x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp(int button, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_UP, button, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.UP, button, x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDrag(int button, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_DRAG, button, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.DRAG, button, x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseScroll(int direction, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.SCROLL, direction, x, y));
|
||||
}
|
||||
}
|
||||
|
@@ -1,13 +1,15 @@
|
||||
// SPDX-FileCopyrightText: 2021 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: LicenseRef-CCPL
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
||||
@@ -16,6 +18,7 @@ import net.minecraft.world.entity.player.Inventory;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
@@ -44,8 +47,8 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
protected void init() {
|
||||
// First ensure we're still grabbing the mouse, so the user can look around. Then reset bits of state that
|
||||
// grabbing unsets.
|
||||
minecraft.mouseHandler.grabMouse();
|
||||
minecraft.screen = this;
|
||||
minecraft().mouseHandler.grabMouse();
|
||||
minecraft().screen = this;
|
||||
KeyMapping.releaseAll();
|
||||
|
||||
super.init();
|
||||
@@ -64,13 +67,13 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) {
|
||||
minecraft.player.getInventory().swapPaint(pDelta);
|
||||
Objects.requireNonNull(minecraft().player).getInventory().swapPaint(pDelta);
|
||||
return super.mouseScrolled(pMouseX, pMouseY, pDelta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
minecraft.player.closeContainer();
|
||||
Objects.requireNonNull(minecraft().player).closeContainer();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@@ -93,12 +96,16 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
||||
|
||||
var font = minecraft.font;
|
||||
var font = minecraft().font;
|
||||
var lines = font.split(Component.translatable("gui.computercraft.pocket_computer_overlay"), (int) (width * 0.8));
|
||||
var y = 10;
|
||||
for (var line : lines) {
|
||||
graphics.drawString(font, line, (width / 2) - (minecraft.font.width(line) / 2), y, 0xFFFFFF, true);
|
||||
graphics.drawString(font, line, (width / 2) - (font.width(line) / 2), y, 0xFFFFFF, true);
|
||||
y += 9;
|
||||
}
|
||||
}
|
||||
|
||||
private Minecraft minecraft() {
|
||||
return Nullability.assertNonNull(minecraft);
|
||||
}
|
||||
}
|
||||
|
@@ -6,15 +6,22 @@ package dan200.computercraft.client.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.Tesselator;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.common.HeldItemMenu;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.media.PrintoutMenu;
|
||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.network.chat.Component;
|
||||
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 java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import static dan200.computercraft.client.render.PrintoutRenderer.*;
|
||||
import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMAP;
|
||||
|
||||
@@ -23,40 +30,75 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA
|
||||
*
|
||||
* @see dan200.computercraft.client.render.PrintoutRenderer
|
||||
*/
|
||||
public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
||||
private final boolean book;
|
||||
private final int pages;
|
||||
private final TextBuffer[] text;
|
||||
private final TextBuffer[] colours;
|
||||
private int page;
|
||||
public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu> implements ContainerListener {
|
||||
private PrintoutInfo printout = PrintoutInfo.DEFAULT;
|
||||
private int page = 0;
|
||||
|
||||
public PrintoutScreen(HeldItemMenu container, Inventory player, Component title) {
|
||||
public PrintoutScreen(PrintoutMenu container, Inventory player, Component title) {
|
||||
super(container, player, title);
|
||||
|
||||
imageHeight = Y_SIZE;
|
||||
}
|
||||
|
||||
var text = PrintoutItem.getText(container.getStack());
|
||||
this.text = new TextBuffer[text.length];
|
||||
for (var i = 0; i < this.text.length; i++) this.text[i] = new TextBuffer(text[i]);
|
||||
private void setPrintout(ItemStack stack) {
|
||||
var text = PrintoutItem.getText(stack);
|
||||
var textBuffers = new TextBuffer[text.length];
|
||||
for (var i = 0; i < textBuffers.length; i++) textBuffers[i] = new TextBuffer(text[i]);
|
||||
|
||||
var colours = PrintoutItem.getColours(container.getStack());
|
||||
this.colours = new TextBuffer[colours.length];
|
||||
for (var i = 0; i < this.colours.length; i++) this.colours[i] = new TextBuffer(colours[i]);
|
||||
var colours = PrintoutItem.getColours(stack);
|
||||
var colourBuffers = new TextBuffer[colours.length];
|
||||
for (var i = 0; i < colours.length; i++) colourBuffers[i] = new TextBuffer(colours[i]);
|
||||
|
||||
page = 0;
|
||||
pages = Math.max(this.text.length / PrintoutItem.LINES_PER_PAGE, 1);
|
||||
book = ((PrintoutItem) container.getStack().getItem()).getType() == PrintoutItem.Type.BOOK;
|
||||
var pages = Math.max(text.length / PrintoutItem.LINES_PER_PAGE, 1);
|
||||
var book = stack.is(ModRegistry.Items.PRINTED_BOOK.get());
|
||||
|
||||
printout = new PrintoutInfo(pages, book, textBuffers, colourBuffers);
|
||||
}
|
||||
|
||||
@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
|
||||
public boolean keyPressed(int key, int scancode, int modifiers) {
|
||||
if (key == GLFW.GLFW_KEY_RIGHT) {
|
||||
if (page < pages - 1) page++;
|
||||
nextPage();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == GLFW.GLFW_KEY_LEFT) {
|
||||
if (page > 0) page--;
|
||||
previousPage();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -68,13 +110,13 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
||||
if (super.mouseScrolled(x, y, delta)) return true;
|
||||
if (delta < 0) {
|
||||
// Scroll up goes to the next page
|
||||
if (page < pages - 1) page++;
|
||||
nextPage();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (delta > 0) {
|
||||
// Scroll down goes to the previous page
|
||||
if (page > 0) page--;
|
||||
previousPage();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -85,8 +127,9 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
||||
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
|
||||
// Draw the printout
|
||||
var renderer = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
|
||||
drawBorder(graphics.pose(), renderer, leftPos, topPos, 0, page, pages, book, FULL_BRIGHT_LIGHTMAP);
|
||||
drawText(graphics.pose(), renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutItem.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours);
|
||||
|
||||
drawBorder(graphics.pose(), renderer, leftPos, topPos, 0, page, printout.pages(), printout.book(), FULL_BRIGHT_LIGHTMAP);
|
||||
drawText(graphics.pose(), renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutItem.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, printout.text(), printout.colour());
|
||||
renderer.endBatch();
|
||||
}
|
||||
|
||||
@@ -105,4 +148,18 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
||||
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
|
||||
// Skip rendering labels.
|
||||
}
|
||||
|
||||
record PrintoutInfo(int pages, boolean book, TextBuffer[] text, TextBuffer[] colour) {
|
||||
public static final PrintoutInfo DEFAULT;
|
||||
|
||||
static {
|
||||
var textLines = new TextBuffer[PrintoutItem.LINES_PER_PAGE];
|
||||
Arrays.fill(textLines, new TextBuffer(" ".repeat(PrintoutItem.LINE_MAX_LENGTH)));
|
||||
|
||||
var colourLines = new TextBuffer[PrintoutItem.LINES_PER_PAGE];
|
||||
Arrays.fill(colourLines, new TextBuffer("f".repeat(PrintoutItem.LINE_MAX_LENGTH)));
|
||||
|
||||
DEFAULT = new PrintoutInfo(1, false, textLines, colourLines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,8 +8,8 @@ import com.mojang.blaze3d.vertex.Tesselator;
|
||||
import dan200.computercraft.client.render.RenderTypes;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.core.util.StringUtil;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
@@ -112,26 +112,8 @@ public class TerminalWidget extends AbstractWidget {
|
||||
}
|
||||
|
||||
private void paste() {
|
||||
var clipboard = Minecraft.getInstance().keyboardHandler.getClipboard();
|
||||
|
||||
// Clip to the first occurrence of \r or \n
|
||||
var newLineIndex1 = clipboard.indexOf('\r');
|
||||
var newLineIndex2 = clipboard.indexOf('\n');
|
||||
if (newLineIndex1 >= 0 && newLineIndex2 >= 0) {
|
||||
clipboard = clipboard.substring(0, Math.min(newLineIndex1, newLineIndex2));
|
||||
} else if (newLineIndex1 >= 0) {
|
||||
clipboard = clipboard.substring(0, newLineIndex1);
|
||||
} else if (newLineIndex2 >= 0) {
|
||||
clipboard = clipboard.substring(0, newLineIndex2);
|
||||
}
|
||||
|
||||
// Filter the string
|
||||
clipboard = SharedConstants.filterText(clipboard);
|
||||
if (!clipboard.isEmpty()) {
|
||||
// Clip to 512 characters and queue the event
|
||||
if (clipboard.length() > 512) clipboard = clipboard.substring(0, 512);
|
||||
computer.queueEvent("paste", new Object[]{ clipboard });
|
||||
}
|
||||
var clipboard = StringUtil.normaliseClipboardString(Minecraft.getInstance().keyboardHandler.getClipboard());
|
||||
if (!clipboard.isEmpty()) computer.queueEvent("paste", new Object[]{ clipboard });
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -264,7 +246,7 @@ public class TerminalWidget extends AbstractWidget {
|
||||
keysDown.clear();
|
||||
|
||||
// When blurring, we should make the last mouse button go up
|
||||
if (lastMouseButton > 0) {
|
||||
if (lastMouseButton >= 0) {
|
||||
computer.mouseUp(lastMouseButton + 1, lastMouseX + 1, lastMouseY + 1);
|
||||
lastMouseButton = -1;
|
||||
}
|
||||
|
@@ -47,7 +47,7 @@ public class ShaderMod {
|
||||
Optional<ShaderMod> get();
|
||||
}
|
||||
|
||||
private static class Storage {
|
||||
private static final class Storage {
|
||||
static final ShaderMod INSTANCE = ServiceLoader.load(Provider.class)
|
||||
.stream()
|
||||
.flatMap(x -> x.get().get().stream())
|
||||
|
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.integration.jei;
|
||||
package dan200.computercraft.client.integration.jei;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
@@ -22,7 +22,7 @@ import mezz.jei.api.runtime.IJeiRuntime;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@JeiPlugin
|
||||
public class JEIComputerCraft implements IModPlugin {
|
||||
@@ -61,7 +61,7 @@ public class JEIComputerCraft implements IModPlugin {
|
||||
var category = registry.createRecipeLookup(RecipeTypes.CRAFTING);
|
||||
category.get().forEach(wrapper -> {
|
||||
if (RecipeModHelpers.shouldRemoveRecipe(wrapper.getId())) {
|
||||
registry.hideRecipes(RecipeTypes.CRAFTING, Collections.singleton(wrapper));
|
||||
registry.hideRecipes(RecipeTypes.CRAFTING, List.of(wrapper));
|
||||
}
|
||||
});
|
||||
}
|
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.integration.jei;
|
||||
package dan200.computercraft.client.integration.jei;
|
||||
|
||||
import dan200.computercraft.shared.integration.UpgradeRecipeGenerator;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
@@ -15,7 +15,6 @@ import mezz.jei.api.recipe.category.IRecipeCategory;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.crafting.CraftingRecipe;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
class RecipeResolver implements IRecipeManagerPlugin {
|
||||
@@ -24,36 +23,36 @@ class RecipeResolver implements IRecipeManagerPlugin {
|
||||
@Override
|
||||
public <V> List<RecipeType<?>> getRecipeTypes(IFocus<V> focus) {
|
||||
var value = focus.getTypedValue().getIngredient();
|
||||
if (!(value instanceof ItemStack stack)) return Collections.emptyList();
|
||||
if (!(value instanceof ItemStack stack)) return List.of();
|
||||
|
||||
return switch (focus.getRole()) {
|
||||
case INPUT ->
|
||||
stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem || resolver.isUpgrade(stack)
|
||||
? Collections.singletonList(RecipeTypes.CRAFTING)
|
||||
: Collections.emptyList();
|
||||
? List.of(RecipeTypes.CRAFTING)
|
||||
: List.of();
|
||||
case OUTPUT -> stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem
|
||||
? Collections.singletonList(RecipeTypes.CRAFTING)
|
||||
: Collections.emptyList();
|
||||
default -> Collections.emptyList();
|
||||
? List.of(RecipeTypes.CRAFTING)
|
||||
: List.of();
|
||||
default -> List.of();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, V> List<T> getRecipes(IRecipeCategory<T> recipeCategory, IFocus<V> focus) {
|
||||
if (!(focus.getTypedValue().getIngredient() instanceof ItemStack stack) || recipeCategory.getRecipeType() != RecipeTypes.CRAFTING) {
|
||||
return Collections.emptyList();
|
||||
return List.of();
|
||||
}
|
||||
|
||||
return switch (focus.getRole()) {
|
||||
case INPUT -> cast(resolver.findRecipesWithInput(stack));
|
||||
case OUTPUT -> cast(resolver.findRecipesWithOutput(stack));
|
||||
default -> Collections.emptyList();
|
||||
default -> List.of();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> getRecipes(IRecipeCategory<T> recipeCategory) {
|
||||
return Collections.emptyList();
|
||||
return List.of();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@@ -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 = new ResourceLocation(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, 1, 1, 1, 1);
|
||||
}
|
||||
|
||||
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, 1, 1, 1, 1);
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.network;
|
||||
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
/**
|
||||
* Methods for sending packets from clients to the server.
|
||||
*/
|
||||
public final class ClientNetworking {
|
||||
private ClientNetworking() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a network message to the server.
|
||||
*
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public static void sendToServer(NetworkMessage<ServerNetworkContext> message) {
|
||||
var connection = Minecraft.getInstance().getConnection();
|
||||
if (connection != null) connection.send(ClientPlatformHelper.get().createPacket(message));
|
||||
}
|
||||
}
|
@@ -4,6 +4,7 @@
|
||||
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.client.ClientTableFormatter;
|
||||
import dan200.computercraft.client.gui.AbstractComputerScreen;
|
||||
import dan200.computercraft.client.gui.OptionScreen;
|
||||
@@ -16,12 +17,13 @@ import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.computer.upload.UploadResult;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.speaker.EncodedAudio;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
@@ -29,18 +31,17 @@ import javax.annotation.Nullable;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The base implementation of {@link ClientNetworkContext}.
|
||||
* <p>
|
||||
* This should be extended by mod loader specific modules with the remaining abstract methods.
|
||||
* The client-side implementation of {@link ClientNetworkContext}.
|
||||
*/
|
||||
public abstract class AbstractClientNetworkContext implements ClientNetworkContext {
|
||||
@AutoService(ClientNetworkContext.class)
|
||||
public final class ClientNetworkContextImpl implements ClientNetworkContext {
|
||||
@Override
|
||||
public final void handleChatTable(TableBuilder table) {
|
||||
public void handleChatTable(TableBuilder table) {
|
||||
ClientTableFormatter.INSTANCE.display(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleComputerTerminal(int containerId, TerminalState terminal) {
|
||||
public void handleComputerTerminal(int containerId, TerminalState terminal) {
|
||||
Player player = Minecraft.getInstance().player;
|
||||
if (player != null && player.containerMenu.containerId == containerId && player.containerMenu instanceof ComputerMenu menu) {
|
||||
menu.updateTerminal(terminal);
|
||||
@@ -48,7 +49,7 @@ public abstract class AbstractClientNetworkContext implements ClientNetworkConte
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleMonitorData(BlockPos pos, TerminalState terminal) {
|
||||
public void handleMonitorData(BlockPos pos, @Nullable TerminalState terminal) {
|
||||
var player = Minecraft.getInstance().player;
|
||||
if (player == null) return;
|
||||
|
||||
@@ -59,44 +60,44 @@ public abstract class AbstractClientNetworkContext implements ClientNetworkConte
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handlePocketComputerData(int instanceId, ComputerState state, int lightState, TerminalState terminal) {
|
||||
var computer = ClientPocketComputers.get(instanceId, terminal.colour);
|
||||
computer.setState(state, lightState);
|
||||
if (terminal.hasTerminal()) computer.setTerminal(terminal);
|
||||
public void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable String name) {
|
||||
var mc = Minecraft.getInstance();
|
||||
ClientPlatformHelper.get().playStreamingMusic(pos, sound);
|
||||
if (name != null) mc.gui.setNowPlaying(Component.literal(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handlePocketComputerDeleted(int instanceId) {
|
||||
public void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, @Nullable TerminalState terminal) {
|
||||
ClientPocketComputers.setState(instanceId, state, lightState, terminal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePocketComputerDeleted(UUID instanceId) {
|
||||
ClientPocketComputers.remove(instanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume) {
|
||||
SpeakerManager.getSound(source).playAudio(reifyPosition(position), volume);
|
||||
public void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume, EncodedAudio buffer) {
|
||||
SpeakerManager.getSound(source).playAudio(reifyPosition(position), volume, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerAudioPush(UUID source, ByteBuf buffer) {
|
||||
SpeakerManager.getSound(source).pushAudio(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerMove(UUID source, SpeakerPosition.Message position) {
|
||||
public void handleSpeakerMove(UUID source, SpeakerPosition.Message position) {
|
||||
SpeakerManager.moveSound(source, reifyPosition(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerPlay(UUID source, SpeakerPosition.Message position, ResourceLocation sound, float volume, float pitch) {
|
||||
public void handleSpeakerPlay(UUID source, SpeakerPosition.Message position, ResourceLocation sound, float volume, float pitch) {
|
||||
SpeakerManager.getSound(source).playSound(reifyPosition(position), sound, volume, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerStop(UUID source) {
|
||||
public void handleSpeakerStop(UUID source) {
|
||||
SpeakerManager.stopSound(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleUploadResult(int containerId, UploadResult result, @Nullable Component errorMessage) {
|
||||
public void handleUploadResult(int containerId, UploadResult result, @Nullable Component errorMessage) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
|
||||
var screen = OptionScreen.unwrap(minecraft.screen);
|
@@ -9,6 +9,10 @@ import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@@ -18,11 +22,12 @@ public interface ClientPlatformHelper extends dan200.computercraft.impl.client.C
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a network message to the server.
|
||||
* Convert a serverbound {@link NetworkMessage} to a Minecraft {@link Packet}.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param message The messsge to convert.
|
||||
* @return The converted message.
|
||||
*/
|
||||
void sendToServer(NetworkMessage<ServerNetworkContext> message);
|
||||
Packet<ServerGamePacketListener> createPacket(NetworkMessage<ServerNetworkContext> message);
|
||||
|
||||
/**
|
||||
* Render a {@link BakedModel}, using any loader-specific hooks.
|
||||
@@ -35,4 +40,13 @@ public interface ClientPlatformHelper extends dan200.computercraft.impl.client.C
|
||||
* @param tints Block colour tints to apply to the model.
|
||||
*/
|
||||
void renderBakedModel(PoseStack transform, MultiBufferSource buffers, BakedModel model, int lightmapCoord, int overlayLight, @Nullable int[] tints);
|
||||
|
||||
/**
|
||||
* Play a record at a particular position.
|
||||
*
|
||||
* @param pos The position to play this record.
|
||||
* @param sound The record to play, or {@code null} to stop it.
|
||||
* @see net.minecraft.client.renderer.LevelRenderer#playStreamingMusic(SoundEvent, BlockPos)
|
||||
*/
|
||||
void playStreamingMusic(BlockPos pos, @Nullable SoundEvent sound);
|
||||
}
|
||||
|
@@ -4,21 +4,25 @@
|
||||
|
||||
package dan200.computercraft.client.pocket;
|
||||
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Maps {@link ServerComputer#getInstanceID()} to locals {@link PocketComputerData}.
|
||||
* Maps {@link ServerComputer#getInstanceUUID()} to locals {@link PocketComputerData}.
|
||||
* <p>
|
||||
* This is populated by {@link PocketComputerDataMessage} and accessed when rendering pocket computers
|
||||
*/
|
||||
public final class ClientPocketComputers {
|
||||
private static final Int2ObjectMap<PocketComputerData> instances = new Int2ObjectOpenHashMap<>();
|
||||
private static final Map<UUID, PocketComputerData> instances = new HashMap<>();
|
||||
|
||||
private ClientPocketComputers() {
|
||||
}
|
||||
@@ -27,25 +31,29 @@ public final class ClientPocketComputers {
|
||||
instances.clear();
|
||||
}
|
||||
|
||||
public static void remove(int id) {
|
||||
public static void remove(UUID id) {
|
||||
instances.remove(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create a pocket computer.
|
||||
* Set the state of a pocket computer.
|
||||
*
|
||||
* @param instanceId The instance ID of the pocket computer.
|
||||
* @param advanced Whether this computer has an advanced terminal.
|
||||
* @return The pocket computer data.
|
||||
* @param instanceId The instance ID of the pocket computer.
|
||||
* @param state The computer state of the pocket computer.
|
||||
* @param lightColour The current colour of the modem light.
|
||||
* @param terminalData The current terminal contents.
|
||||
*/
|
||||
public static PocketComputerData get(int instanceId, boolean advanced) {
|
||||
public static void setState(UUID instanceId, ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
|
||||
var computer = instances.get(instanceId);
|
||||
if (computer == null) instances.put(instanceId, computer = new PocketComputerData(advanced));
|
||||
return computer;
|
||||
if (computer == null) {
|
||||
instances.put(instanceId, new PocketComputerData(state, lightColour, terminalData));
|
||||
} else {
|
||||
computer.setState(state, lightColour, terminalData);
|
||||
}
|
||||
}
|
||||
|
||||
public static PocketComputerData get(ItemStack stack) {
|
||||
var family = stack.getItem() instanceof PocketComputerItem computer ? computer.getFamily() : ComputerFamily.NORMAL;
|
||||
return get(PocketComputerItem.getInstanceID(stack), family != ComputerFamily.NORMAL);
|
||||
public static @Nullable PocketComputerData get(ItemStack stack) {
|
||||
var id = PocketComputerItem.getInstanceID(stack);
|
||||
return id == null ? null : instances.get(id);
|
||||
}
|
||||
}
|
||||
|
@@ -4,13 +4,13 @@
|
||||
|
||||
package dan200.computercraft.client.pocket;
|
||||
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Clientside data about a pocket computer.
|
||||
* <p>
|
||||
@@ -21,20 +21,22 @@ import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||
* @see ClientPocketComputers The registry which holds pocket computers.
|
||||
* @see PocketServerComputer The server-side pocket computer.
|
||||
*/
|
||||
public class PocketComputerData {
|
||||
private final NetworkedTerminal terminal;
|
||||
private ComputerState state = ComputerState.OFF;
|
||||
private int lightColour = -1;
|
||||
public final class PocketComputerData {
|
||||
private @Nullable NetworkedTerminal terminal;
|
||||
private ComputerState state;
|
||||
private int lightColour;
|
||||
|
||||
public PocketComputerData(boolean colour) {
|
||||
terminal = new NetworkedTerminal(Config.pocketTermWidth, Config.pocketTermHeight, colour);
|
||||
PocketComputerData(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
|
||||
this.state = state;
|
||||
this.lightColour = lightColour;
|
||||
if (terminalData != null) terminal = terminalData.create();
|
||||
}
|
||||
|
||||
public int getLightState() {
|
||||
return state != ComputerState.OFF ? lightColour : -1;
|
||||
}
|
||||
|
||||
public Terminal getTerminal() {
|
||||
public @Nullable NetworkedTerminal getTerminal() {
|
||||
return terminal;
|
||||
}
|
||||
|
||||
@@ -42,12 +44,16 @@ public class PocketComputerData {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(ComputerState state, int lightColour) {
|
||||
void setState(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
|
||||
this.state = state;
|
||||
this.lightColour = lightColour;
|
||||
}
|
||||
|
||||
public void setTerminal(TerminalState state) {
|
||||
state.apply(terminal);
|
||||
if (terminalData != null) {
|
||||
if (terminal == null) {
|
||||
terminal = terminalData.create();
|
||||
} else {
|
||||
terminalData.apply(terminal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,51 @@
|
||||
// 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.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, PrintoutItem.getPageCount(item));
|
||||
}
|
||||
}
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user