mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-11-14 05:44:52 +00:00
Merge branch 'mc-1.20.x' into mc-1.20.y
This commit is contained in:
commit
5c457950d8
18
.github/workflows/main-ci.yml
vendored
18
.github/workflows/main-ci.yml
vendored
@ -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@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up Java
|
- name: 📥 Set up Java
|
||||||
uses: actions/setup-java@v4
|
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/actions/setup-gradle@v3
|
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 :web: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() }}
|
||||||
|
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
|
|
@ -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 {
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -26,7 +26,7 @@ slf4j = "2.0.7"
|
|||||||
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.2"
|
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"
|
||||||
@ -59,7 +59,7 @@ checkstyle = "10.14.1"
|
|||||||
curseForgeGradle = "1.1.18"
|
curseForgeGradle = "1.1.18"
|
||||||
errorProne-core = "2.23.0"
|
errorProne-core = "2.23.0"
|
||||||
errorProne-plugin = "3.1.0"
|
errorProne-plugin = "3.1.0"
|
||||||
fabric-loom = "1.5.7"
|
fabric-loom = "1.6.7"
|
||||||
githubRelease = "2.5.2"
|
githubRelease = "2.5.2"
|
||||||
gradleVersions = "0.50.0"
|
gradleVersions = "0.50.0"
|
||||||
ideaExt = "1.1.7"
|
ideaExt = "1.1.7"
|
||||||
@ -70,8 +70,8 @@ neoGradle = "7.0.100"
|
|||||||
nullAway = "0.10.25"
|
nullAway = "0.10.25"
|
||||||
spotless = "6.23.3"
|
spotless = "6.23.3"
|
||||||
taskTree = "2.1.1"
|
taskTree = "2.1.1"
|
||||||
teavm = "0.10.0-SQUID.3"
|
teavm = "0.10.0-SQUID.4"
|
||||||
vanillaExtract = "0.1.2"
|
vanillaExtract = "0.1.3"
|
||||||
versionCatalogUpdate = "0.8.1"
|
versionCatalogUpdate = "0.8.1"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
@ -152,6 +152,7 @@ neoGradle-userdev = { module = "net.neoforged.gradle:userdev", version.ref = "ne
|
|||||||
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" }
|
||||||
|
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.6-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
|
||||||
|
@ -8,6 +8,7 @@ import dan200.computercraft.annotations.ForgeOverride;
|
|||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
import dan200.computercraft.shared.common.IBundledRedstoneBlock;
|
||||||
import dan200.computercraft.shared.computer.items.IComputerItem;
|
import dan200.computercraft.shared.computer.items.IComputerItem;
|
||||||
|
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
||||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@ -160,8 +161,19 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public final InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
return world.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer ? computer.use(player, hand) : InteractionResult.PASS;
|
if (!player.isCrouching() && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
||||||
|
// Regular right click to activate computer
|
||||||
|
if (!level.isClientSide && computer.isUsable(player)) {
|
||||||
|
var serverComputer = computer.createServerComputer();
|
||||||
|
serverComputer.turnOn();
|
||||||
|
|
||||||
|
new ComputerContainerData(serverComputer, getItem(computer)).open(player, computer);
|
||||||
|
}
|
||||||
|
return InteractionResult.sidedSuccess(level.isClientSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.use(state, level, pos, player, hand, hit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -13,7 +13,6 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
|
|||||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
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.core.ServerContext;
|
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||||
import dan200.computercraft.shared.network.container.ComputerContainerData;
|
|
||||||
import dan200.computercraft.shared.platform.ComponentAccess;
|
import dan200.computercraft.shared.platform.ComponentAccess;
|
||||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||||
@ -25,10 +24,10 @@ import net.minecraft.core.Direction;
|
|||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
|
||||||
import net.minecraft.world.*;
|
import net.minecraft.world.LockCode;
|
||||||
|
import net.minecraft.world.MenuProvider;
|
||||||
|
import net.minecraft.world.Nameable;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.item.Items;
|
|
||||||
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
@ -76,10 +75,6 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
unload();
|
unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean canNameWithTag(Player player) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected double getInteractRange() {
|
protected double getInteractRange() {
|
||||||
return BlockEntityHelpers.DEFAULT_INTERACT_RANGE;
|
return BlockEntityHelpers.DEFAULT_INTERACT_RANGE;
|
||||||
}
|
}
|
||||||
@ -89,31 +84,6 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
&& BlockEntityHelpers.isUsable(this, player, getInteractRange());
|
&& BlockEntityHelpers.isUsable(this, player, getInteractRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
public InteractionResult use(Player player, InteractionHand hand) {
|
|
||||||
var currentItem = player.getItemInHand(hand);
|
|
||||||
if (!currentItem.isEmpty() && currentItem.getItem() == Items.NAME_TAG && canNameWithTag(player) && currentItem.hasCustomHoverName()) {
|
|
||||||
// Label to rename computer
|
|
||||||
if (!getLevel().isClientSide) {
|
|
||||||
setLabel(currentItem.getHoverName().getString());
|
|
||||||
currentItem.shrink(1);
|
|
||||||
}
|
|
||||||
return InteractionResult.sidedSuccess(getLevel().isClientSide);
|
|
||||||
} else if (!player.isCrouching()) {
|
|
||||||
// Regular right click to activate computer
|
|
||||||
if (!getLevel().isClientSide && isUsable(player)) {
|
|
||||||
var computer = createServerComputer();
|
|
||||||
computer.turnOn();
|
|
||||||
|
|
||||||
var stack = getBlockState().getBlock() instanceof AbstractComputerBlock<?>
|
|
||||||
? ((AbstractComputerBlock<?>) getBlockState().getBlock()).getItem(this)
|
|
||||||
: ItemStack.EMPTY;
|
|
||||||
new ComputerContainerData(computer, stack).open(player, this);
|
|
||||||
}
|
|
||||||
return InteractionResult.sidedSuccess(getLevel().isClientSide);
|
|
||||||
}
|
|
||||||
return InteractionResult.PASS;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void serverTick() {
|
protected void serverTick() {
|
||||||
if (getLevel().isClientSide) return;
|
if (getLevel().isClientSide) return;
|
||||||
if (computerID < 0 && !startOn) return; // Don't tick if we don't need a computer!
|
if (computerID < 0 && !startOn) return; // Don't tick if we don't need a computer!
|
||||||
@ -343,7 +313,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
if (getLevel().isClientSide || computerID == id) return;
|
if (getLevel().isClientSide || computerID == id) return;
|
||||||
|
|
||||||
computerID = id;
|
computerID = id;
|
||||||
setChanged();
|
BlockEntityHelpers.updateBlock(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -353,7 +323,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
|
|||||||
this.label = label;
|
this.label = label;
|
||||||
var computer = getServerComputer();
|
var computer = getServerComputer();
|
||||||
if (computer != null) computer.setLabel(label);
|
if (computer != null) computer.setLabel(label);
|
||||||
setChanged();
|
BlockEntityHelpers.updateBlock(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -21,10 +21,13 @@ import dan200.computercraft.shared.util.WaterloggableHelpers;
|
|||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.Containers;
|
import net.minecraft.world.Containers;
|
||||||
|
import net.minecraft.world.InteractionHand;
|
||||||
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
import net.minecraft.world.item.Items;
|
||||||
import net.minecraft.world.item.context.BlockPlaceContext;
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.Explosion;
|
import net.minecraft.world.level.Explosion;
|
||||||
@ -41,6 +44,7 @@ import net.minecraft.world.level.block.state.StateDefinition;
|
|||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
import net.minecraft.world.level.block.state.properties.DirectionProperty;
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
import net.minecraft.world.phys.shapes.Shapes;
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
@ -168,6 +172,22 @@ public class TurtleBlock extends AbstractComputerBlock<TurtleBlockEntity> implem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Deprecated
|
||||||
|
public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
|
||||||
|
var currentItem = player.getItemInHand(hand);
|
||||||
|
if (currentItem.getItem() == Items.NAME_TAG && currentItem.hasCustomHoverName() && level.getBlockEntity(pos) instanceof AbstractComputerBlockEntity computer) {
|
||||||
|
// Label to rename computer
|
||||||
|
if (!level.isClientSide) {
|
||||||
|
computer.setLabel(currentItem.getHoverName().getString());
|
||||||
|
currentItem.shrink(1);
|
||||||
|
}
|
||||||
|
return InteractionResult.sidedSuccess(level.isClientSide);
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.use(state, level, pos, player, hand, hit);
|
||||||
|
}
|
||||||
|
|
||||||
@ForgeOverride
|
@ForgeOverride
|
||||||
public float getExplosionResistance(BlockState state, BlockGetter world, BlockPos pos, Explosion explosion) {
|
public float getExplosionResistance(BlockState state, BlockGetter world, BlockPos pos, Explosion explosion) {
|
||||||
var exploder = explosion.getDirectSourceEntity();
|
var exploder = explosion.getDirectSourceEntity();
|
||||||
|
@ -87,11 +87,6 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
|||||||
if (!hasMoved()) super.unload();
|
if (!hasMoved()) super.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean canNameWithTag(Player player) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected double getInteractRange() {
|
protected double getInteractRange() {
|
||||||
return 12.0;
|
return 12.0;
|
||||||
|
@ -136,7 +136,7 @@
|
|||||||
"gui.computercraft.config.term_sizes": "Velikosti terminálu",
|
"gui.computercraft.config.term_sizes": "Velikosti terminálu",
|
||||||
"gui.computercraft.config.term_sizes.computer": "Počítač",
|
"gui.computercraft.config.term_sizes.computer": "Počítač",
|
||||||
"gui.computercraft.config.term_sizes.computer.height": "Výška terminálu",
|
"gui.computercraft.config.term_sizes.computer.height": "Výška terminálu",
|
||||||
"gui.computercraft.config.term_sizes.computer.height.tooltip": "Rozsash: 1 ~ 255",
|
"gui.computercraft.config.term_sizes.computer.height.tooltip": "Rozsah: 1 ~ 255",
|
||||||
"gui.computercraft.config.term_sizes.computer.tooltip": "Velikost počítačového terminálu.",
|
"gui.computercraft.config.term_sizes.computer.tooltip": "Velikost počítačového terminálu.",
|
||||||
"gui.computercraft.config.term_sizes.computer.width": "Šířka terminálu",
|
"gui.computercraft.config.term_sizes.computer.width": "Šířka terminálu",
|
||||||
"gui.computercraft.config.term_sizes.computer.width.tooltip": "Rozsah: 1 ~ 255",
|
"gui.computercraft.config.term_sizes.computer.width.tooltip": "Rozsah: 1 ~ 255",
|
||||||
@ -177,7 +177,7 @@
|
|||||||
"gui.computercraft.tooltip.turn_off.key": "Zmáčkni Ctrl+S",
|
"gui.computercraft.tooltip.turn_off.key": "Zmáčkni Ctrl+S",
|
||||||
"gui.computercraft.tooltip.turn_on": "Zapnout teno počítač",
|
"gui.computercraft.tooltip.turn_on": "Zapnout teno počítač",
|
||||||
"gui.computercraft.upload.failed": "Nahrávání se nezdařilo",
|
"gui.computercraft.upload.failed": "Nahrávání se nezdařilo",
|
||||||
"gui.computercraft.upload.failed.computer_off": "Před nahráním souborů musíš vypnout počítač.",
|
"gui.computercraft.upload.failed.computer_off": "Před nahráním souborů musíš zapnout počítač.",
|
||||||
"gui.computercraft.upload.failed.corrupted": "Soubory byly porušeny při nahrávání. Prosím zkus to znovu.",
|
"gui.computercraft.upload.failed.corrupted": "Soubory byly porušeny při nahrávání. Prosím zkus to znovu.",
|
||||||
"gui.computercraft.upload.failed.generic": "Nahrávání souborů se nezdařilo (%s)",
|
"gui.computercraft.upload.failed.generic": "Nahrávání souborů se nezdařilo (%s)",
|
||||||
"gui.computercraft.upload.failed.name_too_long": "Jména souborů pro nahrání jsou příliš dlouhá.",
|
"gui.computercraft.upload.failed.name_too_long": "Jména souborů pro nahrání jsou příliš dlouhá.",
|
||||||
@ -216,5 +216,11 @@
|
|||||||
"upgrade.minecraft.diamond_hoe.adjective": "Farmářský",
|
"upgrade.minecraft.diamond_hoe.adjective": "Farmářský",
|
||||||
"upgrade.minecraft.diamond_pickaxe.adjective": "Těžební",
|
"upgrade.minecraft.diamond_pickaxe.adjective": "Těžební",
|
||||||
"upgrade.minecraft.diamond_shovel.adjective": "Kopací",
|
"upgrade.minecraft.diamond_shovel.adjective": "Kopací",
|
||||||
"upgrade.minecraft.diamond_sword.adjective": "Bojový"
|
"upgrade.minecraft.diamond_sword.adjective": "Bojový",
|
||||||
|
"tag.item.computercraft.computer": "Počítače",
|
||||||
|
"tag.item.computercraft.monitor": "Monitory",
|
||||||
|
"tag.item.computercraft.turtle": "Roboti",
|
||||||
|
"tag.item.computercraft.wired_modem": "Drátové modemy",
|
||||||
|
"gui.computercraft.config.http.proxy": "Proxy",
|
||||||
|
"gui.computercraft.config.upload_max_size.tooltip": "Limit velikosti nahrávaného souboru v bytech. Musí být v rozmezí od 1 KiB do 16 MiB.\nMěj na paměti, že nahrávání souborů je zpracováváno v jednom ticku - velké soubory nebo\nšpatný výkon sítě mohou zpomalit síťové vlákno. A nezapomeň na místo na disku!\nRozsah: 1024 ~ 16777216"
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import net.minecraft.core.BlockPos
|
|||||||
import net.minecraft.core.Direction
|
import net.minecraft.core.Direction
|
||||||
import net.minecraft.gametest.framework.GameTest
|
import net.minecraft.gametest.framework.GameTest
|
||||||
import net.minecraft.gametest.framework.GameTestHelper
|
import net.minecraft.gametest.framework.GameTestHelper
|
||||||
import net.minecraft.world.InteractionHand
|
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraft.world.item.Items
|
import net.minecraft.world.item.Items
|
||||||
import net.minecraft.world.level.block.Blocks
|
import net.minecraft.world.level.block.Blocks
|
||||||
@ -140,8 +139,7 @@ class Computer_Test {
|
|||||||
// Teleport the player to the computer and then open it.
|
// Teleport the player to the computer and then open it.
|
||||||
thenExecute {
|
thenExecute {
|
||||||
context.positionAt(BlockPos(2, 2, 1))
|
context.positionAt(BlockPos(2, 2, 1))
|
||||||
val computer = context.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.COMPUTER_ADVANCED.get())
|
context.useBlock(BlockPos(2, 2, 2), context.level.randomPlayer!!)
|
||||||
computer.use(context.level.randomPlayer!!, InteractionHand.MAIN_HAND)
|
|
||||||
}
|
}
|
||||||
// Assert the terminal is synced to the client.
|
// Assert the terminal is synced to the client.
|
||||||
thenIdle(2)
|
thenIdle(2)
|
||||||
|
@ -183,7 +183,7 @@ function unset(name)
|
|||||||
end
|
end
|
||||||
|
|
||||||
--- Resets the value of all settings. Equivalent to calling [`settings.unset`]
|
--- Resets the value of all settings. Equivalent to calling [`settings.unset`]
|
||||||
--- on every setting.
|
-- on every setting.
|
||||||
--
|
--
|
||||||
-- @see settings.unset
|
-- @see settings.unset
|
||||||
function clear()
|
function clear()
|
||||||
@ -213,16 +213,16 @@ end
|
|||||||
-- Existing settings will be merged with any pre-existing ones. Conflicting
|
-- Existing settings will be merged with any pre-existing ones. Conflicting
|
||||||
-- entries will be overwritten, but any others will be preserved.
|
-- entries will be overwritten, but any others will be preserved.
|
||||||
--
|
--
|
||||||
-- @tparam[opt] string sPath The file to load from, defaulting to `.settings`.
|
-- @tparam[opt=".settings"] string path The file to load from.
|
||||||
-- @treturn boolean Whether settings were successfully read from this
|
-- @treturn boolean Whether settings were successfully read from this
|
||||||
-- file. Reasons for failure may include the file not existing or being
|
-- file. Reasons for failure may include the file not existing or being
|
||||||
-- corrupted.
|
-- corrupted.
|
||||||
--
|
--
|
||||||
-- @see settings.save
|
-- @see settings.save
|
||||||
-- @changed 1.87.0 `sPath` is now optional.
|
-- @changed 1.87.0 `path` is now optional.
|
||||||
function load(sPath)
|
function load(path)
|
||||||
expect(1, sPath, "string", "nil")
|
expect(1, path, "string", "nil")
|
||||||
local file = fs.open(sPath or ".settings", "r")
|
local file = fs.open(path or ".settings", "r")
|
||||||
if not file then
|
if not file then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@ -255,14 +255,14 @@ end
|
|||||||
-- This will entirely overwrite the pre-existing file. Settings defined in the
|
-- This will entirely overwrite the pre-existing file. Settings defined in the
|
||||||
-- file, but not currently loaded will be removed.
|
-- file, but not currently loaded will be removed.
|
||||||
--
|
--
|
||||||
-- @tparam[opt] string sPath The path to save settings to, defaulting to `.settings`.
|
-- @tparam[opt=".settings"] string path The path to save settings to.
|
||||||
-- @treturn boolean If the settings were successfully saved.
|
-- @treturn boolean If the settings were successfully saved.
|
||||||
--
|
--
|
||||||
-- @see settings.load
|
-- @see settings.load
|
||||||
-- @changed 1.87.0 `sPath` is now optional.
|
-- @changed 1.87.0 `path` is now optional.
|
||||||
function save(sPath)
|
function save(path)
|
||||||
expect(1, sPath, "string", "nil")
|
expect(1, path, "string", "nil")
|
||||||
local file = fs.open(sPath or ".settings", "w")
|
local file = fs.open(path or ".settings", "w")
|
||||||
if not file then
|
if not file then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -29,6 +29,7 @@ dependencies {
|
|||||||
implementation(libs.guava)
|
implementation(libs.guava)
|
||||||
implementation(libs.netty.http)
|
implementation(libs.netty.http)
|
||||||
implementation(libs.slf4j)
|
implementation(libs.slf4j)
|
||||||
|
runtimeOnly(libs.teavm.core) // Contains the TeaVM runtime
|
||||||
|
|
||||||
"builderCompileOnly"(libs.bundles.annotations)
|
"builderCompileOnly"(libs.bundles.annotations)
|
||||||
"builderImplementation"(libs.bundles.teavm.tooling)
|
"builderImplementation"(libs.bundles.teavm.tooling)
|
||||||
|
@ -68,6 +68,10 @@ public class TransformingClassLoader extends ClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Path findUnmappedFile(String name) {
|
private @Nullable Path findUnmappedFile(String name) {
|
||||||
|
// For some odd reason, we try to resolve the generated lambda classes. This includes classes called
|
||||||
|
// things like <linit>lambda, which is an invalid path on Windows. Detect those, and abort early.
|
||||||
|
if (name.indexOf("<") >= 0) return null;
|
||||||
|
|
||||||
return classpath.stream().map(x -> x.resolve(name)).filter(Files::exists).findFirst().orElse(null);
|
return classpath.stream().map(x -> x.resolve(name)).filter(Files::exists).findFirst().orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,13 +99,18 @@ public class TransformingClassLoader extends ClassLoader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable InputStream getResourceAsStream(String name) {
|
public @Nullable InputStream getResourceAsStream(String name) {
|
||||||
if (!name.endsWith(".class")) return super.getResourceAsStream(name);
|
if (!name.endsWith(".class") || name.startsWith("java/") || name.startsWith("javax/")) {
|
||||||
|
return super.getResourceAsStream(name);
|
||||||
|
}
|
||||||
|
|
||||||
var lastFile = this.lastFile;
|
var lastFile = this.lastFile;
|
||||||
if (lastFile != null && lastFile.name().equals(name)) return new ByteArrayInputStream(lastFile.contents());
|
if (lastFile != null && lastFile.name().equals(name)) return new ByteArrayInputStream(lastFile.contents());
|
||||||
|
|
||||||
var path = findFile(name);
|
var path = findFile(name);
|
||||||
if (path == null) return null;
|
if (path == null) {
|
||||||
|
System.out.printf("Cannot find %s. Falling back to system class loader.\n", name);
|
||||||
|
return super.getResourceAsStream(name);
|
||||||
|
}
|
||||||
|
|
||||||
ClassReader reader;
|
ClassReader reader;
|
||||||
try (var stream = Files.newInputStream(path)) {
|
try (var stream = Files.newInputStream(path)) {
|
||||||
|
@ -72,6 +72,10 @@ class EmulatedComputer implements ComputerDisplay, ComputerActionable {
|
|||||||
for (const callback of this.callbacks) callback(computer);
|
for (const callback of this.callbacks) callback(computer);
|
||||||
})
|
})
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
|
console.error(e);
|
||||||
|
|
||||||
|
if (this.terminal.sizeX === 0 || this.terminal.sizeY === 0) this.terminal.resize(51, 19);
|
||||||
|
|
||||||
const width = this.terminal.sizeX;
|
const width = this.terminal.sizeX;
|
||||||
const fg = "0".repeat(width);
|
const fg = "0".repeat(width);
|
||||||
const bg = "e".repeat(width);
|
const bg = "e".repeat(width);
|
||||||
@ -83,6 +87,8 @@ class EmulatedComputer implements ComputerDisplay, ComputerActionable {
|
|||||||
this.terminal.fore[y] = fg;
|
this.terminal.fore[y] = fg;
|
||||||
this.terminal.back[y] = bg;
|
this.terminal.back[y] = bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.flushTerminal();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user