mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-18 07:27:39 +00:00
Compare commits
72 Commits
v1.20.1-1.
...
v1.20.1-1.
Author | SHA1 | Date | |
---|---|---|---|
![]() |
209b1ddbf9 | ||
![]() |
0c9f9a8652 | ||
![]() |
862d92785e | ||
![]() |
d48b85d50c | ||
![]() |
4d619de357 | ||
![]() |
57c289f173 | ||
![]() |
f63f85921f | ||
![]() |
c7e49d1929 | ||
![]() |
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 |
30
.github/workflows/main-ci.yml
vendored
30
.github/workflows/main-ci.yml
vendored
@@ -9,16 +9,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 📥 Clone repository
|
- name: 📥 Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: 📥 Set up Java
|
- name: 📥 Set up Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 17
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: 📥 Setup Gradle
|
- name: 📥 Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/actions/setup-gradle@v3
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
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"' \;
|
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
|
- name: 📤 Upload Jar
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: CC-Tweaked
|
name: CC-Tweaked
|
||||||
path: ./jars
|
path: ./jars
|
||||||
|
|
||||||
- name: 📤 Upload coverage
|
- name: 📤 Upload coverage
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v4
|
||||||
|
|
||||||
build-core:
|
build-core:
|
||||||
strategy:
|
strategy:
|
||||||
@@ -81,24 +81,28 @@ jobs:
|
|||||||
runs-on: ${{ matrix.uses }}
|
runs-on: ${{ matrix.uses }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone repository
|
- name: 📥 Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Java
|
- name: 📥 Set up Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 17
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: 📥 Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/actions/setup-gradle@v3
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
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: |
|
run: |
|
||||||
./gradlew --configure-on-demand :core:test
|
./gradlew --configure-on-demand :core:test
|
||||||
|
|
||||||
- name: Parse test reports
|
- name: 🧪 Parse test reports
|
||||||
run: python3 ./tools/parse-reports.py
|
run: python3 ./tools/parse-reports.py
|
||||||
if: ${{ failure() }}
|
if: ${{ failure() }}
|
||||||
|
9
.github/workflows/make-doc.yml
vendored
9
.github/workflows/make-doc.yml
vendored
@@ -3,8 +3,7 @@ name: Build documentation
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- mc-1.19.x
|
- mc-*
|
||||||
- mc-1.20.x
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
make_doc:
|
make_doc:
|
||||||
@@ -13,16 +12,16 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clone repository
|
- name: Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Java
|
- name: Set up Java
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
java-version: 17
|
java-version: 17
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
|
|
||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/gradle-build-action@v2
|
uses: gradle/actions/setup-gradle@v3
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||||
|
|
||||||
|
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
|
|
@@ -8,8 +8,7 @@ Files:
|
|||||||
projects/common/src/main/resources/assets/computercraft/sounds/empty.ogg
|
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/computercraft/turtle_upgrades/*
|
||||||
projects/common/src/testMod/resources/data/cctest/structures/*
|
projects/common/src/testMod/resources/data/cctest/structures/*
|
||||||
projects/fabric/src/generated/*
|
projects/*/src/generated/*
|
||||||
projects/forge/src/generated/*
|
|
||||||
projects/web/src/htmlTransform/export/index.json
|
projects/web/src/htmlTransform/export/index.json
|
||||||
projects/web/src/htmlTransform/export/items/minecraft/*
|
projects/web/src/htmlTransform/export/items/minecraft/*
|
||||||
Comment: Generated/data files are CC0.
|
Comment: Generated/data files are CC0.
|
||||||
|
@@ -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.
|
In order to develop CC: Tweaked, you'll need to download the source code and then run it.
|
||||||
|
|
||||||
- Make sure you've got the following software installed:
|
- Make sure you've got the following software installed:
|
||||||
- Java Development Kit (JDK) installed. This can be downloaded from [Adoptium].
|
- Java Development Kit (JDK). This can be downloaded from [Adoptium].
|
||||||
- [Git](https://git-scm.com/).
|
- [Git](https://git-scm.com/).
|
||||||
- If you want to work on documentation, [NodeJS][node].
|
- [NodeJS][node].
|
||||||
|
|
||||||
- Download CC: Tweaked's source code:
|
- Download CC: Tweaked's source code:
|
||||||
```
|
```
|
||||||
|
@@ -5,9 +5,8 @@
|
|||||||
import cc.tweaked.gradle.JUnitExt
|
import cc.tweaked.gradle.JUnitExt
|
||||||
import net.fabricmc.loom.api.LoomGradleExtensionAPI
|
import net.fabricmc.loom.api.LoomGradleExtensionAPI
|
||||||
import net.fabricmc.loom.util.gradle.SourceSetHelper
|
import net.fabricmc.loom.util.gradle.SourceSetHelper
|
||||||
import org.jetbrains.gradle.ext.compiler
|
import org.jetbrains.gradle.ext.*
|
||||||
import org.jetbrains.gradle.ext.runConfigurations
|
import org.jetbrains.gradle.ext.Application
|
||||||
import org.jetbrains.gradle.ext.settings
|
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
publishing
|
publishing
|
||||||
@@ -86,6 +85,19 @@ idea.project.settings.runConfigurations {
|
|||||||
moduleName = "${idea.project.name}.forge.test"
|
moduleName = "${idea.project.name}.forge.test"
|
||||||
packageName = ""
|
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 {
|
idea.project.settings.compiler.javac {
|
||||||
|
@@ -40,10 +40,6 @@ repositories {
|
|||||||
|
|
||||||
val mainMaven = maven("https://squiddev.cc/maven") {
|
val mainMaven = maven("https://squiddev.cc/maven") {
|
||||||
name = "SquidDev"
|
name = "SquidDev"
|
||||||
content {
|
|
||||||
// Until https://github.com/SpongePowered/Mixin/pull/593 is merged
|
|
||||||
includeModule("org.spongepowered", "mixin")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
exclusiveContent {
|
exclusiveContent {
|
||||||
@@ -98,9 +94,8 @@ sourceSets.all {
|
|||||||
check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
|
check("InlineMeSuggester", CheckSeverity.OFF) // Minecraft uses @Deprecated liberally
|
||||||
// Too many false positives right now. Maybe we need an indirection for it later on.
|
// Too many false positives right now. Maybe we need an indirection for it later on.
|
||||||
check("ReferenceEquality", CheckSeverity.OFF)
|
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("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("NonOverridingEquals", CheckSeverity.OFF) // Peripheral.equals makes this hard to avoid
|
||||||
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
|
check("FutureReturnValueIgnored", CheckSeverity.OFF) // Too many false positives with Netty
|
||||||
|
|
||||||
@@ -113,6 +108,8 @@ sourceSets.all {
|
|||||||
option("NullAway:CastToNonNullMethod", "dan200.computercraft.core.util.Nullability.assertNonNull")
|
option("NullAway:CastToNonNullMethod", "dan200.computercraft.core.util.Nullability.assertNonNull")
|
||||||
option("NullAway:CheckOptionalEmptiness")
|
option("NullAway:CheckOptionalEmptiness")
|
||||||
option("NullAway:AcknowledgeRestrictiveAnnotations")
|
option("NullAway:AcknowledgeRestrictiveAnnotations")
|
||||||
|
|
||||||
|
excludedPaths = ".*/jmh_generated/.*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -32,7 +32,7 @@ val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
|
|||||||
apiToken = findProperty("curseForgeApiKey") ?: ""
|
apiToken = findProperty("curseForgeApiKey") ?: ""
|
||||||
enabled = apiToken != ""
|
enabled = apiToken != ""
|
||||||
|
|
||||||
val mainFile = upload("282001", modPublishing.output.get().archiveFile)
|
val mainFile = upload("282001", modPublishing.output)
|
||||||
mainFile.changelog =
|
mainFile.changelog =
|
||||||
"Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
|
"Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
|
||||||
mainFile.changelogType = "markdown"
|
mainFile.changelogType = "markdown"
|
||||||
|
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.net.URL
|
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
|
|
||||||
abstract class CCTweakedExtension(
|
abstract class CCTweakedExtension(
|
||||||
@@ -226,12 +225,12 @@ abstract class CCTweakedExtension(
|
|||||||
* where possible.
|
* where possible.
|
||||||
*/
|
*/
|
||||||
fun downloadFile(label: String, url: String): File {
|
fun downloadFile(label: String, url: String): File {
|
||||||
val url = URL(url)
|
val uri = URI(url)
|
||||||
val path = File(url.path)
|
val path = File(uri.path)
|
||||||
|
|
||||||
project.repositories.ivy {
|
project.repositories.ivy {
|
||||||
name = label
|
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 {
|
patternLayout {
|
||||||
artifact("[artifact].[ext]")
|
artifact("[artifact].[ext]")
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
}
|
@@ -46,7 +46,7 @@ abstract class NpmInstall : DefaultTask() {
|
|||||||
@TaskAction
|
@TaskAction
|
||||||
fun install() {
|
fun install() {
|
||||||
project.exec {
|
project.exec {
|
||||||
commandLine("npm", "ci")
|
commandLine(ProcessHelpers.getExecutable("npm"), "ci")
|
||||||
workingDir = projectRoot.get().asFile
|
workingDir = projectRoot.get().asFile
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,6 +59,6 @@ abstract class NpmInstall : DefaultTask() {
|
|||||||
abstract class NpxExecToDir : ExecToDir() {
|
abstract class NpxExecToDir : ExecToDir() {
|
||||||
init {
|
init {
|
||||||
dependsOn(NpmInstall.TASK_NAME)
|
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.BufferedReader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStreamReader
|
import java.io.InputStreamReader
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
|
||||||
internal object ProcessHelpers {
|
internal object ProcessHelpers {
|
||||||
fun startProcess(vararg command: String): Process {
|
fun startProcess(vararg command: String): Process {
|
||||||
@@ -34,7 +35,7 @@ internal object ProcessHelpers {
|
|||||||
val process = startProcess(*command)
|
val process = startProcess(*command)
|
||||||
process.outputStream.close()
|
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()
|
reader.lines().filter { it.isNotEmpty() }.toList()
|
||||||
}
|
}
|
||||||
ProcessGroovyMethods.closeStreams(process)
|
ProcessGroovyMethods.closeStreams(process)
|
||||||
@@ -46,6 +47,28 @@ internal object ProcessHelpers {
|
|||||||
val path = System.getenv("PATH") ?: return false
|
val path = System.getenv("PATH") ?: return false
|
||||||
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
return path.splitToSequence(File.pathSeparator).any { File(it, name).exists() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
internal fun Process.waitForOrThrow(message: String) {
|
||||||
|
@@ -13,8 +13,12 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<property name="tabWidth" value="4"/>
|
<property name="tabWidth" value="4"/>
|
||||||
<property name="charset" value="UTF-8" />
|
<property name="charset" value="UTF-8" />
|
||||||
|
|
||||||
|
<module name="BeforeExecutionExclusionFileFilter">
|
||||||
|
<property name="fileNamePattern" value="module\-info\.java$"/>
|
||||||
|
</module>
|
||||||
|
|
||||||
<module name="SuppressionFilter">
|
<module name="SuppressionFilter">
|
||||||
<property name="file" value="${config_loc}/suppressions.xml" />
|
<property name="file" value="${config_loc}/suppressions.xml" />
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
<module name="BeforeExecutionExclusionFileFilter">
|
<module name="BeforeExecutionExclusionFileFilter">
|
||||||
|
@@ -21,5 +21,5 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<suppress checks="PackageName" files=".*[\\/]T[A-Za-z]+.java" />
|
<suppress checks="PackageName" files=".*[\\/]T[A-Za-z]+.java" />
|
||||||
|
|
||||||
<!-- Allow underscores in our test classes. -->
|
<!-- Allow underscores in our test classes. -->
|
||||||
<suppress checks="MethodName" files=".*Contract.java" />
|
<suppress checks="MethodName" files=".*(Contract|Test).java" />
|
||||||
</suppressions>
|
</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
|
|
@@ -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.
|
constellation is redundant, but it does not cause problems.
|
||||||
|
|
||||||
## Building a GPS constellation
|
## 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
|
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
|
modems or 4 ender modems. Try not to mix ender and wireless modems together as you might get some odd behavior when your
|
||||||
|
@@ -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
|
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.
|
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
|
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
|
[`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.
|
[`fs.ReadHandle.read`] if you prefer.
|
||||||
|
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 |
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"
|
@@ -2,7 +2,7 @@
|
|||||||
#
|
#
|
||||||
# SPDX-License-Identifier: MPL-2.0
|
# SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
org.gradle.jvmargs=-Xmx3G
|
org.gradle.jvmargs=-Xmx3G -Dfile.encoding=UTF-8
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
|
|
||||||
kotlin.stdlib.default.dependency=false
|
kotlin.stdlib.default.dependency=false
|
||||||
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
|
|||||||
|
|
||||||
# Mod properties
|
# Mod properties
|
||||||
isUnstable=false
|
isUnstable=false
|
||||||
modVersion=1.109.7
|
modVersion=1.111.0
|
||||||
|
|
||||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||||
mcVersion=1.20.1
|
mcVersion=1.20.1
|
||||||
|
@@ -26,7 +26,7 @@ slf4j = "2.0.1"
|
|||||||
asm = "9.6"
|
asm = "9.6"
|
||||||
autoService = "1.1.1"
|
autoService = "1.1.1"
|
||||||
checkerFramework = "3.42.0"
|
checkerFramework = "3.42.0"
|
||||||
cobalt = "0.9.1"
|
cobalt = "0.9.3"
|
||||||
commonsCli = "1.6.0"
|
commonsCli = "1.6.0"
|
||||||
jetbrainsAnnotations = "24.1.0"
|
jetbrainsAnnotations = "24.1.0"
|
||||||
jsr305 = "3.0.2"
|
jsr305 = "3.0.2"
|
||||||
@@ -55,25 +55,24 @@ jmh = "1.37"
|
|||||||
|
|
||||||
# Build tools
|
# Build tools
|
||||||
cctJavadoc = "1.8.2"
|
cctJavadoc = "1.8.2"
|
||||||
checkstyle = "10.12.6"
|
checkstyle = "10.14.1"
|
||||||
curseForgeGradle = "1.0.14"
|
curseForgeGradle = "1.0.14"
|
||||||
errorProne-core = "2.23.0"
|
errorProne-core = "2.27.0"
|
||||||
errorProne-plugin = "3.1.0"
|
errorProne-plugin = "3.1.0"
|
||||||
fabric-loom = "1.5.7"
|
fabric-loom = "1.6.7"
|
||||||
forgeGradle = "6.0.20"
|
forgeGradle = "6.0.21"
|
||||||
githubRelease = "2.5.2"
|
githubRelease = "2.5.2"
|
||||||
gradleVersions = "0.50.0"
|
gradleVersions = "0.50.0"
|
||||||
ideaExt = "1.1.7"
|
ideaExt = "1.1.7"
|
||||||
illuaminate = "0.1.0-44-g9ee0055"
|
illuaminate = "0.1.0-71-g378d86e"
|
||||||
librarian = "1.+"
|
librarian = "1.+"
|
||||||
lwjgl = "3.3.3"
|
lwjgl = "3.3.3"
|
||||||
minotaur = "2.+"
|
minotaur = "2.+"
|
||||||
mixinGradle = "0.7.38"
|
nullAway = "0.10.25"
|
||||||
nullAway = "0.9.9"
|
|
||||||
spotless = "6.23.3"
|
spotless = "6.23.3"
|
||||||
taskTree = "2.1.1"
|
taskTree = "2.1.1"
|
||||||
teavm = "0.10.0-SQUID.2"
|
teavm = "0.10.0-SQUID.4"
|
||||||
vanillaExtract = "0.1.1"
|
vanillaExtract = "0.1.3"
|
||||||
versionCatalogUpdate = "0.8.1"
|
versionCatalogUpdate = "0.8.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
@@ -155,6 +154,7 @@ minotaur = { module = "com.modrinth.minotaur:Minotaur", version.ref = "minotaur"
|
|||||||
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
|
nullAway = { module = "com.uber.nullaway:nullaway", version.ref = "nullAway" }
|
||||||
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
|
spotless = { module = "com.diffplug.spotless:spotless-plugin-gradle", version.ref = "spotless" }
|
||||||
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
|
teavm-classlib = { module = "org.teavm:teavm-classlib", version.ref = "teavm" }
|
||||||
|
teavm-core = { module = "org.teavm:teavm-core", version.ref = "teavm" }
|
||||||
teavm-jso = { module = "org.teavm:teavm-jso", 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-apis = { module = "org.teavm:teavm-jso-apis", version.ref = "teavm" }
|
||||||
teavm-jso-impl = { module = "org.teavm:teavm-jso-impl", version.ref = "teavm" }
|
teavm-jso-impl = { module = "org.teavm:teavm-jso-impl", version.ref = "teavm" }
|
||||||
@@ -171,7 +171,6 @@ githubRelease = { id = "com.github.breadmoirai.github-release", version.ref = "g
|
|||||||
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
|
gradleVersions = { id = "com.github.ben-manes.versions", version.ref = "gradleVersions" }
|
||||||
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||||
librarian = { id = "org.parchmentmc.librarian.forgegradle", version.ref = "librarian" }
|
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" }
|
taskTree = { id = "com.dorongold.task-tree", version.ref = "taskTree" }
|
||||||
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
|
versionCatalogUpdate = { id = "nl.littlerobots.version-catalog-update", version.ref = "versionCatalogUpdate" }
|
||||||
|
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
@@ -29,7 +29,7 @@ public final class Services {
|
|||||||
* @throws IllegalStateException When the service cannot be loaded.
|
* @throws IllegalStateException When the service cannot be loaded.
|
||||||
*/
|
*/
|
||||||
public static <T> T load(Class<T> klass) {
|
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()) {
|
return switch (services.size()) {
|
||||||
case 1 -> services.get(0).get();
|
case 1 -> services.get(0).get();
|
||||||
case 0 -> throw new IllegalStateException("Cannot find service for " + klass.getName());
|
case 0 -> throw new IllegalStateException("Cannot find service for " + klass.getName());
|
||||||
|
@@ -11,6 +11,12 @@ plugins {
|
|||||||
id("cc-tweaked.publishing")
|
id("cc-tweaked.publishing")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
resources.srcDir("src/generated/resources")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
minecraft {
|
minecraft {
|
||||||
accessWideners(
|
accessWideners(
|
||||||
"src/main/resources/computercraft.accesswidener",
|
"src/main/resources/computercraft.accesswidener",
|
||||||
@@ -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") }
|
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::") }
|
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 }
|
||||||
|
@@ -22,6 +22,7 @@ import dan200.computercraft.core.util.Colour;
|
|||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||||
import dan200.computercraft.shared.common.IColouredItem;
|
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.core.ServerContext;
|
||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||||
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
|
import dan200.computercraft.shared.computer.inventory.ViewComputerMenu;
|
||||||
@@ -77,8 +78,10 @@ public final class ClientRegistry {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Register any client-side objects which must be done on the main thread.
|
* 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.COMPUTER.get(), ComputerScreen::new);
|
||||||
MenuScreens.<AbstractComputerMenu, ComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_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.<AbstractComputerMenu, NoTermComputerScreen<AbstractComputerMenu>>register(ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new);
|
||||||
@@ -90,11 +93,14 @@ public final class ClientRegistry {
|
|||||||
|
|
||||||
MenuScreens.<ViewComputerMenu, ComputerScreen<ViewComputerMenu>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), ComputerScreen::new);
|
MenuScreens.<ViewComputerMenu, ComputerScreen<ViewComputerMenu>>register(ModRegistry.Menus.VIEW_COMPUTER.get(), ComputerScreen::new);
|
||||||
|
|
||||||
registerItemProperty("state",
|
registerItemProperty(itemProperties, "state",
|
||||||
new UnclampedPropertyFunction((stack, world, player, random) -> ClientPocketComputers.get(stack).getState().ordinal()),
|
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
|
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,
|
(stack, world, player, random) -> IColouredItem.getColourBasic(stack) != -1 ? 1 : 0,
|
||||||
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
ModRegistry.Items.POCKET_COMPUTER_NORMAL, ModRegistry.Items.POCKET_COMPUTER_ADVANCED
|
||||||
);
|
);
|
||||||
@@ -115,9 +121,17 @@ public final class ClientRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SafeVarargs
|
@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);
|
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) {
|
public static void registerReloadListeners(Consumer<PreparableReloadListener> register, Minecraft minecraft) {
|
||||||
@@ -155,17 +169,14 @@ public final class ClientRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int getPocketColour(ItemStack stack, int layer) {
|
private static int getPocketColour(ItemStack stack, int layer) {
|
||||||
switch (layer) {
|
return switch (layer) {
|
||||||
case 0:
|
default -> 0xFFFFFF;
|
||||||
default:
|
case 1 -> IColouredItem.getColourBasic(stack); // Frame colour
|
||||||
return 0xFFFFFF;
|
case 2 -> { // Light colour
|
||||||
case 1: // Frame colour
|
var computer = ClientPocketComputers.get(stack);
|
||||||
return IColouredItem.getColourBasic(stack);
|
yield computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState();
|
||||||
case 2: { // Light colour
|
|
||||||
var light = ClientPocketComputers.get(stack).getLightState();
|
|
||||||
return light == -1 ? Colour.BLACK.getHex() : light;
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getTurtleColour(ItemStack stack, int layer) {
|
private static int getTurtleColour(ItemStack stack, int layer) {
|
||||||
|
@@ -9,6 +9,7 @@ import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
|||||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||||
import dan200.computercraft.client.network.ClientNetworking;
|
import dan200.computercraft.client.network.ClientNetworking;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
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.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
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 dan200.computercraft.shared.network.server.UploadFileMessage;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
@@ -96,8 +98,8 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
|||||||
getTerminal().update();
|
getTerminal().update();
|
||||||
|
|
||||||
if (uploadNagDeadline != Long.MAX_VALUE && Util.getNanos() >= uploadNagDeadline) {
|
if (uploadNagDeadline != Long.MAX_VALUE && Util.getNanos() >= uploadNagDeadline) {
|
||||||
new ItemToast(minecraft, displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
|
new ItemToast(minecraft(), displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
|
||||||
.showOrReplace(minecraft.getToasts());
|
.showOrReplace(minecraft().getToasts());
|
||||||
uploadNagDeadline = Long.MAX_VALUE;
|
uploadNagDeadline = Long.MAX_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,7 +209,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
|||||||
return;
|
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) {
|
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) {
|
private void alert(Component title, Component message) {
|
||||||
OptionScreen.show(minecraft, title, message,
|
OptionScreen.show(minecraft(), title, message,
|
||||||
List.of(OptionScreen.newButton(OK, b -> minecraft.setScreen(this))),
|
List.of(OptionScreen.newButton(OK, b -> minecraft().setScreen(this))),
|
||||||
() -> minecraft.setScreen(this)
|
() -> minecraft().setScreen(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Minecraft minecraft() {
|
||||||
|
return Nullability.assertNonNull(minecraft);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -49,31 +49,31 @@ public final class ClientInputHandler implements InputHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void keyDown(int key, boolean repeat) {
|
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
|
@Override
|
||||||
public void keyUp(int key) {
|
public void keyUp(int key) {
|
||||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.TYPE_UP, key));
|
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.Action.UP, key));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseClick(int button, int x, int y) {
|
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
|
@Override
|
||||||
public void mouseUp(int button, int x, int y) {
|
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
|
@Override
|
||||||
public void mouseDrag(int button, int x, int y) {
|
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
|
@Override
|
||||||
public void mouseScroll(int direction, int x, int y) {
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,8 +6,10 @@ package dan200.computercraft.client.gui;
|
|||||||
|
|
||||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
|
import dan200.computercraft.core.util.Nullability;
|
||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||||
import net.minecraft.client.KeyMapping;
|
import net.minecraft.client.KeyMapping;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
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 org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||||
|
|
||||||
@@ -44,8 +47,8 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
|||||||
protected void init() {
|
protected void init() {
|
||||||
// First ensure we're still grabbing the mouse, so the user can look around. Then reset bits of state that
|
// First ensure we're still grabbing the mouse, so the user can look around. Then reset bits of state that
|
||||||
// grabbing unsets.
|
// grabbing unsets.
|
||||||
minecraft.mouseHandler.grabMouse();
|
minecraft().mouseHandler.grabMouse();
|
||||||
minecraft.screen = this;
|
minecraft().screen = this;
|
||||||
KeyMapping.releaseAll();
|
KeyMapping.releaseAll();
|
||||||
|
|
||||||
super.init();
|
super.init();
|
||||||
@@ -64,13 +67,13 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mouseScrolled(double pMouseX, double pMouseY, double pDelta) {
|
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);
|
return super.mouseScrolled(pMouseX, pMouseY, pDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClose() {
|
public void onClose() {
|
||||||
minecraft.player.closeContainer();
|
Objects.requireNonNull(minecraft().player).closeContainer();
|
||||||
super.onClose();
|
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) {
|
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
||||||
super.render(graphics, mouseX, mouseY, 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 lines = font.split(Component.translatable("gui.computercraft.pocket_computer_overlay"), (int) (width * 0.8));
|
||||||
var y = 10;
|
var y = 10;
|
||||||
for (var line : lines) {
|
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;
|
y += 9;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Minecraft minecraft() {
|
||||||
|
return Nullability.assertNonNull(minecraft);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,7 @@ import dan200.computercraft.shared.computer.terminal.TerminalState;
|
|||||||
import dan200.computercraft.shared.computer.upload.UploadResult;
|
import dan200.computercraft.shared.computer.upload.UploadResult;
|
||||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||||
|
import dan200.computercraft.shared.peripheral.speaker.EncodedAudio;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@@ -27,7 +28,6 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,7 +49,7 @@ public final class ClientNetworkContextImpl implements ClientNetworkContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMonitorData(BlockPos pos, TerminalState terminal) {
|
public void handleMonitorData(BlockPos pos, @Nullable TerminalState terminal) {
|
||||||
var player = Minecraft.getInstance().player;
|
var player = Minecraft.getInstance().player;
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
|
|
||||||
@@ -67,19 +67,17 @@ public final class ClientNetworkContextImpl implements ClientNetworkContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePocketComputerData(int instanceId, ComputerState state, int lightState, TerminalState terminal) {
|
public void handlePocketComputerData(UUID instanceId, ComputerState state, int lightState, @Nullable TerminalState terminal) {
|
||||||
var computer = ClientPocketComputers.get(instanceId, terminal.colour);
|
ClientPocketComputers.setState(instanceId, state, lightState, terminal);
|
||||||
computer.setState(state, lightState);
|
|
||||||
if (terminal.hasTerminal()) computer.setTerminal(terminal);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handlePocketComputerDeleted(int instanceId) {
|
public void handlePocketComputerDeleted(UUID instanceId) {
|
||||||
ClientPocketComputers.remove(instanceId);
|
ClientPocketComputers.remove(instanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume, ByteBuffer buffer) {
|
public void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume, EncodedAudio buffer) {
|
||||||
SpeakerManager.getSound(source).playAudio(reifyPosition(position), volume, buffer);
|
SpeakerManager.getSound(source).playAudio(reifyPosition(position), volume, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -4,21 +4,25 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.pocket;
|
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.core.ServerComputer;
|
||||||
|
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||||
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
|
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
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 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>
|
* <p>
|
||||||
* This is populated by {@link PocketComputerDataMessage} and accessed when rendering pocket computers
|
* This is populated by {@link PocketComputerDataMessage} and accessed when rendering pocket computers
|
||||||
*/
|
*/
|
||||||
public final class ClientPocketComputers {
|
public final class ClientPocketComputers {
|
||||||
private static final Int2ObjectMap<PocketComputerData> instances = new Int2ObjectOpenHashMap<>();
|
private static final Map<UUID, PocketComputerData> instances = new HashMap<>();
|
||||||
|
|
||||||
private ClientPocketComputers() {
|
private ClientPocketComputers() {
|
||||||
}
|
}
|
||||||
@@ -27,25 +31,29 @@ public final class ClientPocketComputers {
|
|||||||
instances.clear();
|
instances.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void remove(int id) {
|
public static void remove(UUID id) {
|
||||||
instances.remove(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 instanceId The instance ID of the pocket computer.
|
||||||
* @param advanced Whether this computer has an advanced terminal.
|
* @param state The computer state of the pocket computer.
|
||||||
* @return The pocket computer data.
|
* @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);
|
var computer = instances.get(instanceId);
|
||||||
if (computer == null) instances.put(instanceId, computer = new PocketComputerData(advanced));
|
if (computer == null) {
|
||||||
return computer;
|
instances.put(instanceId, new PocketComputerData(state, lightColour, terminalData));
|
||||||
|
} else {
|
||||||
|
computer.setState(state, lightColour, terminalData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PocketComputerData get(ItemStack stack) {
|
public static @Nullable PocketComputerData get(ItemStack stack) {
|
||||||
var family = stack.getItem() instanceof PocketComputerItem computer ? computer.getFamily() : ComputerFamily.NORMAL;
|
var id = PocketComputerItem.getInstanceID(stack);
|
||||||
return get(PocketComputerItem.getInstanceID(stack), family != ComputerFamily.NORMAL);
|
return id == null ? null : instances.get(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.pocket;
|
package dan200.computercraft.client.pocket;
|
||||||
|
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
|
||||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||||
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
|
||||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||||
import dan200.computercraft.shared.config.Config;
|
|
||||||
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clientside data about a pocket computer.
|
* Clientside data about a pocket computer.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -21,20 +21,22 @@ import dan200.computercraft.shared.pocket.core.PocketServerComputer;
|
|||||||
* @see ClientPocketComputers The registry which holds pocket computers.
|
* @see ClientPocketComputers The registry which holds pocket computers.
|
||||||
* @see PocketServerComputer The server-side pocket computer.
|
* @see PocketServerComputer The server-side pocket computer.
|
||||||
*/
|
*/
|
||||||
public class PocketComputerData {
|
public final class PocketComputerData {
|
||||||
private final NetworkedTerminal terminal;
|
private @Nullable NetworkedTerminal terminal;
|
||||||
private ComputerState state = ComputerState.OFF;
|
private ComputerState state;
|
||||||
private int lightColour = -1;
|
private int lightColour;
|
||||||
|
|
||||||
public PocketComputerData(boolean colour) {
|
PocketComputerData(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
|
||||||
terminal = new NetworkedTerminal(Config.pocketTermWidth, Config.pocketTermHeight, colour);
|
this.state = state;
|
||||||
|
this.lightColour = lightColour;
|
||||||
|
if (terminalData != null) terminal = terminalData.create();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLightState() {
|
public int getLightState() {
|
||||||
return state != ComputerState.OFF ? lightColour : -1;
|
return state != ComputerState.OFF ? lightColour : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Terminal getTerminal() {
|
public @Nullable NetworkedTerminal getTerminal() {
|
||||||
return terminal;
|
return terminal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,12 +44,16 @@ public class PocketComputerData {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setState(ComputerState state, int lightColour) {
|
void setState(ComputerState state, int lightColour, @Nullable TerminalState terminalData) {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
this.lightColour = lightColour;
|
this.lightColour = lightColour;
|
||||||
}
|
|
||||||
|
|
||||||
public void setTerminal(TerminalState state) {
|
if (terminalData != null) {
|
||||||
state.apply(terminal);
|
if (terminal == null) {
|
||||||
|
terminal = terminalData.create();
|
||||||
|
} else {
|
||||||
|
terminalData.apply(terminal);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -17,6 +17,8 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.world.item.ItemDisplayContext;
|
import net.minecraft.world.item.ItemDisplayContext;
|
||||||
import net.minecraft.world.item.ItemStack;
|
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.
|
* 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);
|
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) {
|
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();
|
transform.pushPose();
|
||||||
if (hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty()) {
|
if (hand == InteractionHand.MAIN_HAND && player.getOffhandItem().isEmpty()) {
|
||||||
|
@@ -11,6 +11,7 @@ import dan200.computercraft.client.pocket.ClientPocketComputers;
|
|||||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||||
import dan200.computercraft.core.util.Colour;
|
import dan200.computercraft.core.util.Colour;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
|
import dan200.computercraft.shared.config.Config;
|
||||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@@ -32,10 +33,16 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
|||||||
@Override
|
@Override
|
||||||
protected void renderItem(PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light) {
|
protected void renderItem(PoseStack transform, MultiBufferSource bufferSource, ItemStack stack, int light) {
|
||||||
var computer = ClientPocketComputers.get(stack);
|
var computer = ClientPocketComputers.get(stack);
|
||||||
var terminal = computer.getTerminal();
|
var terminal = computer == null ? null : computer.getTerminal();
|
||||||
|
|
||||||
var termWidth = terminal.getWidth();
|
int termWidth, termHeight;
|
||||||
var termHeight = terminal.getHeight();
|
if (terminal == null) {
|
||||||
|
termWidth = Config.pocketTermWidth;
|
||||||
|
termHeight = Config.pocketTermHeight;
|
||||||
|
} else {
|
||||||
|
termWidth = terminal.getWidth();
|
||||||
|
termHeight = terminal.getHeight();
|
||||||
|
}
|
||||||
|
|
||||||
var width = termWidth * FONT_WIDTH + MARGIN * 2;
|
var width = termWidth * FONT_WIDTH + MARGIN * 2;
|
||||||
var height = termHeight * FONT_HEIGHT + MARGIN * 2;
|
var height = termHeight * FONT_HEIGHT + MARGIN * 2;
|
||||||
@@ -60,14 +67,15 @@ public final class PocketItemRenderer extends ItemMapLikeRenderer {
|
|||||||
renderFrame(matrix, bufferSource, family, frameColour, light, width, height);
|
renderFrame(matrix, bufferSource, family, frameColour, light, width, height);
|
||||||
|
|
||||||
// Render the light
|
// Render the light
|
||||||
var lightColour = ClientPocketComputers.get(stack).getLightState();
|
var lightColour = computer == null || computer.getLightState() == -1 ? Colour.BLACK.getHex() : computer.getLightState();
|
||||||
if (lightColour == -1) lightColour = Colour.BLACK.getHex();
|
|
||||||
renderLight(transform, bufferSource, lightColour, width, height);
|
renderLight(transform, bufferSource, lightColour, width, height);
|
||||||
|
|
||||||
FixedWidthFontRenderer.drawTerminal(
|
var quadEmitter = FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(RenderTypes.TERMINAL));
|
||||||
FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(RenderTypes.TERMINAL)),
|
if (terminal == null) {
|
||||||
MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN
|
FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, width, height);
|
||||||
);
|
} else {
|
||||||
|
FixedWidthFontRenderer.drawTerminal(quadEmitter, MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
|
||||||
|
}
|
||||||
|
|
||||||
transform.popPose();
|
transform.popPose();
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,7 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
|||||||
// Render the label
|
// Render the label
|
||||||
var label = turtle.getLabel();
|
var label = turtle.getLabel();
|
||||||
var hit = renderer.cameraHitResult;
|
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 mc = Minecraft.getInstance();
|
||||||
var font = this.font;
|
var font = this.font;
|
||||||
|
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
package dan200.computercraft.client.sound;
|
package dan200.computercraft.client.sound;
|
||||||
|
|
||||||
import com.mojang.blaze3d.audio.Channel;
|
import com.mojang.blaze3d.audio.Channel;
|
||||||
|
import dan200.computercraft.shared.peripheral.speaker.EncodedAudio;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral;
|
import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||||
import net.minecraft.client.sounds.AudioStream;
|
import net.minecraft.client.sounds.AudioStream;
|
||||||
@@ -36,7 +37,7 @@ class DfpwmStream implements AudioStream {
|
|||||||
/**
|
/**
|
||||||
* The {@link Channel} which this sound is playing on.
|
* The {@link Channel} which this sound is playing on.
|
||||||
*
|
*
|
||||||
* @see SpeakerInstance#playAudio(SpeakerPosition, float, ByteBuffer)
|
* @see SpeakerInstance#playAudio(SpeakerPosition, float, EncodedAudio)
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Channel channel;
|
Channel channel;
|
||||||
@@ -44,21 +45,23 @@ class DfpwmStream implements AudioStream {
|
|||||||
/**
|
/**
|
||||||
* The underlying {@link SoundEngine} executor.
|
* The underlying {@link SoundEngine} executor.
|
||||||
*
|
*
|
||||||
* @see SpeakerInstance#playAudio(SpeakerPosition, float, ByteBuffer)
|
* @see SpeakerInstance#playAudio(SpeakerPosition, float, EncodedAudio)
|
||||||
* @see SoundEngine#executor
|
* @see SoundEngine#executor
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Executor executor;
|
Executor executor;
|
||||||
|
|
||||||
private int charge = 0; // q
|
|
||||||
private int strength = 0; // s
|
|
||||||
private int lowPassCharge;
|
private int lowPassCharge;
|
||||||
private boolean previousBit = false;
|
|
||||||
|
|
||||||
DfpwmStream() {
|
DfpwmStream() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void push(ByteBuffer input) {
|
void push(EncodedAudio audio) {
|
||||||
|
var charge = audio.charge();
|
||||||
|
var strength = audio.strength();
|
||||||
|
var previousBit = audio.previousBit();
|
||||||
|
var input = audio.audio();
|
||||||
|
|
||||||
var readable = input.remaining();
|
var readable = input.remaining();
|
||||||
var output = ByteBuffer.allocate(readable * 8).order(ByteOrder.nativeOrder());
|
var output = ByteBuffer.allocate(readable * 8).order(ByteOrder.nativeOrder());
|
||||||
|
|
||||||
|
@@ -6,12 +6,12 @@ package dan200.computercraft.client.sound;
|
|||||||
|
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.core.util.Nullability;
|
import dan200.computercraft.core.util.Nullability;
|
||||||
|
import dan200.computercraft.shared.peripheral.speaker.EncodedAudio;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An instance of a speaker, which is either playing a {@link DfpwmStream} stream or a normal sound.
|
* An instance of a speaker, which is either playing a {@link DfpwmStream} stream or a normal sound.
|
||||||
@@ -25,7 +25,7 @@ public class SpeakerInstance {
|
|||||||
SpeakerInstance() {
|
SpeakerInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pushAudio(ByteBuffer buffer) {
|
private void pushAudio(EncodedAudio buffer) {
|
||||||
var sound = this.sound;
|
var sound = this.sound;
|
||||||
|
|
||||||
var stream = currentStream;
|
var stream = currentStream;
|
||||||
@@ -43,7 +43,7 @@ public class SpeakerInstance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void playAudio(SpeakerPosition position, float volume, ByteBuffer buffer) {
|
public void playAudio(SpeakerPosition position, float volume, EncodedAudio buffer) {
|
||||||
pushAudio(buffer);
|
pushAudio(buffer);
|
||||||
|
|
||||||
var soundManager = Minecraft.getInstance().getSoundManager();
|
var soundManager = Minecraft.getInstance().getSoundManager();
|
||||||
|
@@ -1,8 +1,14 @@
|
|||||||
{
|
{
|
||||||
"argument.computercraft.argument_expected": "Argument expected",
|
"argument.computercraft.argument_expected": "Argument expected",
|
||||||
|
"argument.computercraft.computer.distance": "Distance to entity",
|
||||||
|
"argument.computercraft.computer.family": "Computer family",
|
||||||
|
"argument.computercraft.computer.id": "Computer ID",
|
||||||
|
"argument.computercraft.computer.instance": "Unique instance ID",
|
||||||
|
"argument.computercraft.computer.label": "Computer label",
|
||||||
"argument.computercraft.computer.many_matching": "Multiple computers matching '%s' (instances %s)",
|
"argument.computercraft.computer.many_matching": "Multiple computers matching '%s' (instances %s)",
|
||||||
"argument.computercraft.computer.no_matching": "No computers matching '%s'",
|
"argument.computercraft.computer.no_matching": "No computers matching '%s'",
|
||||||
"argument.computercraft.tracking_field.no_field": "Unknown field '%s'",
|
"argument.computercraft.tracking_field.no_field": "Unknown field '%s'",
|
||||||
|
"argument.computercraft.unknown_computer_family": "Unknown computer family '%s'",
|
||||||
"block.computercraft.cable": "Networking Cable",
|
"block.computercraft.cable": "Networking Cable",
|
||||||
"block.computercraft.computer_advanced": "Advanced Computer",
|
"block.computercraft.computer_advanced": "Advanced Computer",
|
||||||
"block.computercraft.computer_command": "Command Computer",
|
"block.computercraft.computer_command": "Command Computer",
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user