1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-15 22:17:39 +00:00

Compare commits

...

46 Commits

Author SHA1 Message Date
Jonathan Coates
209b1ddbf9 Bump CC:T to 1.111.0 2024-05-28 18:19:13 +01:00
Jonathan Coates
0c9f9a8652 Warn when Optifine is installed
We keep getting bug reports on 1.20.1 about an Optifine bug that causes
Forge's capabilities to not work (#1458). The cause of this bug is not
immediately visible to users, and can be very confusing when hit.

Optifine have not released a fix for this bug (despite it being reported
a year ago), and we continue to receive bug reports about it.

Nobody likes it when mods complain about other mods. So much Minecraft
drama can be traced back to this, and it's a slippery slope to go down.
I've tried to keep this as unobtrusive as possible — it's just a chat
message at world join, and it'll turn off if the bug is fixed.
2024-05-28 18:10:50 +01:00
Jonathan Coates
862d92785e Don't expose a menu provider for computers
We can't safely use this anyway (as custom data is not sent), so better
not to expose it at all. Fixes #1844.
2024-05-28 09:47:12 +01:00
Jonathan Coates
d48b85d50c Add r+/w+ support to io library 2024-05-26 10:16:33 +01:00
Jonathan Coates
4d619de357 Don't publish Gradle module metadata for common
Fixes #1842
2024-05-26 09:34:10 +01:00
Daniel Ratcliffe
57c289f173 Allow planks to be used for building in "adventure" 2024-05-25 10:04:45 +01:00
Jonathan Coates
f63f85921f Fix missing quotes in the settings example 2024-05-19 08:38:41 +01:00
Jonathan Coates
c7e49d1929 Use RecordItem.getDisplayName to get audio title
Rather than constructing the component manually. This should be more
compatible with mods that override getDisplayName.
2024-05-09 22:54:03 +01:00
Jonathan Coates
1e214f329e Build docs for all MC versions 2024-05-06 09:59:09 +01:00
Jonathan Coates
de930c8d09 Split up turtle textures (#1813)
Turtles currently read their textures from a single 128x128 sprite
sheet. Most of this texture is unused which means we end up wasting a
lot of the block texture atlas[^1].

This change splits up the turtle textures into individual 32x32
textures[^2], one for each side, and then an additional backpack
texture.

I'm very sorry to any resource pack artists out there. The
tools/update-resources.py script will update existing packs, but does
not (currently) handle non-standard resolutions.

[^1]: It used to be worse: https://github.com/dan200/ComputerCraft/issues/145

[^2]: Turtle textures are a bit weird, in that they mostly *look* 16x16,
  but have some detail in places.
2024-04-30 20:58:07 +00:00
Weblate
735e7ce09b Translations for Italian
Co-authored-by: Alessandro <ale.proto00@gmail.com>
2024-04-29 19:00:14 +00:00
Jonathan Coates
6e9799316a Update ErrorProne 2024-04-28 18:32:19 +01:00
Jonathan Coates
4e90240922 Bump CC:T to 1.110.3 2024-04-26 18:22:06 +01:00
Jonathan Coates
1a87d1bf45 Move shared generated resources to common project
In 1.20.1, Forge and Fabric have different "common" tag conventions (for
instance, Forge uses forge:dusts/redstone, while Fabric uses
c:redstone_dusts). This means the generated recipes (and advancements)
will be different for the two loader projects. As such, we run data
generators for each loader, and store the results separately.

However, aside from some recipes and advancements, most resources /are/
the same between the two. This means we end up with a lot of duplicate
files, which make the diff even harder to read. This gets worse in
1.20.5, when NeoForge and Fabric have (largely) unified their tag names.

This commit now merges the generated resources of the two loaders,
moving shared files to the common project.

 - Add a new MergeTrees command, to handle the de-duplication of files.
 - Change the existing runData tasks to write to
   build/generatedResources.
 - Add a new :common:runData task, that reads from the
   build/generatedResources folder and writes to the per-project
   src/generated/resources.
2024-04-26 18:09:08 +01:00
Jonathan Coates
00e2e2bd2d Switch to vanilla's stillValid implementation 2024-04-25 18:21:23 +01:00
Jonathan Coates
7c1f40031b Some cleanup to network messages
- Use enums for key and mouse actions, rather than integer ids.
 - Change TerminalState to always contain a terminal. We now make
   TerminalState nullable when we want to skip sending anything.
2024-04-25 18:19:34 +01:00
Jonathan Coates
929debd382 Don't build the webside on Windows/Mac
It seems to stall on Mac, and unlike Windows, I don't have access to a
machine to debug it :/.
2024-04-24 21:49:49 +01:00
Jonathan Coates
4980b7355d Don't share CharsetDecoders across threads
Fixes #1803
2024-04-24 21:19:30 +01:00
Jonathan Coates
925092add3 Fix build on Windows
- Force encoding to UTF-8
 - Fix npm not being found on the path
 - Test building common/web on OSX and Windows
2024-04-24 17:55:48 +01:00
Jonathan Coates
550296edc5 Fix typo in speaker docs
Closes #1799
2024-04-21 09:45:02 +01:00
Jonathan Coates
0771c4891b Various Gradle tweaks
- Update Gradle to 8.7
 - Configure IntelliJ to build internally, rather than delgating to
   Gradle. We've seen some weird issues with using delegated builds, so
   best avoided.
 - Remove gitpod config. This has been broken for a while (used Java 16
   rather than 17) and nobody noticed, so I suspect nobody uses this.
2024-04-19 18:14:51 +01:00
Jonathan Coates
776fa00b94 Update to latest TeaVM
- Add the core TeaVM jar to the runtime the classpath, to ensure
   various runtime classes are present.
 - Fix computer initialisation errors not being displayed on the screen.
   The terminal was set to the default 0x0 size when logging the error,
   and so never displayed anything!
2024-04-17 21:57:11 +01:00
Jonathan Coates
03bb279206 Move computer right click code to the block
Rather than handling right clicks within the block entity code, we now
handle it within the block. Turtles now handle the nametagging
behaviour themselves, rather than overriding canNameWithTag.
2024-04-17 15:01:50 +01:00
Weblate
fabd77132d Translations for Czech
Co-authored-by: Patriik <apatriik0@gmail.com>
2024-04-09 08:54:05 +00:00
Jonathan Coates
95be0a25bf Update Cobalt to 0.9.3
- Fix some errors missing source positions
 - Poll interrupted state when parsing Lua
2024-04-08 12:18:21 +01:00
Jonathan Coates
ad49325376 Bump CC:T to 1.110.2 2024-04-07 21:20:56 +01:00
Jonathan Coates
825d45eb26 Fix NPE when rendering turtle's label
Minecraft.hitResult may /technically/ be null when rendering a turtle.
In vanilla, this doesn't appear to happen, but other mods (e.g.
Immersive Portals) may still take advantage of this.

This hitResult is then propagated to BlockEntityRenderDispatcher, where
the field was /not/ marked as nullable. This meant we didn't even notice
the potential of an NPE!

Closes #1775
2024-04-06 08:46:19 +01:00
Jonathan Coates
8b2516abb5 Update to latest NullAway
This fixes several issues with @Nullable fields not being checked. This
is great in principle, but a little annoying in practice as MC's
@Nullable annotations are sometimes a little overly strict -- we now
need to wrap a couple of things in assertNonNull checks.
2024-04-06 08:38:44 +01:00
Jonathan Coates
bce099ef32 Allow mounting folders in the standalone emulator
This theoretically allows you to use the emulator to run the test suite
(via  --mount-ro projects/core/src/test/resources/test-rom/:test-rom),
but not sure how useful this is in practice.
2024-04-03 21:27:18 +01:00
Jonathan Coates
6d14ce625f Use the correct modem in create:brittle
I tested this in-game, I swear! Just, typically, only with ender and
wired modems.
2024-04-03 09:29:31 +01:00
Jonathan Coates
c8eadf4011 Register CC's modems as brittle
This tells Create that modems will pop-off if their neighbour is moved,
and so changes the order that the block is moved in.

We possibly should use BlockMovementChecks.AttachedCheck instead, to
properly handle the direction modems are facing in. However, this
doesn't appear to be part of the public API, so probably best avoided.

Fixes #948
2024-04-03 08:44:30 +01:00
Jonathan Coates
0c1ab780bb Validate arguments in the vector API
This doesn't produce the best error messages (should "self" be argument
0 or 1?), but is better than throwing errors in vector's internals.
2024-04-01 22:25:08 +01:00
Jonathan Coates
0f623c2cca Move can-place modem logic to one place
This should make future changes easier. Closes #1769.
2024-04-01 13:55:44 +01:00
Matthew Wilbern
b9ba2534a4 speaker sound command (#1747) 2024-03-29 10:24:11 +00:00
Jonathan Coates
c764981a40 Merge pull request #1761 from cc-tweaked/feature/no-play-record
Prevent playing music discs with speaker.playSound
2024-03-29 07:55:31 +00:00
Jonathan Coates
6363164f2b Fix creating a zero-sized pocket terminal
When the terminal data is not present, width/height are set to 0, rather
than the terminal's width/height. This meant we'd create an empty
terminal, which then crashes when we try to render it.

We now make the terminal nullable and initialise it the first time we
receive the terminal data. To prevent future mistakes, we hide
width/height, and use TerminalState.create everywhere.

Fixes #1765
2024-03-26 21:59:41 +00:00
Jonathan Coates
63580b4acb Fallback to the current side when getting fluid cap
We did this for item caps in 9af1aa1ecf,
but makes sense to do this for fluid methods too.
2024-03-26 21:40:44 +00:00
Jonathan Coates
9af1aa1ecf Fallback to the current side when getting item cap
Fixes #1764
2024-03-25 08:59:08 +00:00
Jonathan Coates
ad0f551204 Merge pull request #1763 from cyberbit/patch-1
Fix cc.image.nft.draw signature
2024-03-24 15:18:44 +00:00
Jonathan Coates
0d3e00cc41 Small cleanup to OS API docs
- Mention the timer event in os.startTimer. Really we should have a
   similar example here too, but let's at least link the two for now.
 - Fix strftime link
2024-03-24 15:12:23 +00:00
cyberbit
836d6b939e Fix cc.image.nft.draw signature 2024-03-24 09:54:01 -05:00
Jonathan Coates
0e5248e5e6 Prevent playing music discs with speaker.playSound
I have mixed feelings about speaker.playSound. On one hand, it's pretty
useful to be able to play any sound. On the other, it sometimes feels
... maybe a little too magic?

One particular thing I don't like is that it allows you to play
arbitrary records, which sidesteps both a vanilla mechanic (finding
record discs) and existing CC functionality (disk.playAudio). We now
prevent playing record tracks from the speaker.
2024-03-24 12:53:57 +00:00
Jonathan Coates
e154b0db2a Fix speaker.playSound overwriting current sound
playSound should return false if we've already played a sound this tick,
rather than overwriting it.
2024-03-24 12:20:53 +00:00
Jonathan Coates
ae767eb5be Improve error when no path is passed to "speaker"
Co-authored-by: Matthew W <fatboychummy@gmail.com>
2024-03-24 11:10:36 +00:00
Jonathan Coates
777aa34bb0 Bump CC:T to 1.110.1 2024-03-23 11:09:42 +00:00
Jonathan Coates
286f969f94 Remove computers from both lookups when they timeout
In 5d8c46c7e6, we switched to using UUIDs
for looking up computers (rather than an integer ID). However, for
compatibility in some of the command code, we need to maintain the old
integer lookup map.

Most of the code was updated to handle this, *except* the code to remove
a computer from the registry. This meant that we'd fail to remove a
computer from the UUID lookup map, so computers ended up in a phantom
state where they were destroyed, but still accessible.

This is not an issue on 1.20.4, because the legacy int lookup map was
removed.

Fixes #1760
2024-03-23 10:59:47 +00:00
638 changed files with 1560 additions and 3781 deletions

View File

@@ -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() }}

View File

@@ -3,8 +3,7 @@ name: Build documentation
on:
push:
branches:
- mc-1.19.x
- mc-1.20.x
- mc-*
jobs:
make_doc:
@@ -13,16 +12,16 @@ jobs:
steps:
- name: Clone repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Set up Java
uses: actions/setup-java@v1
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-') }}

View File

@@ -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

View File

@@ -8,8 +8,7 @@ Files:
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/*/src/generated/*
projects/web/src/htmlTransform/export/index.json
projects/web/src/htmlTransform/export/items/minecraft/*
Comment: Generated/data files are CC0.

View File

@@ -29,9 +29,9 @@ automatically with GitHub, so please don't submit PRs adding/changing translatio
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 (JDK). This can be downloaded from [Adoptium].
- [Git](https://git-scm.com/).
- If you want to work on documentation, [NodeJS][node].
- [NodeJS][node].
- Download CC: Tweaked's source code:
```

View File

@@ -5,9 +5,8 @@
import cc.tweaked.gradle.JUnitExt
import net.fabricmc.loom.api.LoomGradleExtensionAPI
import net.fabricmc.loom.util.gradle.SourceSetHelper
import org.jetbrains.gradle.ext.compiler
import org.jetbrains.gradle.ext.runConfigurations
import org.jetbrains.gradle.ext.settings
import org.jetbrains.gradle.ext.*
import org.jetbrains.gradle.ext.Application
plugins {
publishing
@@ -86,6 +85,19 @@ idea.project.settings.runConfigurations {
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 {

View File

@@ -94,9 +94,8 @@ 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

View File

@@ -35,7 +35,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(
@@ -226,12 +225,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]")
}

View 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)
}

View File

@@ -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")
}
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -131,7 +131,7 @@ 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.ReadHandle.read`] if you prefer.

View File

@@ -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.110.0
modVersion=1.111.0
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.20.1

View File

@@ -26,7 +26,7 @@ slf4j = "2.0.1"
asm = "9.6"
autoService = "1.1.1"
checkerFramework = "3.42.0"
cobalt = "0.9.2"
cobalt = "0.9.3"
commonsCli = "1.6.0"
jetbrainsAnnotations = "24.1.0"
jsr305 = "3.0.2"
@@ -57,22 +57,22 @@ jmh = "1.37"
cctJavadoc = "1.8.2"
checkstyle = "10.14.1"
curseForgeGradle = "1.0.14"
errorProne-core = "2.23.0"
errorProne-core = "2.27.0"
errorProne-plugin = "3.1.0"
fabric-loom = "1.5.7"
forgeGradle = "6.0.20"
fabric-loom = "1.6.7"
forgeGradle = "6.0.21"
githubRelease = "2.5.2"
gradleVersions = "0.50.0"
ideaExt = "1.1.7"
illuaminate = "0.1.0-69-gf294ab2"
illuaminate = "0.1.0-71-g378d86e"
librarian = "1.+"
lwjgl = "3.3.3"
minotaur = "2.+"
nullAway = "0.9.9"
nullAway = "0.10.25"
spotless = "6.23.3"
taskTree = "2.1.1"
teavm = "0.10.0-SQUID.3"
vanillaExtract = "0.1.2"
teavm = "0.10.0-SQUID.4"
vanillaExtract = "0.1.3"
versionCatalogUpdate = "0.8.1"
[libraries]
@@ -154,6 +154,7 @@ minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur"
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
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" }

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View File

@@ -11,6 +11,12 @@ plugins {
id("cc-tweaked.publishing")
}
sourceSets {
main {
resources.srcDir("src/generated/resources")
}
}
minecraft {
accessWideners(
"src/main/resources/computercraft.accesswidener",
@@ -105,3 +111,21 @@ val lintLua by tasks.registering(IlluaminateExec::class) {
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 }

View File

@@ -9,6 +9,7 @@ import dan200.computercraft.client.gui.widgets.DynamicImageButton;
import dan200.computercraft.client.gui.widgets.TerminalWidget;
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,6 +19,7 @@ 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;
@@ -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;
}
}
@@ -207,7 +209,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
return;
}
if (toUpload.size() > 0) UploadFileMessage.send(menu, toUpload, ClientNetworking::sendToServer);
if (!toUpload.isEmpty()) UploadFileMessage.send(menu, toUpload, ClientNetworking::sendToServer);
}
public void uploadResult(UploadResult result, @Nullable Component message) {
@@ -223,9 +225,13 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
}
private void alert(Component title, Component message) {
OptionScreen.show(minecraft, title, message,
List.of(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);
}
}

View File

@@ -49,31 +49,31 @@ public final class ClientInputHandler implements InputHandler {
@Override
public void keyDown(int key, boolean repeat) {
ClientNetworking.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) {
ClientNetworking.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) {
ClientNetworking.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) {
ClientNetworking.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) {
ClientNetworking.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) {
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y));
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.Action.SCROLL, direction, x, y));
}
}

View File

@@ -6,8 +6,10 @@ 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);
}
}

View File

@@ -49,7 +49,7 @@ public final class ClientNetworkContextImpl implements ClientNetworkContext {
}
@Override
public void handleMonitorData(BlockPos pos, TerminalState terminal) {
public void handleMonitorData(BlockPos pos, @Nullable TerminalState terminal) {
var player = Minecraft.getInstance().player;
if (player == null) return;
@@ -67,7 +67,7 @@ public final class ClientNetworkContextImpl implements ClientNetworkContext {
}
@Override
public void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, TerminalState terminal) {
public void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, @Nullable TerminalState terminal) {
ClientPocketComputers.setState(instanceId, state, lightState, terminal);
}

View File

@@ -6,7 +6,6 @@ package dan200.computercraft.client.pocket;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
import dan200.computercraft.shared.computer.terminal.TerminalState;
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
@@ -44,16 +43,13 @@ public final class ClientPocketComputers {
* @param lightColour The current colour of the modem light.
* @param terminalData The current terminal contents.
*/
public static void setState(UUID instanceId, ComputerState state, int lightColour, TerminalState terminalData) {
public static void setState(UUID instanceId, ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
var computer = instances.get(instanceId);
if (computer == null) {
var terminal = new NetworkedTerminal(terminalData.width, terminalData.height, terminalData.colour);
instances.put(instanceId, computer = new PocketComputerData(state, lightColour, terminal));
instances.put(instanceId, new PocketComputerData(state, lightColour, terminalData));
} else {
computer.setState(state, lightColour);
computer.setState(state, lightColour, terminalData);
}
if (terminalData.hasTerminal()) terminalData.apply(computer.getTerminal());
}
public static @Nullable PocketComputerData get(ItemStack stack) {

View File

@@ -6,8 +6,11 @@ package dan200.computercraft.client.pocket;
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.pocket.core.PocketServerComputer;
import javax.annotation.Nullable;
/**
* Clientside data about a pocket computer.
* <p>
@@ -19,21 +22,21 @@ import dan200.computercraft.shared.pocket.core.PocketServerComputer;
* @see PocketServerComputer The server-side pocket computer.
*/
public final class PocketComputerData {
private final NetworkedTerminal terminal;
private @Nullable NetworkedTerminal terminal;
private ComputerState state;
private int lightColour;
PocketComputerData(ComputerState state, int lightColour, NetworkedTerminal terminal) {
PocketComputerData(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
this.state = state;
this.lightColour = lightColour;
this.terminal = terminal;
if (terminalData != null) terminal = terminalData.create();
}
public int getLightState() {
return state != ComputerState.OFF ? lightColour : -1;
}
public NetworkedTerminal getTerminal() {
public @Nullable NetworkedTerminal getTerminal() {
return terminal;
}
@@ -41,8 +44,16 @@ public final class PocketComputerData {
return state;
}
void setState(ComputerState state, int lightColour) {
void setState(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
this.state = state;
this.lightColour = lightColour;
if (terminalData != null) {
if (terminal == null) {
terminal = terminalData.create();
} else {
terminalData.apply(terminal);
}
}
}
}

View File

@@ -17,6 +17,8 @@ import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import java.util.Objects;
/**
* A base class for items which have map-like rendering when held in the hand.
*
@@ -35,7 +37,7 @@ public abstract class ItemMapLikeRenderer {
protected abstract void renderItem(PoseStack transform, MultiBufferSource render, ItemStack stack, int light);
public void renderItemFirstPerson(PoseStack transform, MultiBufferSource render, int lightTexture, InteractionHand hand, float pitch, float equipProgress, float swingProgress, ItemStack stack) {
Player player = Minecraft.getInstance().player;
Player player = Objects.requireNonNull(Minecraft.getInstance().player);
transform.pushPose();
if (hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty()) {

View File

@@ -55,7 +55,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
// Render the label
var label = turtle.getLabel();
var hit = renderer.cameraHitResult;
if (label != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())) {
if (label != null && hit != null && hit.getType() == HitResult.Type.BLOCK && turtle.getBlockPos().equals(((BlockHitResult) hit).getBlockPos())) {
var mc = Minecraft.getInstance();
var font = this.font;

View File

@@ -0,0 +1,12 @@
{
"parent": "computercraft:block/turtle_base",
"textures": {
"back": "computercraft:block/turtle_advanced_back",
"backpack": "computercraft:block/turtle_advanced_backpack",
"bottom": "computercraft:block/turtle_advanced_bottom",
"front": "computercraft:block/turtle_advanced_front",
"left": "computercraft:block/turtle_advanced_left",
"right": "computercraft:block/turtle_advanced_right",
"top": "computercraft:block/turtle_advanced_top"
}
}

Some files were not shown because too many files have changed in this diff Show More