mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-14 12:07:10 +00:00
Compare commits
1 Commits
v1.20.1-1.
...
feature/li
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d3d8e6a8e |
39
.github/workflows/main-ci.yml
vendored
39
.github/workflows/main-ci.yml
vendored
@@ -8,16 +8,16 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 📥 Clone repository
|
- name: Clone repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: 📥 Set up Java
|
- name: Set up Java
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
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/gradle-build-action@v2
|
||||||
with:
|
with:
|
||||||
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
cache-read-only: ${{ !startsWith(github.ref, 'refs/heads/mc-') }}
|
||||||
@@ -27,45 +27,42 @@ jobs:
|
|||||||
mkdir -p ~/.gradle
|
mkdir -p ~/.gradle
|
||||||
echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
|
echo "org.gradle.daemon=false" >> ~/.gradle/gradle.properties
|
||||||
|
|
||||||
- name: ⚒️ Build
|
- name: Build with Gradle
|
||||||
run: ./gradlew assemble || ./gradlew assemble
|
run: ./gradlew assemble || ./gradlew assemble
|
||||||
|
|
||||||
- name: 💡 Lint
|
- name: Download assets for game tests
|
||||||
uses: pre-commit/action@v3.0.0
|
|
||||||
|
|
||||||
- name: 🧪 Run tests
|
|
||||||
run: ./gradlew test validateMixinNames checkChangelog
|
|
||||||
|
|
||||||
- name: 📥 Download assets for game tests
|
|
||||||
run: ./gradlew downloadAssets || ./gradlew downloadAssets
|
run: ./gradlew downloadAssets || ./gradlew downloadAssets
|
||||||
|
|
||||||
- name: 🧪 Run integration tests
|
- name: Run tests and linters
|
||||||
run: ./gradlew runGametest
|
run: ./gradlew build
|
||||||
|
|
||||||
- name: 🧪 Run client tests
|
- name: Run client tests
|
||||||
run: ./gradlew runGametestClient # Not checkClient, as no point running rendering tests.
|
run: ./gradlew runGametestClient # Not checkClient, as no point running rendering tests.
|
||||||
# These are a little flaky on GH actions: its useful to run them, but don't break the build.
|
# These are a little flaky on GH actions: its useful to run them, but don't break the build.
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
|
|
||||||
- name: 🧪 Parse test reports
|
- name: Prepare Jars
|
||||||
run: ./tools/parse-reports.py
|
|
||||||
if: ${{ failure() }}
|
|
||||||
|
|
||||||
- name: 📦 Prepare Jars
|
|
||||||
run: |
|
run: |
|
||||||
# Find the main jar and append the git hash onto it.
|
# Find the main jar and append the git hash onto it.
|
||||||
mkdir -p jars
|
mkdir -p jars
|
||||||
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@v3
|
||||||
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@v3
|
||||||
|
|
||||||
|
- name: Parse test reports
|
||||||
|
run: ./tools/parse-reports.py
|
||||||
|
if: ${{ failure() }}
|
||||||
|
|
||||||
|
- name: Run linters
|
||||||
|
uses: pre-commit/action@v3.0.0
|
||||||
|
|
||||||
build-core:
|
build-core:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ Upstream-Contact: Jonathan Coates <git@squiddev.cc>
|
|||||||
Files:
|
Files:
|
||||||
projects/common/src/main/resources/assets/computercraft/sounds.json
|
projects/common/src/main/resources/assets/computercraft/sounds.json
|
||||||
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/structures/*
|
projects/common/src/testMod/resources/data/cctest/structures/*
|
||||||
projects/fabric/src/generated/*
|
projects/fabric/src/generated/*
|
||||||
projects/forge/src/generated/*
|
projects/forge/src/generated/*
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ repositories {
|
|||||||
includeGroup("org.squiddev")
|
includeGroup("org.squiddev")
|
||||||
includeGroup("cc.tweaked")
|
includeGroup("cc.tweaked")
|
||||||
// Things we mirror
|
// Things we mirror
|
||||||
|
includeGroup("alexiil.mc.lib")
|
||||||
includeGroup("dev.architectury")
|
includeGroup("dev.architectury")
|
||||||
includeGroup("maven.modrinth")
|
includeGroup("maven.modrinth")
|
||||||
includeGroup("me.shedaniel")
|
includeGroup("me.shedaniel")
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ fun JavaExec.copyToFull(spec: JavaExec) {
|
|||||||
* Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo].
|
* Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo].
|
||||||
*/
|
*/
|
||||||
fun BaseExecSpec.copyToExec(spec: BaseExecSpec) {
|
fun BaseExecSpec.copyToExec(spec: BaseExecSpec) {
|
||||||
|
spec.workingDir = workingDir
|
||||||
spec.isIgnoreExitValue = isIgnoreExitValue
|
spec.isIgnoreExitValue = isIgnoreExitValue
|
||||||
if (standardInput != null) spec.standardInput = standardInput
|
if (standardInput != null) spec.standardInput = standardInput
|
||||||
if (standardOutput != null) spec.standardOutput = standardOutput
|
if (standardOutput != null) spec.standardOutput = standardOutput
|
||||||
|
|||||||
@@ -30,22 +30,41 @@ internal fun setRunConfigInternal(project: Project, spec: JavaExecSpec, config:
|
|||||||
val originalTask = project.tasks.named(config.taskName, MinecraftRunTask::class.java)
|
val originalTask = project.tasks.named(config.taskName, MinecraftRunTask::class.java)
|
||||||
|
|
||||||
// Add argument and JVM argument via providers, to be as lazy as possible with fetching artifacts.
|
// Add argument and JVM argument via providers, to be as lazy as possible with fetching artifacts.
|
||||||
val lazyTokens = RunConfigGenerator.configureTokensLazy(
|
fun lazyTokens(): MutableMap<String, Supplier<String>> {
|
||||||
project, config, RunConfigGenerator.mapModClassesToGradle(project, config),
|
return RunConfigGenerator.configureTokensLazy(
|
||||||
originalTask.get().minecraftArtifacts,
|
project, config, RunConfigGenerator.mapModClassesToGradle(project, config),
|
||||||
originalTask.get().runtimeClasspathArtifacts,
|
originalTask.get().minecraftArtifacts.files,
|
||||||
)
|
originalTask.get().runtimeClasspathArtifacts.files,
|
||||||
|
)
|
||||||
|
}
|
||||||
spec.argumentProviders.add(
|
spec.argumentProviders.add(
|
||||||
CommandLineArgumentProvider {
|
CommandLineArgumentProvider {
|
||||||
RunConfigGenerator.getArgsStream(config, lazyTokens, false).toList()
|
RunConfigGenerator.getArgsStream(config, lazyTokens(), false).toList()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
spec.jvmArgumentProviders.add(
|
spec.jvmArgumentProviders.add(
|
||||||
CommandLineArgumentProvider {
|
CommandLineArgumentProvider {
|
||||||
|
val lazyTokens = lazyTokens()
|
||||||
(if (config.isClient) config.jvmArgs + originalTask.get().additionalClientArgs.get() else config.jvmArgs).map { config.replace(lazyTokens, it) } +
|
(if (config.isClient) config.jvmArgs + originalTask.get().additionalClientArgs.get() else config.jvmArgs).map { config.replace(lazyTokens, it) } +
|
||||||
config.properties.map { (k, v) -> "-D${k}=${config.replace(lazyTokens, v)}" }
|
config.properties.map { (k, v) -> "-D${k}=${config.replace(lazyTokens, v)}" }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// We can't configure environment variables lazily, so we do these now with a more minimal lazyTokens set.
|
||||||
|
val lazyTokens = mutableMapOf<String, Supplier<String>>()
|
||||||
|
for ((k, v) in config.tokens) lazyTokens[k] = Supplier<String> { v }
|
||||||
|
for ((k, v) in config.lazyTokens) lazyTokens[k] = v
|
||||||
|
lazyTokens.compute(
|
||||||
|
"source_roots",
|
||||||
|
{ _, sourceRoots ->
|
||||||
|
Supplier<String> {
|
||||||
|
val modClasses = RunConfigGenerator.mapModClassesToGradle(project, config)
|
||||||
|
(when (sourceRoots) {
|
||||||
|
null -> modClasses
|
||||||
|
else -> Stream.concat<String>(sourceRoots.get().split(File.pathSeparator).stream(), modClasses)
|
||||||
|
}).distinct().collect(Collectors.joining(File.pathSeparator))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
for ((key, value) in config.environment) spec.environment(key, config.replace(lazyTokens, value))
|
for ((key, value) in config.environment) spec.environment(key, config.replace(lazyTokens, value))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,6 @@ The @{websocket_closed} event is fired when an open WebSocket connection is clos
|
|||||||
## Return Values
|
## Return Values
|
||||||
1. @{string}: The event name.
|
1. @{string}: The event name.
|
||||||
2. @{string}: The URL of the WebSocket that was closed.
|
2. @{string}: The URL of the WebSocket that was closed.
|
||||||
3. <span class="type">@{string}|@{nil}</span>: The [server-provided reason][close_reason]
|
|
||||||
the websocket was closed. This will be @{nil} if the connection was closed
|
|
||||||
abnormally.
|
|
||||||
4. <span class="type">@{number}|@{nil}</span>: The [connection close code][close_code],
|
|
||||||
indicating why the socket was closed. This will be @{nil} if the connection
|
|
||||||
was closed abnormally.
|
|
||||||
|
|
||||||
[close_reason]: https://www.rfc-editor.org/rfc/rfc6455.html#section-7.1.6 "The WebSocket Connection Close Reason, RFC 6455"
|
|
||||||
[close_code]: https://www.rfc-editor.org/rfc/rfc6455.html#section-7.1.5 "The WebSocket Connection Close Code, RFC 6455"
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
Prints a message when a WebSocket is closed (this may take a minute):
|
Prints a message when a WebSocket is closed (this may take a minute):
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error
|
|||||||
|
|
||||||
# Mod properties
|
# Mod properties
|
||||||
isUnstable=false
|
isUnstable=false
|
||||||
modVersion=1.106.1
|
modVersion=1.105.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.19.4
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
# Minecraft
|
# Minecraft
|
||||||
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
# MC version is specified in gradle.properties, as we need that in settings.gradle.
|
||||||
# Remember to update corresponding versions in fabric.mod.json/mods.toml
|
# Remember to update corresponding versions in fabric.mod.json/mods.toml
|
||||||
fabric-api = "0.83.1+1.20.1"
|
fabric-api = "0.80.0+1.19.4"
|
||||||
fabric-loader = "0.14.21"
|
fabric-loader = "0.14.19"
|
||||||
forge = "47.1.0"
|
forge = "45.0.42"
|
||||||
forgeSpi = "6.0.0"
|
forgeSpi = "6.0.0"
|
||||||
mixin = "0.8.5"
|
mixin = "0.8.5"
|
||||||
parchment = "2023.03.12"
|
parchment = "2023.03.12"
|
||||||
@@ -35,6 +35,7 @@ slf4j = "1.7.36"
|
|||||||
# Minecraft mods
|
# Minecraft mods
|
||||||
iris = "1.5.2+1.19.4"
|
iris = "1.5.2+1.19.4"
|
||||||
jei = "13.1.0.11"
|
jei = "13.1.0.11"
|
||||||
|
libmultipart = "0.10.0"
|
||||||
modmenu = "6.1.0-rc.1"
|
modmenu = "6.1.0-rc.1"
|
||||||
oculus = "1.2.5"
|
oculus = "1.2.5"
|
||||||
rei = "10.0.578"
|
rei = "10.0.578"
|
||||||
@@ -53,8 +54,8 @@ checkstyle = "10.3.4"
|
|||||||
curseForgeGradle = "1.0.14"
|
curseForgeGradle = "1.0.14"
|
||||||
errorProne-core = "2.18.0"
|
errorProne-core = "2.18.0"
|
||||||
errorProne-plugin = "3.0.1"
|
errorProne-plugin = "3.0.1"
|
||||||
fabric-loom = "1.3.7"
|
fabric-loom = "1.2.7"
|
||||||
forgeGradle = "6.0.8"
|
forgeGradle = "6.0.6"
|
||||||
githubRelease = "2.2.12"
|
githubRelease = "2.2.12"
|
||||||
ideaExt = "1.1.6"
|
ideaExt = "1.1.6"
|
||||||
illuaminate = "0.1.0-28-ga7efd71"
|
illuaminate = "0.1.0-28-ga7efd71"
|
||||||
@@ -96,6 +97,7 @@ iris = { module = "maven.modrinth:iris", version.ref = "iris" }
|
|||||||
jei-api = { module = "mezz.jei:jei-1.19.4-common-api", version.ref = "jei" }
|
jei-api = { module = "mezz.jei:jei-1.19.4-common-api", version.ref = "jei" }
|
||||||
jei-fabric = { module = "mezz.jei:jei-1.19.4-fabric", version.ref = "jei" }
|
jei-fabric = { module = "mezz.jei:jei-1.19.4-fabric", version.ref = "jei" }
|
||||||
jei-forge = { module = "mezz.jei:jei-1.19.4-forge", version.ref = "jei" }
|
jei-forge = { module = "mezz.jei:jei-1.19.4-forge", version.ref = "jei" }
|
||||||
|
libmultipart = { module = "alexiil.mc.lib:libmultipart-all", version.ref = "libmultipart" }
|
||||||
mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" }
|
mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" }
|
||||||
modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" }
|
modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" }
|
||||||
oculus = { module = "maven.modrinth:oculus", version.ref = "oculus" }
|
oculus = { module = "maven.modrinth:oculus", version.ref = "oculus" }
|
||||||
@@ -150,10 +152,10 @@ kotlin = ["kotlin-stdlib", "kotlin-coroutines"]
|
|||||||
# Minecraft
|
# Minecraft
|
||||||
externalMods-common = ["jei-api", "nightConfig-core", "nightConfig-toml"]
|
externalMods-common = ["jei-api", "nightConfig-core", "nightConfig-toml"]
|
||||||
externalMods-forge-compile = ["oculus", "jei-api"]
|
externalMods-forge-compile = ["oculus", "jei-api"]
|
||||||
externalMods-forge-runtime = []
|
externalMods-forge-runtime = ["jei-forge"]
|
||||||
externalMods-fabric = ["nightConfig-core", "nightConfig-toml"]
|
externalMods-fabric = ["nightConfig-core", "nightConfig-toml"]
|
||||||
externalMods-fabric-compile = ["iris", "jei-api", "rei-api", "rei-builtin"]
|
externalMods-fabric-compile = ["iris", "jei-api", "rei-api", "rei-builtin", "libmultipart"]
|
||||||
externalMods-fabric-runtime = []
|
externalMods-fabric-runtime = ["jei-fabric", "modmenu"]
|
||||||
|
|
||||||
# Testing
|
# Testing
|
||||||
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
test = ["junit-jupiter-api", "junit-jupiter-params", "hamcrest", "jqwik-api"]
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.pocket;
|
package dan200.computercraft.api.pocket;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
||||||
import dan200.computercraft.impl.ComputerCraftAPIService;
|
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||||
@@ -29,6 +30,14 @@ import java.util.function.Function;
|
|||||||
* @see PocketUpgradeDataProvider
|
* @see PocketUpgradeDataProvider
|
||||||
*/
|
*/
|
||||||
public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends UpgradeSerialiser<T> {
|
public interface PocketUpgradeSerialiser<T extends IPocketUpgrade> extends UpgradeSerialiser<T> {
|
||||||
|
/**
|
||||||
|
* The ID for the associated registry.
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #registryId()} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
ResourceKey<Registry<PocketUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "pocket_upgrade_serialiser"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID for the associated registry.
|
* The ID for the associated registry.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import net.minecraft.nbt.CompoundTag;
|
|||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -70,6 +71,29 @@ public interface ITurtleAccess {
|
|||||||
*/
|
*/
|
||||||
boolean teleportTo(Level world, BlockPos pos);
|
boolean teleportTo(Level world, BlockPos pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a vector containing the floating point co-ordinates at which the turtle is rendered.
|
||||||
|
* This will shift when the turtle is moving.
|
||||||
|
*
|
||||||
|
* @param f The subframe fraction.
|
||||||
|
* @return A vector containing the floating point co-ordinates at which the turtle resides.
|
||||||
|
* @see #getVisualYaw(float)
|
||||||
|
* @deprecated Will be removed in 1.20.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
Vec3 getVisualPosition(float f);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the yaw the turtle is facing when it is rendered.
|
||||||
|
*
|
||||||
|
* @param f The subframe fraction.
|
||||||
|
* @return The yaw the turtle is facing.
|
||||||
|
* @see #getVisualPosition(float)
|
||||||
|
* @deprecated Will be removed in 1.20.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
float getVisualYaw(float f);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the world direction the turtle is currently facing.
|
* Returns the world direction the turtle is currently facing.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MPL-2.0
|
|
||||||
|
|
||||||
package dan200.computercraft.api.turtle;
|
|
||||||
|
|
||||||
import net.minecraft.util.StringRepresentable;
|
|
||||||
import net.minecraft.world.entity.EquipmentSlot;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if an equipped turtle item will consume durability.
|
|
||||||
*
|
|
||||||
* @see TurtleUpgradeDataProvider.ToolBuilder#consumeDurability(TurtleToolDurability)
|
|
||||||
*/
|
|
||||||
public enum TurtleToolDurability implements StringRepresentable {
|
|
||||||
/**
|
|
||||||
* The equipped tool always consumes durability when using.
|
|
||||||
*/
|
|
||||||
ALWAYS("always"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The equipped tool consumes durability if it is {@linkplain ItemStack#isEnchanted() enchanted} or has
|
|
||||||
* {@linkplain ItemStack#getAttributeModifiers(EquipmentSlot) custom attribute modifiers}.
|
|
||||||
*/
|
|
||||||
WHEN_ENCHANTED("when_enchanted"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The equipped tool never consumes durability. Tools which have been damaged cannot be used as upgrades.
|
|
||||||
*/
|
|
||||||
NEVER("never");
|
|
||||||
|
|
||||||
private final String serialisedName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The codec which may be used for serialising/deserialising {@link TurtleToolDurability}s.
|
|
||||||
*/
|
|
||||||
public static final StringRepresentable.EnumCodec<TurtleToolDurability> CODEC = StringRepresentable.fromEnum(TurtleToolDurability::values);
|
|
||||||
|
|
||||||
TurtleToolDurability(String serialisedName) {
|
|
||||||
this.serialisedName = serialisedName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSerializedName() {
|
|
||||||
return serialisedName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -13,10 +13,8 @@ import net.minecraft.data.DataGenerator;
|
|||||||
import net.minecraft.data.PackOutput;
|
import net.minecraft.data.PackOutput;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.entity.EquipmentSlot;
|
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -63,8 +61,6 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
|
|||||||
private @Nullable Item craftingItem;
|
private @Nullable Item craftingItem;
|
||||||
private @Nullable Float damageMultiplier = null;
|
private @Nullable Float damageMultiplier = null;
|
||||||
private @Nullable TagKey<Block> breakable;
|
private @Nullable TagKey<Block> breakable;
|
||||||
private boolean allowEnchantments = false;
|
|
||||||
private TurtleToolDurability consumeDurability = TurtleToolDurability.NEVER;
|
|
||||||
|
|
||||||
ToolBuilder(ResourceLocation id, TurtleUpgradeSerialiser<?> serialiser, Item toolItem) {
|
ToolBuilder(ResourceLocation id, TurtleUpgradeSerialiser<?> serialiser, Item toolItem) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@@ -108,28 +104,6 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicate that this upgrade allows items which have been {@linkplain ItemStack#isEnchanted() enchanted} or have
|
|
||||||
* {@linkplain ItemStack#getAttributeModifiers(EquipmentSlot) custom attribute modifiers}.
|
|
||||||
*
|
|
||||||
* @return The tool builder, for further use.
|
|
||||||
*/
|
|
||||||
public ToolBuilder allowEnchantments() {
|
|
||||||
allowEnchantments = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set when the tool will consume durability.
|
|
||||||
*
|
|
||||||
* @param durability The durability predicate.
|
|
||||||
* @return The tool builder, for further use.
|
|
||||||
*/
|
|
||||||
public ToolBuilder consumeDurability(TurtleToolDurability durability) {
|
|
||||||
consumeDurability = durability;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a list of breakable blocks. If not given, the tool can break all blocks. If given, only blocks
|
* Provide a list of breakable blocks. If not given, the tool can break all blocks. If given, only blocks
|
||||||
* in this tag, those in {@link ComputerCraftTags.Blocks#TURTLE_ALWAYS_BREAKABLE} and "insta-mine" ones can
|
* in this tag, those in {@link ComputerCraftTags.Blocks#TURTLE_ALWAYS_BREAKABLE} and "insta-mine" ones can
|
||||||
@@ -158,10 +132,6 @@ public abstract class TurtleUpgradeDataProvider extends UpgradeDataProvider<ITur
|
|||||||
}
|
}
|
||||||
if (damageMultiplier != null) s.addProperty("damageMultiplier", damageMultiplier);
|
if (damageMultiplier != null) s.addProperty("damageMultiplier", damageMultiplier);
|
||||||
if (breakable != null) s.addProperty("breakable", breakable.location().toString());
|
if (breakable != null) s.addProperty("breakable", breakable.location().toString());
|
||||||
if (allowEnchantments) s.addProperty("allowEnchantments", true);
|
|
||||||
if (consumeDurability != TurtleToolDurability.NEVER) {
|
|
||||||
s.addProperty("consumeDurability", consumeDurability.getSerializedName());
|
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.api.turtle;
|
package dan200.computercraft.api.turtle;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
import dan200.computercraft.api.upgrades.UpgradeSerialiser;
|
||||||
import dan200.computercraft.impl.ComputerCraftAPIService;
|
import dan200.computercraft.impl.ComputerCraftAPIService;
|
||||||
@@ -64,6 +65,14 @@ import java.util.function.Function;
|
|||||||
* @see dan200.computercraft.api.client.turtle.TurtleUpgradeModeller
|
* @see dan200.computercraft.api.client.turtle.TurtleUpgradeModeller
|
||||||
*/
|
*/
|
||||||
public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends UpgradeSerialiser<T> {
|
public interface TurtleUpgradeSerialiser<T extends ITurtleUpgrade> extends UpgradeSerialiser<T> {
|
||||||
|
/**
|
||||||
|
* The ID for the associated registry.
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #registryId()} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
ResourceKey<Registry<TurtleUpgradeSerialiser<?>>> REGISTRY_ID = ResourceKey.createRegistryKey(new ResourceLocation(ComputerCraftAPI.MOD_ID, "turtle_upgrade_serialiser"));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID for the associated registry.
|
* The ID for the associated registry.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
||||||
import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
||||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||||
@@ -18,7 +19,6 @@ 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.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
@@ -124,10 +124,10 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void render(PoseStack stack, int mouseX, int mouseY, float partialTicks) {
|
||||||
renderBackground(graphics);
|
renderBackground(stack);
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(stack, mouseX, mouseY, partialTicks);
|
||||||
renderTooltip(graphics, mouseX, mouseY);
|
renderTooltip(stack, mouseX, mouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -147,7 +147,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
|
protected void renderLabels(PoseStack transform, int mouseX, int mouseY) {
|
||||||
// Skip rendering labels.
|
// Skip rendering labels.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
||||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||||
import dan200.computercraft.client.render.ComputerBorderRenderer;
|
import dan200.computercraft.client.render.ComputerBorderRenderer;
|
||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
|
||||||
@@ -36,14 +36,13 @@ public final class ComputerScreen<T extends AbstractComputerMenu> extends Abstra
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
|
public void renderBg(PoseStack stack, float partialTicks, int mouseX, int mouseY) {
|
||||||
// Draw a border around the terminal
|
// Draw a border around the terminal
|
||||||
var terminal = getTerminal();
|
var terminal = getTerminal();
|
||||||
var texture = ComputerBorderRenderer.getTexture(family);
|
|
||||||
ComputerBorderRenderer.render(
|
ComputerBorderRenderer.render(
|
||||||
graphics.pose().last().pose(), texture, terminal.getX(), terminal.getY(),
|
stack.last().pose(), ComputerBorderRenderer.getTexture(family), terminal.getX(), terminal.getY(),
|
||||||
FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight()
|
FULL_BRIGHT_LIGHTMAP, terminal.getWidth(), terminal.getHeight()
|
||||||
);
|
);
|
||||||
ComputerSidebar.renderBackground(graphics, texture, leftPos, topPos + sidebarYOffset);
|
ComputerSidebar.renderBackground(stack, leftPos, topPos + sidebarYOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveMenu;
|
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveMenu;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -22,14 +23,16 @@ public class DiskDriveScreen extends AbstractContainerScreen<DiskDriveMenu> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
|
protected void renderBg(PoseStack transform, float partialTicks, int mouseX, int mouseY) {
|
||||||
graphics.blit(BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight);
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
|
RenderSystem.setShaderTexture(0, BACKGROUND);
|
||||||
|
blit(transform, leftPos, topPos, 0, 0, imageWidth, imageHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void render(PoseStack transform, int mouseX, int mouseY, float partialTicks) {
|
||||||
renderBackground(graphics);
|
renderBackground(transform);
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(transform, mouseX, mouseY, partialTicks);
|
||||||
renderTooltip(graphics, mouseX, mouseY);
|
renderTooltip(transform, mouseX, mouseY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiComponent;
|
||||||
import net.minecraft.client.gui.components.toasts.Toast;
|
import net.minecraft.client.gui.components.toasts.Toast;
|
||||||
import net.minecraft.client.gui.components.toasts.ToastComponent;
|
import net.minecraft.client.gui.components.toasts.ToastComponent;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@@ -71,52 +73,55 @@ public class ItemToast implements Toast {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Visibility render(GuiGraphics graphics, ToastComponent component, long time) {
|
public Visibility render(PoseStack transform, ToastComponent component, long time) {
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
|
|
||||||
firstDisplay = time;
|
firstDisplay = time;
|
||||||
isNew = false;
|
isNew = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RenderSystem.setShaderTexture(0, TEXTURE);
|
||||||
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
|
|
||||||
if (width == 160 && message.size() <= 1) {
|
if (width == 160 && message.size() <= 1) {
|
||||||
graphics.blit(TEXTURE, 0, 0, 0, 64, width, height());
|
GuiComponent.blit(transform, 0, 0, 0, 64, width, height());
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
var height = height();
|
var height = height();
|
||||||
|
|
||||||
var bottom = Math.min(4, height - 28);
|
var bottom = Math.min(4, height - 28);
|
||||||
renderBackgroundRow(graphics, width, 0, 0, 28);
|
renderBackgroundRow(transform, component, width, 0, 0, 28);
|
||||||
|
|
||||||
for (var i = 28; i < height - bottom; i += 10) {
|
for (var i = 28; i < height - bottom; i += 10) {
|
||||||
renderBackgroundRow(graphics, width, 16, i, Math.min(16, height - i - bottom));
|
renderBackgroundRow(transform, component, width, 16, i, Math.min(16, height - i - bottom));
|
||||||
}
|
}
|
||||||
|
|
||||||
renderBackgroundRow(graphics, width, 32 - bottom, height - bottom, bottom);
|
renderBackgroundRow(transform, component, width, 32 - bottom, height - bottom, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
var textX = MARGIN;
|
var textX = MARGIN;
|
||||||
if (!stack.isEmpty()) {
|
if (!stack.isEmpty()) {
|
||||||
textX += MARGIN + IMAGE_SIZE;
|
textX += MARGIN + IMAGE_SIZE;
|
||||||
graphics.renderFakeItem(stack, MARGIN, MARGIN + height() / 2 - IMAGE_SIZE);
|
component.getMinecraft().getItemRenderer().renderAndDecorateFakeItem(transform, stack, MARGIN, MARGIN + height() / 2 - IMAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.drawString(component.getMinecraft().font, title, textX, MARGIN, 0xff500050, false);
|
component.getMinecraft().font.draw(transform, title, textX, MARGIN, 0xff500050);
|
||||||
for (var i = 0; i < message.size(); ++i) {
|
for (var i = 0; i < message.size(); ++i) {
|
||||||
graphics.drawString(component.getMinecraft().font, message.get(i), textX, LINE_SPACING + (i + 1) * LINE_SPACING, 0xff000000, false);
|
component.getMinecraft().font.draw(transform, message.get(i), textX, (float) (LINE_SPACING + (i + 1) * LINE_SPACING), 0xff000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return time - firstDisplay < DISPLAY_TIME ? Visibility.SHOW : Visibility.HIDE;
|
return time - firstDisplay < DISPLAY_TIME ? Visibility.SHOW : Visibility.HIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void renderBackgroundRow(GuiGraphics graphics, int x, int u, int y, int height) {
|
private static void renderBackgroundRow(PoseStack transform, ToastComponent component, int x, int u, int y, int height) {
|
||||||
var leftOffset = 5;
|
var leftOffset = 5;
|
||||||
var rightOffset = Math.min(60, x - leftOffset);
|
var rightOffset = Math.min(60, x - leftOffset);
|
||||||
|
|
||||||
graphics.blit(TEXTURE, 0, y, 0, 32 + u, leftOffset, height);
|
GuiComponent.blit(transform, 0, y, 0, 32 + u, leftOffset, height);
|
||||||
for (var k = leftOffset; k < x - rightOffset; k += 64) {
|
for (var k = leftOffset; k < x - rightOffset; k += 64) {
|
||||||
graphics.blit(TEXTURE, k, y, 32, 32 + u, Math.min(64, x - k - rightOffset), height);
|
GuiComponent.blit(transform, k, y, 32, 32 + u, Math.min(64, x - k - rightOffset), height);
|
||||||
}
|
}
|
||||||
|
|
||||||
graphics.blit(TEXTURE, x - rightOffset, y, 160 - rightOffset, 32 + u, rightOffset, height);
|
GuiComponent.blit(transform, x - rightOffset, y, 160 - rightOffset, 32 + u, rightOffset, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
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.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.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;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@@ -42,6 +42,7 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
|
passEvents = true; // Pass mouse vents through to the game's mouse handler.
|
||||||
// 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();
|
||||||
@@ -90,15 +91,15 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void render(PoseStack transform, int mouseX, int mouseY, float partialTicks) {
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(transform, 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.0f;
|
||||||
for (var line : lines) {
|
for (var line : lines) {
|
||||||
graphics.drawString(font, line, (width / 2) - (minecraft.font.width(line) / 2), y, 0xFFFFFF, true);
|
font.drawShadow(transform, line, (float) ((width / 2) - (minecraft.font.width(line) / 2)), y, 0xFFFFFF);
|
||||||
y += 9;
|
y += 9.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.AbstractWidget;
|
import net.minecraft.client.gui.components.AbstractWidget;
|
||||||
import net.minecraft.client.gui.components.Button;
|
import net.minecraft.client.gui.components.Button;
|
||||||
import net.minecraft.client.gui.components.MultiLineLabel;
|
import net.minecraft.client.gui.components.MultiLineLabel;
|
||||||
@@ -85,19 +86,20 @@ public final class OptionScreen extends Screen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void render(PoseStack transform, int mouseX, int mouseY, float partialTicks) {
|
||||||
renderBackground(graphics);
|
renderBackground(transform);
|
||||||
|
|
||||||
// Render the actual texture.
|
// Render the actual texture.
|
||||||
graphics.blit(BACKGROUND, x, y, 0, 0, innerWidth, PADDING);
|
RenderSystem.setShaderTexture(0, BACKGROUND);
|
||||||
graphics.blit(BACKGROUND,
|
blit(transform, x, y, 0, 0, innerWidth, PADDING);
|
||||||
|
blit(transform,
|
||||||
x, y + PADDING, 0, PADDING, innerWidth, innerHeight - PADDING * 2,
|
x, y + PADDING, 0, PADDING, innerWidth, innerHeight - PADDING * 2,
|
||||||
innerWidth, PADDING
|
innerWidth, PADDING
|
||||||
);
|
);
|
||||||
graphics.blit(BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING);
|
blit(transform, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING);
|
||||||
|
|
||||||
assertNonNull(messageRenderer).renderLeftAlignedNoShadow(graphics, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040);
|
assertNonNull(messageRenderer).renderLeftAlignedNoShadow(transform, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040);
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(transform, mouseX, mouseY, partialTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dan200.computercraft.shared.peripheral.printer.PrinterMenu;
|
import dan200.computercraft.shared.peripheral.printer.PrinterMenu;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
@@ -22,16 +23,18 @@ public class PrinterScreen extends AbstractContainerScreen<PrinterMenu> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
|
protected void renderBg(PoseStack transform, float partialTicks, int mouseX, int mouseY) {
|
||||||
graphics.blit(BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight);
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
|
RenderSystem.setShaderTexture(0, BACKGROUND);
|
||||||
|
blit(transform, leftPos, topPos, 0, 0, imageWidth, imageHeight);
|
||||||
|
|
||||||
if (getMenu().isPrinting()) graphics.blit(BACKGROUND, leftPos + 34, topPos + 21, 176, 0, 25, 45);
|
if (getMenu().isPrinting()) blit(transform, leftPos + 34, topPos + 21, 176, 0, 25, 45);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void render(PoseStack stack, int mouseX, int mouseY, float partialTicks) {
|
||||||
renderBackground(graphics);
|
renderBackground(stack);
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(stack, mouseX, mouseY, partialTicks);
|
||||||
renderTooltip(graphics, mouseX, mouseY);
|
renderTooltip(stack, mouseX, mouseY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,12 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.Tesselator;
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
import dan200.computercraft.core.terminal.TextBuffer;
|
import dan200.computercraft.core.terminal.TextBuffer;
|
||||||
import dan200.computercraft.shared.common.HeldItemMenu;
|
import dan200.computercraft.shared.common.HeldItemMenu;
|
||||||
import dan200.computercraft.shared.media.items.PrintoutItem;
|
import dan200.computercraft.shared.media.items.PrintoutItem;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
import net.minecraft.client.renderer.MultiBufferSource;
|
import net.minecraft.client.renderer.MultiBufferSource;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@@ -82,27 +83,30 @@ public class PrintoutScreen extends AbstractContainerScreen<HeldItemMenu> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
|
protected void renderBg(PoseStack transform, float partialTicks, int mouseX, int mouseY) {
|
||||||
// Draw the printout
|
// Draw the printout
|
||||||
|
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
|
|
||||||
var renderer = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
|
var renderer = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
|
||||||
drawBorder(graphics.pose(), renderer, leftPos, topPos, 0, page, pages, book, FULL_BRIGHT_LIGHTMAP);
|
drawBorder(transform, renderer, leftPos, topPos, 0, page, pages, book, FULL_BRIGHT_LIGHTMAP);
|
||||||
drawText(graphics.pose(), renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutItem.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours);
|
drawText(transform, renderer, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutItem.LINES_PER_PAGE * page, FULL_BRIGHT_LIGHTMAP, text, colours);
|
||||||
renderer.endBatch();
|
renderer.endBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void render(PoseStack stack, int mouseX, int mouseY, float partialTicks) {
|
||||||
// We must take the background further back in order to not overlap with our printed pages.
|
// We must take the background further back in order to not overlap with our printed pages.
|
||||||
graphics.pose().pushPose();
|
stack.pushPose();
|
||||||
graphics.pose().translate(0, 0, -1);
|
stack.translate(0, 0, -1);
|
||||||
renderBackground(graphics);
|
renderBackground(stack);
|
||||||
graphics.pose().popPose();
|
stack.popPose();
|
||||||
|
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(stack, mouseX, mouseY, partialTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
|
protected void renderLabels(PoseStack transform, int mouseX, int mouseY) {
|
||||||
// Skip rendering labels.
|
// Skip rendering labels.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui;
|
package dan200.computercraft.client.gui;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
||||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||||
@@ -11,7 +13,6 @@ import dan200.computercraft.client.render.ComputerBorderRenderer;
|
|||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||||
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.player.Inventory;
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
@@ -43,22 +44,23 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
|
protected void renderBg(PoseStack transform, float partialTicks, int mouseX, int mouseY) {
|
||||||
var advanced = family == ComputerFamily.ADVANCED;
|
var advanced = family == ComputerFamily.ADVANCED;
|
||||||
var texture = advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL;
|
RenderSystem.setShaderTexture(0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL);
|
||||||
graphics.blit(texture, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0, 0, TEX_WIDTH, TEX_HEIGHT, FULL_TEX_SIZE, FULL_TEX_SIZE);
|
blit(transform, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0, 0, TEX_WIDTH, TEX_HEIGHT, FULL_TEX_SIZE, FULL_TEX_SIZE);
|
||||||
|
|
||||||
// Render selected slot
|
// Render selected slot
|
||||||
var slot = getMenu().getSelectedSlot();
|
var slot = getMenu().getSelectedSlot();
|
||||||
if (slot >= 0) {
|
if (slot >= 0) {
|
||||||
var slotX = slot % 4;
|
var slotX = slot % 4;
|
||||||
var slotY = slot / 4;
|
var slotY = slot / 4;
|
||||||
graphics.blit(texture,
|
blit(transform,
|
||||||
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, 0,
|
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, 0,
|
||||||
0, 217, 24, 24, FULL_TEX_SIZE, FULL_TEX_SIZE
|
0, 217, 24, 24, FULL_TEX_SIZE, FULL_TEX_SIZE
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ComputerSidebar.renderBackground(graphics, ComputerBorderRenderer.getTexture(family), leftPos, topPos + sidebarYOffset);
|
RenderSystem.setShaderTexture(0, advanced ? ComputerBorderRenderer.BACKGROUND_ADVANCED : ComputerBorderRenderer.BACKGROUND_NORMAL);
|
||||||
|
ComputerSidebar.renderBackground(transform, leftPos, topPos + sidebarYOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,13 +4,14 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui.widgets;
|
package dan200.computercraft.client.gui.widgets;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import dan200.computercraft.api.ComputerCraftAPI;
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
import dan200.computercraft.client.gui.widgets.DynamicImageButton.HintedMessage;
|
import dan200.computercraft.client.gui.widgets.DynamicImageButton.HintedMessage;
|
||||||
import dan200.computercraft.client.render.ComputerBorderRenderer;
|
import dan200.computercraft.client.render.ComputerBorderRenderer;
|
||||||
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;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.AbstractWidget;
|
import net.minecraft.client.gui.components.AbstractWidget;
|
||||||
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
@@ -67,19 +68,19 @@ public final class ComputerSidebar {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void renderBackground(GuiGraphics graphics, ResourceLocation texture, int x, int y) {
|
public static void renderBackground(PoseStack transform, int x, int y) {
|
||||||
graphics.blit(texture,
|
Screen.blit(transform,
|
||||||
x, y, 0, 102, AbstractComputerMenu.SIDEBAR_WIDTH, FULL_BORDER,
|
x, y, 0, 102, AbstractComputerMenu.SIDEBAR_WIDTH, FULL_BORDER,
|
||||||
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
|
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
|
||||||
);
|
);
|
||||||
|
|
||||||
graphics.blit(texture,
|
Screen.blit(transform,
|
||||||
x, y + FULL_BORDER, AbstractComputerMenu.SIDEBAR_WIDTH, HEIGHT - FULL_BORDER * 2,
|
x, y + FULL_BORDER, AbstractComputerMenu.SIDEBAR_WIDTH, HEIGHT - FULL_BORDER * 2,
|
||||||
0, 107, AbstractComputerMenu.SIDEBAR_WIDTH, 4,
|
0, 107, AbstractComputerMenu.SIDEBAR_WIDTH, 4,
|
||||||
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
|
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
|
||||||
);
|
);
|
||||||
|
|
||||||
graphics.blit(texture,
|
Screen.blit(transform,
|
||||||
x, y + HEIGHT - FULL_BORDER, 0, 111, AbstractComputerMenu.SIDEBAR_WIDTH, FULL_BORDER,
|
x, y + HEIGHT - FULL_BORDER, 0, 111, AbstractComputerMenu.SIDEBAR_WIDTH, FULL_BORDER,
|
||||||
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
|
ComputerBorderRenderer.TEX_SIZE, ComputerBorderRenderer.TEX_SIZE
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
package dan200.computercraft.client.gui.widgets;
|
package dan200.computercraft.client.gui.widgets;
|
||||||
|
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.Button;
|
import net.minecraft.client.gui.components.Button;
|
||||||
import net.minecraft.client.gui.components.Tooltip;
|
import net.minecraft.client.gui.components.Tooltip;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
@@ -57,14 +57,15 @@ public class DynamicImageButton extends Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void renderWidget(PoseStack stack, int mouseX, int mouseY, float partialTicks) {
|
||||||
RenderSystem.enableBlend();
|
RenderSystem.setShaderTexture(0, texture);
|
||||||
RenderSystem.enableDepthTest();
|
RenderSystem.disableDepthTest();
|
||||||
|
|
||||||
var yTex = yTexStart;
|
var yTex = yTexStart;
|
||||||
if (isHoveredOrFocused()) yTex += yDiffTex;
|
if (isHoveredOrFocused()) yTex += yDiffTex;
|
||||||
|
|
||||||
graphics.blit(texture, getX(), getY(), xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight);
|
blit(stack, getX(), getY(), xTexStart.getAsInt(), yTex, width, height, textureWidth, textureHeight);
|
||||||
|
RenderSystem.enableDepthTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,9 +74,9 @@ public class DynamicImageButton extends Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void render(PoseStack stack, int mouseX, int mouseY, float partialTicks) {
|
||||||
setTooltip(message.get().tooltip());
|
setTooltip(message.get().tooltip());
|
||||||
super.render(graphics, mouseX, mouseY, partialTicks);
|
super.render(stack, mouseX, mouseY, partialTicks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public record HintedMessage(Component message, Tooltip tooltip) {
|
public record HintedMessage(Component message, Tooltip tooltip) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client.gui.widgets;
|
package dan200.computercraft.client.gui.widgets;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
import com.mojang.blaze3d.vertex.Tesselator;
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
import dan200.computercraft.client.render.RenderTypes;
|
import dan200.computercraft.client.render.RenderTypes;
|
||||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||||
@@ -11,7 +12,6 @@ import dan200.computercraft.core.terminal.Terminal;
|
|||||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||||
import net.minecraft.SharedConstants;
|
import net.minecraft.SharedConstants;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.AbstractWidget;
|
import net.minecraft.client.gui.components.AbstractWidget;
|
||||||
import net.minecraft.client.gui.narration.NarratedElementType;
|
import net.minecraft.client.gui.narration.NarratedElementType;
|
||||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
||||||
@@ -274,11 +274,11 @@ public class TerminalWidget extends AbstractWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
|
public void renderWidget(PoseStack transform, int mouseX, int mouseY, float partialTicks) {
|
||||||
if (!visible) return;
|
if (!visible) return;
|
||||||
|
|
||||||
var bufferSource = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
|
var bufferSource = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder());
|
||||||
var emitter = FixedWidthFontRenderer.toVertexConsumer(graphics.pose(), bufferSource.getBuffer(RenderTypes.TERMINAL));
|
var emitter = FixedWidthFontRenderer.toVertexConsumer(transform, bufferSource.getBuffer(RenderTypes.TERMINAL));
|
||||||
|
|
||||||
FixedWidthFontRenderer.drawTerminal(
|
FixedWidthFontRenderer.drawTerminal(
|
||||||
emitter,
|
emitter,
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public abstract class AbstractClientNetworkContext implements ClientNetworkConte
|
|||||||
var player = Minecraft.getInstance().player;
|
var player = Minecraft.getInstance().player;
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
|
|
||||||
var te = player.level().getBlockEntity(pos);
|
var te = player.level.getBlockEntity(pos);
|
||||||
if (!(te instanceof MonitorBlockEntity monitor)) return;
|
if (!(te instanceof MonitorBlockEntity monitor)) return;
|
||||||
|
|
||||||
monitor.read(terminal);
|
monitor.read(terminal);
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import org.joml.Matrix4f;
|
|||||||
* {@linkplain PocketItemRenderer in-hand pocket computers}.
|
* {@linkplain PocketItemRenderer in-hand pocket computers}.
|
||||||
*/
|
*/
|
||||||
public class ComputerBorderRenderer {
|
public class ComputerBorderRenderer {
|
||||||
private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_normal.png");
|
public static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_normal.png");
|
||||||
private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_advanced.png");
|
public static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_advanced.png");
|
||||||
private static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_command.png");
|
public static final ResourceLocation BACKGROUND_COMMAND = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_command.png");
|
||||||
public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_colour.png");
|
public static final ResourceLocation BACKGROUND_COLOUR = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/corners_colour.png");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ package dan200.computercraft.client.render.monitor;
|
|||||||
import com.mojang.blaze3d.platform.GlStateManager;
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
import com.mojang.blaze3d.platform.MemoryTracker;
|
import com.mojang.blaze3d.platform.MemoryTracker;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.mojang.blaze3d.vertex.*;
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import com.mojang.blaze3d.vertex.Tesselator;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexBuffer;
|
||||||
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||||
import com.mojang.math.Axis;
|
import com.mojang.math.Axis;
|
||||||
import dan200.computercraft.client.FrameInfo;
|
import dan200.computercraft.client.FrameInfo;
|
||||||
import dan200.computercraft.client.integration.ShaderMod;
|
import dan200.computercraft.client.integration.ShaderMod;
|
||||||
@@ -167,7 +170,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
|||||||
tboVertex(buffer, matrix, -xMargin, pixelHeight + yMargin);
|
tboVertex(buffer, matrix, -xMargin, pixelHeight + yMargin);
|
||||||
tboVertex(buffer, matrix, pixelWidth + xMargin, -yMargin);
|
tboVertex(buffer, matrix, pixelWidth + xMargin, -yMargin);
|
||||||
tboVertex(buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin);
|
tboVertex(buffer, matrix, pixelWidth + xMargin, pixelHeight + yMargin);
|
||||||
RenderTypes.MONITOR_TBO.end(buffer, VertexSorting.DISTANCE_TO_ORIGIN);
|
RenderTypes.MONITOR_TBO.end(buffer, 0, 0, 0);
|
||||||
}
|
}
|
||||||
case VBO -> {
|
case VBO -> {
|
||||||
var backgroundBuffer = assertNonNull(renderState.backgroundBuffer);
|
var backgroundBuffer = assertNonNull(renderState.backgroundBuffer);
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ public class DirectVertexBuffer extends VertexBuffer {
|
|||||||
private int actualIndexCount;
|
private int actualIndexCount;
|
||||||
|
|
||||||
public DirectVertexBuffer() {
|
public DirectVertexBuffer() {
|
||||||
super(Usage.STATIC);
|
|
||||||
if (DirectBuffers.HAS_DSA) {
|
if (DirectBuffers.HAS_DSA) {
|
||||||
RenderSystem.glDeleteBuffers(vertexBufferId);
|
RenderSystem.glDeleteBuffers(vertexBufferId);
|
||||||
if (DirectBuffers.ON_LINUX) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer.
|
if (DirectBuffers.ON_LINUX) BufferUploader.reset(); // See comment on DirectBuffers.deleteBuffer.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import net.minecraft.world.level.storage.loot.entries.LootItem;
|
|||||||
import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer;
|
import net.minecraft.world.level.storage.loot.entries.LootPoolEntryContainer;
|
||||||
import net.minecraft.world.level.storage.loot.functions.CopyNameFunction;
|
import net.minecraft.world.level.storage.loot.functions.CopyNameFunction;
|
||||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
||||||
import net.minecraft.world.level.storage.loot.predicates.AnyOfCondition;
|
import net.minecraft.world.level.storage.loot.predicates.AlternativeLootItemCondition;
|
||||||
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition;
|
import net.minecraft.world.level.storage.loot.predicates.ExplosionCondition;
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition;
|
import net.minecraft.world.level.storage.loot.predicates.LootItemBlockStatePropertyCondition;
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
||||||
@@ -79,7 +79,7 @@ class LootTableProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void registerGeneric(BiConsumer<ResourceLocation, LootTable.Builder> add) {
|
private static void registerGeneric(BiConsumer<ResourceLocation, LootTable.Builder> add) {
|
||||||
add.accept(CommonHooks.TREASURE_DISK_LOOT, LootTable.lootTable());
|
add.accept(CommonHooks.LOOT_TREASURE_DISK, LootTable.lootTable());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void selfDrop(BiConsumer<ResourceLocation, LootTable.Builder> add, Supplier<? extends Block> wrapper) {
|
private static void selfDrop(BiConsumer<ResourceLocation, LootTable.Builder> add, Supplier<? extends Block> wrapper) {
|
||||||
@@ -98,7 +98,7 @@ class LootTableProvider {
|
|||||||
blockDrop(
|
blockDrop(
|
||||||
add, block,
|
add, block,
|
||||||
DynamicLoot.dynamicEntry(new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer")),
|
DynamicLoot.dynamicEntry(new ResourceLocation(ComputerCraftAPI.MOD_ID, "computer")),
|
||||||
AnyOfCondition.anyOf(
|
AlternativeLootItemCondition.alternative(
|
||||||
BlockNamedEntityLootCondition.BUILDER,
|
BlockNamedEntityLootCondition.BUILDER,
|
||||||
HasComputerIdLootCondition.BUILDER,
|
HasComputerIdLootCondition.BUILDER,
|
||||||
PlayerCreativeLootCondition.BUILDER.invert()
|
PlayerCreativeLootCondition.BUILDER.invert()
|
||||||
|
|||||||
@@ -88,8 +88,6 @@ class TagProvider {
|
|||||||
ModRegistry.Items.MONITOR_ADVANCED.get()
|
ModRegistry.Items.MONITOR_ADVANCED.get()
|
||||||
);
|
);
|
||||||
|
|
||||||
tags.tag(ItemTags.BOOKSHELF_BOOKS).add(ModRegistry.Items.PRINTED_BOOK.get());
|
|
||||||
|
|
||||||
tags.tag(ComputerCraftTags.Items.TURTLE_CAN_PLACE)
|
tags.tag(ComputerCraftTags.Items.TURTLE_CAN_PLACE)
|
||||||
.add(Items.GLASS_BOTTLE)
|
.add(Items.GLASS_BOTTLE)
|
||||||
.addTag(ItemTags.BOATS);
|
.addTag(ItemTags.BOATS);
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ import net.minecraft.world.level.storage.loot.entries.LootTableReference;
|
|||||||
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
|
import net.minecraft.world.level.storage.loot.providers.number.ConstantValue;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
@@ -73,9 +75,9 @@ public final class CommonHooks {
|
|||||||
MonitorWatcher.onWatch(chunk, player);
|
MonitorWatcher.onWatch(chunk, player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final ResourceLocation TREASURE_DISK_LOOT = new ResourceLocation(ComputerCraftAPI.MOD_ID, "treasure_disk");
|
public static final ResourceLocation LOOT_TREASURE_DISK = new ResourceLocation(ComputerCraftAPI.MOD_ID, "treasure_disk");
|
||||||
|
|
||||||
private static final Set<ResourceLocation> TREASURE_DISK_LOOT_TABLES = Set.of(
|
private static final Set<ResourceLocation> TABLES = new HashSet<>(Arrays.asList(
|
||||||
BuiltInLootTables.SIMPLE_DUNGEON,
|
BuiltInLootTables.SIMPLE_DUNGEON,
|
||||||
BuiltInLootTables.ABANDONED_MINESHAFT,
|
BuiltInLootTables.ABANDONED_MINESHAFT,
|
||||||
BuiltInLootTables.STRONGHOLD_CORRIDOR,
|
BuiltInLootTables.STRONGHOLD_CORRIDOR,
|
||||||
@@ -86,15 +88,14 @@ public final class CommonHooks {
|
|||||||
BuiltInLootTables.IGLOO_CHEST,
|
BuiltInLootTables.IGLOO_CHEST,
|
||||||
BuiltInLootTables.WOODLAND_MANSION,
|
BuiltInLootTables.WOODLAND_MANSION,
|
||||||
BuiltInLootTables.VILLAGE_CARTOGRAPHER
|
BuiltInLootTables.VILLAGE_CARTOGRAPHER
|
||||||
);
|
));
|
||||||
|
|
||||||
|
|
||||||
public static @Nullable LootPool.Builder getExtraLootPool(ResourceLocation lootTable) {
|
public static @Nullable LootPool.Builder getExtraLootPool(ResourceLocation lootTable) {
|
||||||
if (!lootTable.getNamespace().equals("minecraft") || !TREASURE_DISK_LOOT_TABLES.contains(lootTable)) {
|
if (!lootTable.getNamespace().equals("minecraft") || !TABLES.contains(lootTable)) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LootPool.lootPool()
|
return LootPool.lootPool()
|
||||||
.add(LootTableReference.lootTableReference(TREASURE_DISK_LOOT))
|
.add(LootTableReference.lootTableReference(LOOT_TREASURE_DISK))
|
||||||
.setRolls(ConstantValue.exactly(1));
|
.setRolls(ConstantValue.exactly(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
|||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.material.MapColor;
|
import net.minecraft.world.level.material.Material;
|
||||||
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
|
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
|
||||||
|
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
@@ -113,7 +113,7 @@ public final class ModRegistry {
|
|||||||
static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK);
|
static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK);
|
||||||
|
|
||||||
private static BlockBehaviour.Properties properties() {
|
private static BlockBehaviour.Properties properties() {
|
||||||
return BlockBehaviour.Properties.of().strength(2);
|
return BlockBehaviour.Properties.of(Material.STONE).strength(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockBehaviour.Properties computerProperties() {
|
private static BlockBehaviour.Properties computerProperties() {
|
||||||
@@ -123,17 +123,17 @@ public final class ModRegistry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static BlockBehaviour.Properties turtleProperties() {
|
private static BlockBehaviour.Properties turtleProperties() {
|
||||||
return BlockBehaviour.Properties.of().strength(2.5f);
|
return BlockBehaviour.Properties.of(Material.STONE).strength(2.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BlockBehaviour.Properties modemProperties() {
|
private static BlockBehaviour.Properties modemProperties() {
|
||||||
return BlockBehaviour.Properties.of().strength(1.5f);
|
return BlockBehaviour.Properties.of(Material.STONE).strength(1.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_NORMAL = REGISTRY.register("computer_normal",
|
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_NORMAL = REGISTRY.register("computer_normal",
|
||||||
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.STONE), ComputerFamily.NORMAL, BlockEntities.COMPUTER_NORMAL));
|
() -> new ComputerBlock<>(computerProperties(), ComputerFamily.NORMAL, BlockEntities.COMPUTER_NORMAL));
|
||||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = REGISTRY.register("computer_advanced",
|
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = REGISTRY.register("computer_advanced",
|
||||||
() -> new ComputerBlock<>(computerProperties().mapColor(MapColor.GOLD), ComputerFamily.ADVANCED, BlockEntities.COMPUTER_ADVANCED));
|
() -> new ComputerBlock<>(computerProperties(), ComputerFamily.ADVANCED, BlockEntities.COMPUTER_ADVANCED));
|
||||||
|
|
||||||
public static final RegistryEntry<ComputerBlock<CommandComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command", () -> new ComputerBlock<>(
|
public static final RegistryEntry<ComputerBlock<CommandComputerBlockEntity>> COMPUTER_COMMAND = REGISTRY.register("computer_command", () -> new ComputerBlock<>(
|
||||||
computerProperties().strength(-1, 6000000.0F),
|
computerProperties().strength(-1, 6000000.0F),
|
||||||
@@ -141,27 +141,27 @@ public final class ModRegistry {
|
|||||||
));
|
));
|
||||||
|
|
||||||
public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = REGISTRY.register("turtle_normal",
|
public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = REGISTRY.register("turtle_normal",
|
||||||
() -> new TurtleBlock(turtleProperties().mapColor(MapColor.STONE), ComputerFamily.NORMAL, BlockEntities.TURTLE_NORMAL));
|
() -> new TurtleBlock(turtleProperties(), ComputerFamily.NORMAL, BlockEntities.TURTLE_NORMAL));
|
||||||
public static final RegistryEntry<TurtleBlock> TURTLE_ADVANCED = REGISTRY.register("turtle_advanced",
|
public static final RegistryEntry<TurtleBlock> TURTLE_ADVANCED = REGISTRY.register("turtle_advanced",
|
||||||
() -> new TurtleBlock(turtleProperties().mapColor(MapColor.GOLD), ComputerFamily.ADVANCED, BlockEntities.TURTLE_ADVANCED));
|
() -> new TurtleBlock(turtleProperties(), ComputerFamily.ADVANCED, BlockEntities.TURTLE_ADVANCED));
|
||||||
|
|
||||||
public static final RegistryEntry<SpeakerBlock> SPEAKER = REGISTRY.register("speaker", () -> new SpeakerBlock(properties().mapColor(MapColor.STONE)));
|
public static final RegistryEntry<SpeakerBlock> SPEAKER = REGISTRY.register("speaker", () -> new SpeakerBlock(properties()));
|
||||||
public static final RegistryEntry<DiskDriveBlock> DISK_DRIVE = REGISTRY.register("disk_drive", () -> new DiskDriveBlock(properties().mapColor(MapColor.STONE)));
|
public static final RegistryEntry<DiskDriveBlock> DISK_DRIVE = REGISTRY.register("disk_drive", () -> new DiskDriveBlock(properties()));
|
||||||
public static final RegistryEntry<PrinterBlock> PRINTER = REGISTRY.register("printer", () -> new PrinterBlock(properties().mapColor(MapColor.STONE)));
|
public static final RegistryEntry<PrinterBlock> PRINTER = REGISTRY.register("printer", () -> new PrinterBlock(properties()));
|
||||||
|
|
||||||
public static final RegistryEntry<MonitorBlock> MONITOR_NORMAL = REGISTRY.register("monitor_normal",
|
public static final RegistryEntry<MonitorBlock> MONITOR_NORMAL = REGISTRY.register("monitor_normal",
|
||||||
() -> new MonitorBlock(properties().mapColor(MapColor.STONE), BlockEntities.MONITOR_NORMAL));
|
() -> new MonitorBlock(properties(), BlockEntities.MONITOR_NORMAL));
|
||||||
public static final RegistryEntry<MonitorBlock> MONITOR_ADVANCED = REGISTRY.register("monitor_advanced",
|
public static final RegistryEntry<MonitorBlock> MONITOR_ADVANCED = REGISTRY.register("monitor_advanced",
|
||||||
() -> new MonitorBlock(properties().mapColor(MapColor.GOLD), BlockEntities.MONITOR_ADVANCED));
|
() -> new MonitorBlock(properties(), BlockEntities.MONITOR_ADVANCED));
|
||||||
|
|
||||||
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_NORMAL = REGISTRY.register("wireless_modem_normal",
|
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_NORMAL = REGISTRY.register("wireless_modem_normal",
|
||||||
() -> new WirelessModemBlock(properties().mapColor(MapColor.STONE), BlockEntities.WIRELESS_MODEM_NORMAL));
|
() -> new WirelessModemBlock(properties(), BlockEntities.WIRELESS_MODEM_NORMAL));
|
||||||
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_ADVANCED = REGISTRY.register("wireless_modem_advanced",
|
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_ADVANCED = REGISTRY.register("wireless_modem_advanced",
|
||||||
() -> new WirelessModemBlock(properties().mapColor(MapColor.GOLD), BlockEntities.WIRELESS_MODEM_ADVANCED));
|
() -> new WirelessModemBlock(properties(), BlockEntities.WIRELESS_MODEM_ADVANCED));
|
||||||
|
|
||||||
public static final RegistryEntry<WiredModemFullBlock> WIRED_MODEM_FULL = REGISTRY.register("wired_modem_full",
|
public static final RegistryEntry<WiredModemFullBlock> WIRED_MODEM_FULL = REGISTRY.register("wired_modem_full",
|
||||||
() -> new WiredModemFullBlock(modemProperties().mapColor(MapColor.STONE)));
|
() -> new WiredModemFullBlock(modemProperties()));
|
||||||
public static final RegistryEntry<CableBlock> CABLE = REGISTRY.register("cable", () -> new CableBlock(modemProperties().mapColor(MapColor.STONE)));
|
public static final RegistryEntry<CableBlock> CABLE = REGISTRY.register("cable", () -> new CableBlock(modemProperties()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BlockEntities {
|
public static class BlockEntities {
|
||||||
@@ -366,11 +366,50 @@ public final class ModRegistry {
|
|||||||
public static final RegistryEntry<ImpostorShapelessRecipe.Serializer> IMPOSTOR_SHAPELESS = REGISTRY.register("impostor_shapeless", ImpostorShapelessRecipe.Serializer::new);
|
public static final RegistryEntry<ImpostorShapelessRecipe.Serializer> IMPOSTOR_SHAPELESS = REGISTRY.register("impostor_shapeless", ImpostorShapelessRecipe.Serializer::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class CreativeTabs {
|
/**
|
||||||
static final RegistrationHelper<CreativeModeTab> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.CREATIVE_MODE_TAB);
|
* Register any objects which don't have to be done on the main thread.
|
||||||
|
*/
|
||||||
|
public static void register() {
|
||||||
|
Blocks.REGISTRY.register();
|
||||||
|
BlockEntities.REGISTRY.register();
|
||||||
|
Items.REGISTRY.register();
|
||||||
|
TurtleSerialisers.REGISTRY.register();
|
||||||
|
PocketUpgradeSerialisers.REGISTRY.register();
|
||||||
|
Menus.REGISTRY.register();
|
||||||
|
ArgumentTypes.REGISTRY.register();
|
||||||
|
LootItemConditionTypes.REGISTRY.register();
|
||||||
|
RecipeSerializers.REGISTRY.register();
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
// Register bundled power providers
|
||||||
private static final RegistryEntry<CreativeModeTab> TAB = REGISTRY.register("tab", () -> PlatformHelper.get().newCreativeModeTab()
|
ComputerCraftAPI.registerBundledRedstoneProvider(new DefaultBundledRedstoneProvider());
|
||||||
|
ComputerCraftAPI.registerRefuelHandler(new FurnaceRefuelHandler());
|
||||||
|
ComputerCraftAPI.registerMediaProvider(stack -> {
|
||||||
|
var item = stack.getItem();
|
||||||
|
if (item instanceof IMedia media) return media;
|
||||||
|
if (item instanceof RecordItem) return RecordMedia.INSTANCE;
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
VanillaDetailRegistries.ITEM_STACK.addProvider(ItemDetails::fill);
|
||||||
|
VanillaDetailRegistries.BLOCK_IN_WORLD.addProvider(BlockDetails::fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register any objects which must be done on the main thread.
|
||||||
|
*/
|
||||||
|
public static void registerMainThread() {
|
||||||
|
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_NORMAL.get(), TurtleItem.CAULDRON_INTERACTION);
|
||||||
|
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_ADVANCED.get(), TurtleItem.CAULDRON_INTERACTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a {@link CreativeModeTab.Builder} to contain all of ComputerCraft's items.
|
||||||
|
*
|
||||||
|
* @param builder The builder to configure.
|
||||||
|
* @return The same building, for calling {@link CreativeModeTab.Builder#build()} on.
|
||||||
|
*/
|
||||||
|
public static CreativeModeTab.Builder registerCreativeTab(CreativeModeTab.Builder builder) {
|
||||||
|
return builder
|
||||||
.icon(() -> new ItemStack(Items.COMPUTER_NORMAL.get()))
|
.icon(() -> new ItemStack(Items.COMPUTER_NORMAL.get()))
|
||||||
.title(Component.translatable("itemGroup.computercraft"))
|
.title(Component.translatable("itemGroup.computercraft"))
|
||||||
.displayItems((context, out) -> {
|
.displayItems((context, out) -> {
|
||||||
@@ -402,45 +441,7 @@ public final class ModRegistry {
|
|||||||
for (var colour = 0; colour < 16; colour++) {
|
for (var colour = 0; colour < 16; colour++) {
|
||||||
out.accept(DiskItem.createFromIDAndColour(-1, null, Colour.VALUES[colour].getHex()));
|
out.accept(DiskItem.createFromIDAndColour(-1, null, Colour.VALUES[colour].getHex()));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register any objects which don't have to be done on the main thread.
|
|
||||||
*/
|
|
||||||
public static void register() {
|
|
||||||
Blocks.REGISTRY.register();
|
|
||||||
BlockEntities.REGISTRY.register();
|
|
||||||
Items.REGISTRY.register();
|
|
||||||
TurtleSerialisers.REGISTRY.register();
|
|
||||||
PocketUpgradeSerialisers.REGISTRY.register();
|
|
||||||
Menus.REGISTRY.register();
|
|
||||||
ArgumentTypes.REGISTRY.register();
|
|
||||||
LootItemConditionTypes.REGISTRY.register();
|
|
||||||
RecipeSerializers.REGISTRY.register();
|
|
||||||
CreativeTabs.REGISTRY.register();
|
|
||||||
|
|
||||||
// Register bundled power providers
|
|
||||||
ComputerCraftAPI.registerBundledRedstoneProvider(new DefaultBundledRedstoneProvider());
|
|
||||||
ComputerCraftAPI.registerRefuelHandler(new FurnaceRefuelHandler());
|
|
||||||
ComputerCraftAPI.registerMediaProvider(stack -> {
|
|
||||||
var item = stack.getItem();
|
|
||||||
if (item instanceof IMedia media) return media;
|
|
||||||
if (item instanceof RecordItem) return RecordMedia.INSTANCE;
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
VanillaDetailRegistries.ITEM_STACK.addProvider(ItemDetails::fill);
|
|
||||||
VanillaDetailRegistries.BLOCK_IN_WORLD.addProvider(BlockDetails::fill);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register any objects which must be done on the main thread.
|
|
||||||
*/
|
|
||||||
public static void registerMainThread() {
|
|
||||||
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_NORMAL.get(), TurtleItem.CAULDRON_INTERACTION);
|
|
||||||
CauldronInteraction.WATER.put(ModRegistry.Items.TURTLE_ADVANCED.get(), TurtleItem.CAULDRON_INTERACTION);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
|
private static void addTurtle(CreativeModeTab.Output out, TurtleItem turtle) {
|
||||||
|
|||||||
@@ -6,12 +6,9 @@ package dan200.computercraft.shared.command;
|
|||||||
|
|
||||||
import com.mojang.brigadier.CommandDispatcher;
|
import com.mojang.brigadier.CommandDispatcher;
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
import com.mojang.brigadier.suggestion.Suggestions;
|
|
||||||
import dan200.computercraft.core.computer.ComputerSide;
|
import dan200.computercraft.core.computer.ComputerSide;
|
||||||
import dan200.computercraft.core.metrics.Metrics;
|
import dan200.computercraft.core.metrics.Metrics;
|
||||||
import dan200.computercraft.shared.command.arguments.ComputersArgumentType;
|
|
||||||
import dan200.computercraft.shared.command.text.TableBuilder;
|
import dan200.computercraft.shared.command.text.TableBuilder;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
@@ -127,9 +124,7 @@ public final class CommandComputerCraft {
|
|||||||
if (computer.isOn()) shutdown++;
|
if (computer.isOn()) shutdown++;
|
||||||
computer.shutdown();
|
computer.shutdown();
|
||||||
}
|
}
|
||||||
|
context.getSource().sendSuccess(Component.translatable("commands.computercraft.shutdown.done", shutdown, computers.size()), false);
|
||||||
var didShutdown = shutdown;
|
|
||||||
context.getSource().sendSuccess(() -> Component.translatable("commands.computercraft.shutdown.done", didShutdown, computers.size()), false);
|
|
||||||
return shutdown;
|
return shutdown;
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -143,9 +138,7 @@ public final class CommandComputerCraft {
|
|||||||
if (!computer.isOn()) on++;
|
if (!computer.isOn()) on++;
|
||||||
computer.turnOn();
|
computer.turnOn();
|
||||||
}
|
}
|
||||||
|
context.getSource().sendSuccess(Component.translatable("commands.computercraft.turn_on.done", on, computers.size()), false);
|
||||||
var didOn = on;
|
|
||||||
context.getSource().sendSuccess(() -> Component.translatable("commands.computercraft.turn_on.done", didOn, computers.size()), false);
|
|
||||||
return on;
|
return on;
|
||||||
}))
|
}))
|
||||||
|
|
||||||
@@ -176,10 +169,7 @@ public final class CommandComputerCraft {
|
|||||||
|
|
||||||
.then(command("queue")
|
.then(command("queue")
|
||||||
.requires(UserLevel.ANYONE)
|
.requires(UserLevel.ANYONE)
|
||||||
.arg(
|
.arg("computer", manyComputers())
|
||||||
RequiredArgumentBuilder.<CommandSourceStack, ComputersArgumentType.ComputersSupplier>argument("computer", manyComputers())
|
|
||||||
.suggests((context, builder) -> Suggestions.empty())
|
|
||||||
)
|
|
||||||
.argManyValue("args", StringArgumentType.string(), Collections.emptyList())
|
.argManyValue("args", StringArgumentType.string(), Collections.emptyList())
|
||||||
.executes((ctx, args) -> {
|
.executes((ctx, args) -> {
|
||||||
var computers = getComputersArgument(ctx, "computer");
|
var computers = getComputersArgument(ctx, "computer");
|
||||||
@@ -223,7 +213,7 @@ public final class CommandComputerCraft {
|
|||||||
getMetricsInstance(context.getSource()).start();
|
getMetricsInstance(context.getSource()).start();
|
||||||
|
|
||||||
var stopCommand = "/computercraft track stop";
|
var stopCommand = "/computercraft track stop";
|
||||||
context.getSource().sendSuccess(() -> Component.translatable(
|
context.getSource().sendSuccess(Component.translatable(
|
||||||
"commands.computercraft.track.start.stop",
|
"commands.computercraft.track.start.stop",
|
||||||
link(text(stopCommand), stopCommand, Component.translatable("commands.computercraft.track.stop.action"))
|
link(text(stopCommand), stopCommand, Component.translatable("commands.computercraft.track.stop.action"))
|
||||||
), false);
|
), false);
|
||||||
|
|||||||
@@ -49,29 +49,6 @@ public enum UserLevel implements Predicate<CommandSourceStack> {
|
|||||||
return source.hasPermission(toLevel());
|
return source.hasPermission(toLevel());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Take the union of two {@link UserLevel}s.
|
|
||||||
* <p>
|
|
||||||
* This satisfies the property that for all sources {@code s}, {@code a.test(s) || b.test(s) == (a ∪ b).test(s)}.
|
|
||||||
*
|
|
||||||
* @param left The first user level to take the union of.
|
|
||||||
* @param right The second user level to take the union of.
|
|
||||||
* @return The union of two levels.
|
|
||||||
*/
|
|
||||||
public static UserLevel union(UserLevel left, UserLevel right) {
|
|
||||||
if (left == right) return left;
|
|
||||||
|
|
||||||
// x ∪ ANYONE = ANYONE
|
|
||||||
if (left == ANYONE || right == ANYONE) return ANYONE;
|
|
||||||
|
|
||||||
// x ∪ OWNER = OWNER
|
|
||||||
if (left == OWNER) return right;
|
|
||||||
if (right == OWNER) return left;
|
|
||||||
|
|
||||||
// At this point, we have x != y and x, y ∈ { OP, OWNER_OP }.
|
|
||||||
return OWNER_OP;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isOwner(CommandSourceStack source) {
|
private static boolean isOwner(CommandSourceStack source) {
|
||||||
var server = source.getServer();
|
var server = source.getServer();
|
||||||
var sender = source.getEntity();
|
var sender = source.getEntity();
|
||||||
|
|||||||
@@ -48,13 +48,9 @@ public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandBuilder<S> arg(ArgumentBuilder<S, ?> arg) {
|
|
||||||
args.add(arg);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CommandBuilder<S> arg(String name, ArgumentType<?> type) {
|
public CommandBuilder<S> arg(String name, ArgumentType<?> type) {
|
||||||
return arg(RequiredArgumentBuilder.argument(name, type));
|
args.add(RequiredArgumentBuilder.argument(name, type));
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue(String name, ArgumentType<T> type, List<T> empty) {
|
public <T> CommandNodeBuilder<S, ArgCommand<S, List<T>>> argManyValue(String name, ArgumentType<T> type, List<T> empty) {
|
||||||
@@ -78,7 +74,7 @@ public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>> {
|
|||||||
|
|
||||||
return command -> {
|
return command -> {
|
||||||
// The node for no arguments
|
// The node for no arguments
|
||||||
var tail = setupTail(ctx -> command.run(ctx, empty.get()));
|
var tail = tail(ctx -> command.run(ctx, empty.get()));
|
||||||
|
|
||||||
// The node for one or more arguments
|
// The node for one or more arguments
|
||||||
ArgumentBuilder<S, ?> moreArg = RequiredArgumentBuilder
|
ArgumentBuilder<S, ?> moreArg = RequiredArgumentBuilder
|
||||||
@@ -87,7 +83,7 @@ public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>> {
|
|||||||
|
|
||||||
// Chain all of them together!
|
// Chain all of them together!
|
||||||
tail.then(moreArg);
|
tail.then(moreArg);
|
||||||
return buildTail(tail);
|
return link(tail);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,16 +94,20 @@ public class CommandBuilder<S> implements CommandNodeBuilder<S, Command<S>> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommandNode<S> executes(Command<S> command) {
|
public CommandNode<S> executes(Command<S> command) {
|
||||||
return buildTail(setupTail(command));
|
if (args.isEmpty()) throw new IllegalStateException("Cannot have empty arg chain builder");
|
||||||
|
|
||||||
|
return link(tail(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArgumentBuilder<S, ?> setupTail(Command<S> command) {
|
private ArgumentBuilder<S, ?> tail(Command<S> command) {
|
||||||
return args.get(args.size() - 1).executes(command);
|
var defaultTail = args.get(args.size() - 1);
|
||||||
|
defaultTail.executes(command);
|
||||||
|
if (requires != null) defaultTail.requires(requires);
|
||||||
|
return defaultTail;
|
||||||
}
|
}
|
||||||
|
|
||||||
private CommandNode<S> buildTail(ArgumentBuilder<S, ?> tail) {
|
private CommandNode<S> link(ArgumentBuilder<S, ?> tail) {
|
||||||
for (var i = args.size() - 2; i >= 0; i--) tail = args.get(i).then(tail);
|
for (var i = args.size() - 2; i >= 0; i--) tail = args.get(i).then(tail);
|
||||||
if (requires != null) tail.requires(requires);
|
|
||||||
return tail.build();
|
return tail.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import com.mojang.brigadier.tree.CommandNode;
|
import com.mojang.brigadier.tree.CommandNode;
|
||||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||||
import dan200.computercraft.shared.command.UserLevel;
|
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.network.chat.ClickEvent;
|
import net.minecraft.network.chat.ClickEvent;
|
||||||
@@ -19,8 +18,6 @@ import net.minecraft.network.chat.Component;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||||
import static dan200.computercraft.shared.command.text.ChatHelpers.coloured;
|
import static dan200.computercraft.shared.command.text.ChatHelpers.coloured;
|
||||||
@@ -40,29 +37,6 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
|
|||||||
return new HelpingArgumentBuilder(literal);
|
return new HelpingArgumentBuilder(literal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public LiteralArgumentBuilder<CommandSourceStack> requires(Predicate<CommandSourceStack> requirement) {
|
|
||||||
throw new IllegalStateException("Cannot use requires on a HelpingArgumentBuilder");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Predicate<CommandSourceStack> getRequirement() {
|
|
||||||
// The requirement of this node is the union of all child's requirements.
|
|
||||||
var requirements = Stream.concat(
|
|
||||||
children.stream().map(ArgumentBuilder::getRequirement),
|
|
||||||
getArguments().stream().map(CommandNode::getRequirement)
|
|
||||||
).toList();
|
|
||||||
|
|
||||||
// If all requirements are a UserLevel, take the union of those instead.
|
|
||||||
var userLevel = UserLevel.OWNER;
|
|
||||||
for (var requirement : requirements) {
|
|
||||||
if (!(requirement instanceof UserLevel level)) return x -> requirements.stream().anyMatch(y -> y.test(x));
|
|
||||||
userLevel = UserLevel.union(userLevel, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
return userLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LiteralArgumentBuilder<CommandSourceStack> executes(final Command<CommandSourceStack> command) {
|
public LiteralArgumentBuilder<CommandSourceStack> executes(final Command<CommandSourceStack> command) {
|
||||||
throw new IllegalStateException("Cannot use executes on a HelpingArgumentBuilder");
|
throw new IllegalStateException("Cannot use executes on a HelpingArgumentBuilder");
|
||||||
@@ -106,7 +80,9 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
|
|||||||
helpCommand.node = node;
|
helpCommand.node = node;
|
||||||
|
|
||||||
// Set up a /... help command
|
// Set up a /... help command
|
||||||
var helpNode = LiteralArgumentBuilder.<CommandSourceStack>literal("help").executes(helpCommand);
|
var helpNode = LiteralArgumentBuilder.<CommandSourceStack>literal("help")
|
||||||
|
.requires(x -> getArguments().stream().anyMatch(y -> y.getRequirement().test(x)))
|
||||||
|
.executes(helpCommand);
|
||||||
|
|
||||||
// Add all normal command children to this and the help node
|
// Add all normal command children to this and the help node
|
||||||
for (var child : getArguments()) {
|
for (var child : getArguments()) {
|
||||||
@@ -153,14 +129,14 @@ public final class HelpingArgumentBuilder extends LiteralArgumentBuilder<Command
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int run(CommandContext<CommandSourceStack> context) {
|
public int run(CommandContext<CommandSourceStack> context) {
|
||||||
context.getSource().sendSuccess(() -> getHelp(context, assertNonNull(node), id, command), false);
|
context.getSource().sendSuccess(getHelp(context, assertNonNull(node), id, command), false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Command<CommandSourceStack> helpForChild(CommandNode<CommandSourceStack> node, String id, String command) {
|
private static Command<CommandSourceStack> helpForChild(CommandNode<CommandSourceStack> node, String id, String command) {
|
||||||
return context -> {
|
return context -> {
|
||||||
context.getSource().sendSuccess(() -> getHelp(context, node, id + "." + node.getName().replace('-', '_'), command + " " + node.getName()), false);
|
context.getSource().sendSuccess(getHelp(context, node, id + "." + node.getName().replace('-', '_'), command + " " + node.getName()), false);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,6 @@ public class ServerTableFormatter implements TableFormatter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeLine(String label, Component component) {
|
public void writeLine(String label, Component component) {
|
||||||
source.sendSuccess(() -> component, false);
|
source.sendSuccess(component, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
|||||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.storage.loot.LootParams;
|
import net.minecraft.world.level.storage.loot.LootContext;
|
||||||
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@@ -138,12 +138,13 @@ public abstract class AbstractComputerBlock<T extends AbstractComputerBlockEntit
|
|||||||
|
|
||||||
var tile = world.getBlockEntity(pos);
|
var tile = world.getBlockEntity(pos);
|
||||||
if (tile instanceof AbstractComputerBlockEntity computer) {
|
if (tile instanceof AbstractComputerBlockEntity computer) {
|
||||||
var context = new LootParams.Builder(serverWorld)
|
var context = new LootContext.Builder(serverWorld)
|
||||||
|
.withRandom(world.random)
|
||||||
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos))
|
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(pos))
|
||||||
.withParameter(LootContextParams.TOOL, player.getMainHandItem())
|
.withParameter(LootContextParams.TOOL, player.getMainHandItem())
|
||||||
.withParameter(LootContextParams.THIS_ENTITY, player)
|
.withParameter(LootContextParams.THIS_ENTITY, player)
|
||||||
.withParameter(LootContextParams.BLOCK_ENTITY, tile)
|
.withParameter(LootContextParams.BLOCK_ENTITY, tile)
|
||||||
.withDynamicDrop(DROP, out -> out.accept(getItem(computer)));
|
.withDynamicDrop(DROP, (ctx, out) -> out.accept(getItem(computer)));
|
||||||
for (var item : state.getDrops(context)) {
|
for (var item : state.getDrops(context)) {
|
||||||
popResource(world, pos, item);
|
popResource(world, pos, item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import it.unimi.dsi.fastutil.ints.IntSet;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
public class ModemState {
|
public final class ModemState {
|
||||||
private final @Nullable Runnable onChanged;
|
private final @Nullable Runnable onChanged;
|
||||||
private final AtomicBoolean changed = new AtomicBoolean(true);
|
private final AtomicBoolean changed = new AtomicBoolean(true);
|
||||||
|
|
||||||
@@ -69,4 +69,30 @@ public class ModemState {
|
|||||||
setOpen(false);
|
setOpen(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy this modem state, returning a new instance. The new instance will have the same set of open channels but no
|
||||||
|
* on-change listener.
|
||||||
|
*
|
||||||
|
* @return The new modem state.
|
||||||
|
*/
|
||||||
|
public ModemState copy() {
|
||||||
|
return copy(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy this modem state, returning a new instance. The new instance will have the same set of open channels and a
|
||||||
|
* different on-change listener.
|
||||||
|
*
|
||||||
|
* @param onChanged The on-change listener.
|
||||||
|
* @return The new modem state.
|
||||||
|
*/
|
||||||
|
public ModemState copy(@Nullable Runnable onChanged) {
|
||||||
|
synchronized (channels) {
|
||||||
|
var clone = onChanged == null ? new ModemState() : new ModemState(onChanged);
|
||||||
|
clone.channels.addAll(channels);
|
||||||
|
clone.open = open;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import net.minecraft.world.phys.Vec3;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class WirelessModemBlockEntity extends BlockEntity {
|
public final class WirelessModemBlockEntity extends BlockEntity {
|
||||||
private static class Peripheral extends WirelessModemPeripheral {
|
private static class Peripheral extends WirelessModemPeripheral {
|
||||||
private final WirelessModemBlockEntity entity;
|
private final WirelessModemBlockEntity entity;
|
||||||
|
|
||||||
@@ -96,6 +96,10 @@ public class WirelessModemBlockEntity extends BlockEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ModemState getModemState() {
|
||||||
|
return modem.getModemState();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
public IPeripheral getPeripheral(@Nullable Direction direction) {
|
||||||
return direction == null || getDirection() == direction ? modem : null;
|
return direction == null || getDirection() == direction ? modem : null;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public record SpeakerPosition(@Nullable Level level, Vec3 position, @Nullable En
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static SpeakerPosition of(Entity entity) {
|
public static SpeakerPosition of(Entity entity) {
|
||||||
return new SpeakerPosition(entity.level(), entity.getEyePosition(1), entity);
|
return new SpeakerPosition(entity.level, entity.getEyePosition(1), entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean withinDistance(SpeakerPosition other, double distanceSq) {
|
public boolean withinDistance(SpeakerPosition other, double distanceSq) {
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
import net.minecraft.world.inventory.CraftingContainer;
|
import net.minecraft.world.inventory.CraftingContainer;
|
||||||
import net.minecraft.world.inventory.MenuType;
|
import net.minecraft.world.inventory.MenuType;
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
|
||||||
import net.minecraft.world.item.DyeColor;
|
import net.minecraft.world.item.DyeColor;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@@ -280,13 +279,6 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper
|
|||||||
*/
|
*/
|
||||||
int getBurnTime(ItemStack stack);
|
int getBurnTime(ItemStack stack);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a builder for a new creative tab.
|
|
||||||
*
|
|
||||||
* @return The creative tab builder.
|
|
||||||
*/
|
|
||||||
CreativeModeTab.Builder newCreativeModeTab();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the "container" item to be returned after crafting. For instance, crafting with a lava bucket should return
|
* Get the "container" item to be returned after crafting. For instance, crafting with a lava bucket should return
|
||||||
* an empty bucket.
|
* an empty bucket.
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
|||||||
super.tickServer();
|
super.tickServer();
|
||||||
|
|
||||||
// Find any players which have gone missing and remove them from the tracking list.
|
// Find any players which have gone missing and remove them from the tracking list.
|
||||||
tracking.removeIf(player -> !player.isAlive() || player.level() != getLevel());
|
tracking.removeIf(player -> !player.isAlive() || player.level != getLevel());
|
||||||
|
|
||||||
// And now find any new players, add them to the tracking list, and broadcast state where appropriate.
|
// And now find any new players, add them to the tracking list, and broadcast state where appropriate.
|
||||||
var sendState = hasOutputChanged() || lightChanged;
|
var sendState = hasOutputChanged() || lightChanged;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public class PocketComputerMenuProvider implements MenuProvider {
|
|||||||
isTypingOnly ? ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get() : ModRegistry.Menus.POCKET_COMPUTER.get(), id, inventory,
|
isTypingOnly ? ModRegistry.Menus.POCKET_COMPUTER_NO_TERM.get() : ModRegistry.Menus.POCKET_COMPUTER.get(), id, inventory,
|
||||||
p -> {
|
p -> {
|
||||||
var stack = p.getItemInHand(hand);
|
var stack = p.getItemInHand(hand);
|
||||||
return stack.getItem() == item && PocketComputerItem.getServerComputer(assertNonNull(entity.level().getServer()), stack) == computer;
|
return stack.getItem() == item && PocketComputerItem.getServerComputer(assertNonNull(entity.level.getServer()), stack) == computer;
|
||||||
},
|
},
|
||||||
computer, item.getFamily()
|
computer, item.getFamily()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -127,11 +127,10 @@ public class PocketComputerItem extends Item implements IComputerItem, IMedia, I
|
|||||||
|
|
||||||
@ForgeOverride
|
@ForgeOverride
|
||||||
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
|
public boolean onEntityItemUpdate(ItemStack stack, ItemEntity entity) {
|
||||||
var level = entity.level();
|
if (entity.level.isClientSide || entity.level.getServer() == null) return false;
|
||||||
if (level.isClientSide || level.getServer() == null) return false;
|
|
||||||
|
|
||||||
var computer = getServerComputer(level.getServer(), stack);
|
var computer = getServerComputer(entity.level.getServer(), stack);
|
||||||
if (computer != null && tick(stack, entity.level(), entity, computer)) entity.setItem(stack.copy());
|
if (computer != null && tick(stack, entity.level, entity, computer)) entity.setItem(stack.copy());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral {
|
|||||||
public void update() {
|
public void update() {
|
||||||
var entity = access.getEntity();
|
var entity = access.getEntity();
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
level = entity.level();
|
level = entity.level;
|
||||||
position = entity.position();
|
position = entity.position();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -555,7 +555,7 @@ public class TurtleAPI implements ILuaAPI {
|
|||||||
* @cc.usage Refuel a turtle from the currently selected slot.
|
* @cc.usage Refuel a turtle from the currently selected slot.
|
||||||
* <pre>{@code
|
* <pre>{@code
|
||||||
* local level = turtle.getFuelLevel()
|
* local level = turtle.getFuelLevel()
|
||||||
* if level == "unlimited" then error("Turtle does not need fuel", 0) end
|
* if new_level == "unlimited" then error("Turtle does not need fuel", 0) end
|
||||||
*
|
*
|
||||||
* local ok, err = turtle.refuel()
|
* local ok, err = turtle.refuel()
|
||||||
* if ok then
|
* if ok then
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import dan200.computercraft.api.turtle.TurtleCommand;
|
|||||||
import dan200.computercraft.api.turtle.TurtleSide;
|
import dan200.computercraft.api.turtle.TurtleSide;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||||
import dan200.computercraft.core.computer.ComputerSide;
|
import dan200.computercraft.core.computer.ComputerSide;
|
||||||
|
import dan200.computercraft.core.util.Colour;
|
||||||
import dan200.computercraft.impl.TurtleUpgrades;
|
import dan200.computercraft.impl.TurtleUpgrades;
|
||||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||||
@@ -34,6 +35,7 @@ import net.minecraft.tags.FluidTags;
|
|||||||
import net.minecraft.world.Container;
|
import net.minecraft.world.Container;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.MoverType;
|
import net.minecraft.world.entity.MoverType;
|
||||||
|
import net.minecraft.world.item.DyeColor;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.material.PushReaction;
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
@@ -317,6 +319,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public Vec3 getVisualPosition(float f) {
|
public Vec3 getVisualPosition(float f) {
|
||||||
var offset = getRenderOffset(f);
|
var offset = getRenderOffset(f);
|
||||||
var pos = owner.getBlockPos();
|
var pos = owner.getBlockPos();
|
||||||
@@ -327,6 +330,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public float getVisualYaw(float f) {
|
public float getVisualYaw(float f) {
|
||||||
var yaw = getDirection().toYRot();
|
var yaw = getDirection().toYRot();
|
||||||
switch (animation) {
|
switch (animation) {
|
||||||
@@ -461,6 +465,23 @@ public class TurtleBrain implements TurtleAccessInternal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable DyeColor getDyeColour() {
|
||||||
|
if (colourHex == -1) return null;
|
||||||
|
var colour = Colour.fromHex(colourHex);
|
||||||
|
return colour == null ? null : DyeColor.byId(15 - colour.ordinal());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDyeColour(@Nullable DyeColor dyeColour) {
|
||||||
|
var newColour = -1;
|
||||||
|
if (dyeColour != null) {
|
||||||
|
newColour = Colour.values()[15 - dyeColour.getId()].getHex();
|
||||||
|
}
|
||||||
|
if (colourHex != newColour) {
|
||||||
|
colourHex = newColour;
|
||||||
|
BlockEntityHelpers.updateBlock(owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setColour(int colour) {
|
public void setColour(int colour) {
|
||||||
if (colour >= 0 && colour <= 0xFFFFFF) {
|
if (colour >= 0 && colour <= 0xFFFFFF) {
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public class TurtleMoveCommand implements TurtleCommand {
|
|||||||
var state = oldWorld.getBlockState(newPosition);
|
var state = oldWorld.getBlockState(newPosition);
|
||||||
if (!oldWorld.isEmptyBlock(newPosition) &&
|
if (!oldWorld.isEmptyBlock(newPosition) &&
|
||||||
!WorldUtil.isLiquidBlock(oldWorld, newPosition) &&
|
!WorldUtil.isLiquidBlock(oldWorld, newPosition) &&
|
||||||
!state.canBeReplaced()) {
|
!state.getMaterial().isReplaceable()) {
|
||||||
return TurtleCommandResult.failure("Movement obstructed");
|
return TurtleCommandResult.failure("Movement obstructed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ import net.minecraft.world.level.Level;
|
|||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
import net.minecraft.world.level.block.entity.SignBlockEntity;
|
||||||
import net.minecraft.world.level.block.entity.SignText;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.EntityHitResult;
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
@@ -75,7 +74,19 @@ public class TurtlePlaceCommand implements TurtleCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean deploy(
|
public static boolean deployCopiedItem(
|
||||||
|
ItemStack stack, ITurtleAccess turtle, Direction direction, @Nullable Object[] extraArguments, @Nullable ErrorMessage outErrorMessage
|
||||||
|
) {
|
||||||
|
// Create a fake player, and orient it appropriately
|
||||||
|
var playerPosition = turtle.getPosition().relative(direction);
|
||||||
|
var turtlePlayer = TurtlePlayer.getWithPosition(turtle, playerPosition, direction);
|
||||||
|
turtlePlayer.loadInventory(stack);
|
||||||
|
var result = deploy(stack, turtle, turtlePlayer, direction, extraArguments, outErrorMessage);
|
||||||
|
turtlePlayer.player().getInventory().clearContent();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean deploy(
|
||||||
ItemStack stack, ITurtleAccess turtle, TurtlePlayer turtlePlayer, Direction direction,
|
ItemStack stack, ITurtleAccess turtle, TurtlePlayer turtlePlayer, Direction direction,
|
||||||
@Nullable Object[] extraArguments, @Nullable ErrorMessage outErrorMessage
|
@Nullable Object[] extraArguments, @Nullable ErrorMessage outErrorMessage
|
||||||
) {
|
) {
|
||||||
@@ -199,7 +210,7 @@ public class TurtlePlaceCommand implements TurtleCommand {
|
|||||||
);
|
);
|
||||||
if (result != InteractionResult.PASS) return result;
|
if (result != InteractionResult.PASS) return result;
|
||||||
|
|
||||||
var level = turtlePlayer.player().level();
|
var level = turtlePlayer.player().level;
|
||||||
|
|
||||||
// We special case some items which we allow to place "normally". Yes, this is very ugly.
|
// We special case some items which we allow to place "normally". Yes, this is very ugly.
|
||||||
var item = stack.getItem();
|
var item = stack.getItem();
|
||||||
@@ -214,18 +225,18 @@ public class TurtlePlaceCommand implements TurtleCommand {
|
|||||||
var signTile = (SignBlockEntity) tile;
|
var signTile = (SignBlockEntity) tile;
|
||||||
var split = Splitter.on('\n').splitToList(message);
|
var split = Splitter.on('\n').splitToList(message);
|
||||||
var firstLine = split.size() <= 2 ? 1 : 0;
|
var firstLine = split.size() <= 2 ? 1 : 0;
|
||||||
|
|
||||||
var signText = new SignText();
|
|
||||||
for (var i = 0; i < 4; i++) {
|
for (var i = 0; i < 4; i++) {
|
||||||
if (i >= firstLine && i < firstLine + split.size()) {
|
if (i >= firstLine && i < firstLine + split.size()) {
|
||||||
var line = split.get(i - firstLine);
|
var line = split.get(i - firstLine);
|
||||||
signText.setMessage(i, line.length() > 15
|
signTile.setMessage(i, line.length() > 15
|
||||||
? Component.literal(line.substring(0, 15))
|
? Component.literal(line.substring(0, 15))
|
||||||
: Component.literal(line)
|
: Component.literal(line)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
signTile.setMessage(i, Component.literal(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
signTile.setText(signText, true);
|
signTile.setChanged();
|
||||||
world.sendBlockUpdated(tile.getBlockPos(), tile.getBlockState(), tile.getBlockState(), Block.UPDATE_ALL);
|
world.sendBlockUpdated(tile.getBlockPos(), tile.getBlockState(), tile.getBlockState(), Block.UPDATE_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class UpgradeContainer implements Container {
|
|||||||
|
|
||||||
private ItemStack setUpgradeStack(int slot, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
private ItemStack setUpgradeStack(int slot, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||||
var stack = upgrade == null ? ItemStack.EMPTY : upgrade.getUpgradeItem();
|
var stack = upgrade == null ? ItemStack.EMPTY : upgrade.getUpgradeItem();
|
||||||
lastUpgrade.set(slot, UpgradeData.copyOf(upgrade));
|
lastUpgrade.set(slot, upgrade);
|
||||||
lastStack.set(slot, stack);
|
lastStack.set(slot, stack);
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
|||||||
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
|
import dan200.computercraft.shared.turtle.core.TurtlePlayer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.entity.player.StackedContents;
|
|
||||||
import net.minecraft.world.inventory.CraftingContainer;
|
import net.minecraft.world.inventory.CraftingContainer;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.crafting.Recipe;
|
import net.minecraft.world.item.crafting.Recipe;
|
||||||
@@ -18,22 +17,20 @@ import net.minecraft.world.item.crafting.RecipeType;
|
|||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.AbstractList;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class TurtleInventoryCrafting implements CraftingContainer {
|
public class TurtleInventoryCrafting extends CraftingContainer {
|
||||||
public static final int WIDTH = 3;
|
|
||||||
public static final int HEIGHT = 3;
|
|
||||||
public static final int SIZE = WIDTH * HEIGHT;
|
|
||||||
|
|
||||||
private final ITurtleAccess turtle;
|
private final ITurtleAccess turtle;
|
||||||
private int xStart = 0;
|
private int xStart = 0;
|
||||||
private int yStart = 0;
|
private int yStart = 0;
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
public TurtleInventoryCrafting(ITurtleAccess turtle) {
|
public TurtleInventoryCrafting(ITurtleAccess turtle) {
|
||||||
|
// Passing null in here is evil, but we don't have a container present. We override most methods in order to
|
||||||
|
// avoid throwing any NPEs.
|
||||||
|
super(null, 0, 0);
|
||||||
this.turtle = turtle;
|
this.turtle = turtle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,7 +96,7 @@ public class TurtleInventoryCrafting implements CraftingContainer {
|
|||||||
// afterwards).
|
// afterwards).
|
||||||
if (existing.isEmpty()) {
|
if (existing.isEmpty()) {
|
||||||
setItem(slot, remainder);
|
setItem(slot, remainder);
|
||||||
} else if (ItemStack.isSameItemSameTags(existing, remainder)) {
|
} else if (ItemStack.isSame(existing, remainder) && ItemStack.tagMatches(existing, remainder)) {
|
||||||
remainder.grow(existing.getCount());
|
remainder.grow(existing.getCount());
|
||||||
setItem(slot, remainder);
|
setItem(slot, remainder);
|
||||||
} else {
|
} else {
|
||||||
@@ -113,12 +110,12 @@ public class TurtleInventoryCrafting implements CraftingContainer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWidth() {
|
public int getWidth() {
|
||||||
return WIDTH;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight() {
|
public int getHeight() {
|
||||||
return HEIGHT;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int modifyIndex(int index) {
|
private int modifyIndex(int index) {
|
||||||
@@ -129,37 +126,35 @@ public class TurtleInventoryCrafting implements CraftingContainer {
|
|||||||
: -1;
|
: -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// IInventory implementation
|
||||||
public boolean isEmpty() {
|
|
||||||
for (int i = 0; i < SIZE; i++) {
|
|
||||||
if (!getItem(i).isEmpty()) return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getContainerSize() {
|
public int getContainerSize() {
|
||||||
return SIZE;
|
return getWidth() * getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getItem(int i) {
|
public ItemStack getItem(int i) {
|
||||||
return turtle.getInventory().getItem(modifyIndex(i));
|
i = modifyIndex(i);
|
||||||
|
return turtle.getInventory().getItem(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack removeItemNoUpdate(int i) {
|
public ItemStack removeItemNoUpdate(int i) {
|
||||||
return turtle.getInventory().removeItemNoUpdate(modifyIndex(i));
|
i = modifyIndex(i);
|
||||||
|
return turtle.getInventory().removeItemNoUpdate(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack removeItem(int i, int size) {
|
public ItemStack removeItem(int i, int size) {
|
||||||
return turtle.getInventory().removeItem(modifyIndex(i), size);
|
i = modifyIndex(i);
|
||||||
|
return turtle.getInventory().removeItem(i, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setItem(int i, ItemStack stack) {
|
public void setItem(int i, ItemStack stack) {
|
||||||
turtle.getInventory().setItem(modifyIndex(i), stack);
|
i = modifyIndex(i);
|
||||||
|
turtle.getInventory().setItem(i, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -179,34 +174,15 @@ public class TurtleInventoryCrafting implements CraftingContainer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canPlaceItem(int i, ItemStack stack) {
|
public boolean canPlaceItem(int i, ItemStack stack) {
|
||||||
return turtle.getInventory().canPlaceItem(modifyIndex(i), stack);
|
i = modifyIndex(i);
|
||||||
|
return turtle.getInventory().canPlaceItem(i, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearContent() {
|
public void clearContent() {
|
||||||
for (var i = 0; i < SIZE; i++) {
|
for (var i = 0; i < getContainerSize(); i++) {
|
||||||
var j = modifyIndex(i);
|
var j = modifyIndex(i);
|
||||||
turtle.getInventory().setItem(j, ItemStack.EMPTY);
|
turtle.getInventory().setItem(j, ItemStack.EMPTY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fillStackedContents(StackedContents contents) {
|
|
||||||
for (int i = 0; i < SIZE; i++) contents.accountSimpleStack(getItem(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<ItemStack> getItems() {
|
|
||||||
return new AbstractList<>() {
|
|
||||||
@Override
|
|
||||||
public ItemStack get(int index) {
|
|
||||||
return getItem(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return SIZE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,19 +17,14 @@ import net.minecraft.core.Direction;
|
|||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.tags.TagKey;
|
import net.minecraft.tags.TagKey;
|
||||||
import net.minecraft.world.InteractionHand;
|
|
||||||
import net.minecraft.world.InteractionResult;
|
import net.minecraft.world.InteractionResult;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.MobType;
|
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
@@ -38,127 +33,61 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||||||
import net.minecraft.world.phys.EntityHitResult;
|
import net.minecraft.world.phys.EntityHitResult;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import static net.minecraft.nbt.Tag.TAG_COMPOUND;
|
import static net.minecraft.nbt.Tag.TAG_COMPOUND;
|
||||||
import static net.minecraft.nbt.Tag.TAG_LIST;
|
import static net.minecraft.nbt.Tag.TAG_LIST;
|
||||||
|
|
||||||
public class TurtleTool extends AbstractTurtleUpgrade {
|
public class TurtleTool extends AbstractTurtleUpgrade {
|
||||||
private static final TurtleCommandResult UNBREAKABLE = TurtleCommandResult.failure("Cannot break unbreakable block");
|
protected static final TurtleCommandResult UNBREAKABLE = TurtleCommandResult.failure("Cannot break unbreakable block");
|
||||||
private static final TurtleCommandResult INEFFECTIVE = TurtleCommandResult.failure("Cannot break block with this tool");
|
protected static final TurtleCommandResult INEFFECTIVE = TurtleCommandResult.failure("Cannot break block with this tool");
|
||||||
|
|
||||||
private static final String TAG_ITEM_TAG = "Tag";
|
|
||||||
|
|
||||||
final ItemStack item;
|
final ItemStack item;
|
||||||
final float damageMulitiplier;
|
final float damageMulitiplier;
|
||||||
final boolean allowEnchantments;
|
@Nullable
|
||||||
final TurtleToolDurability consumeDurability;
|
final TagKey<Block> breakable;
|
||||||
final @Nullable TagKey<Block> breakable;
|
|
||||||
|
|
||||||
public TurtleTool(
|
public TurtleTool(ResourceLocation id, String adjective, Item craftItem, ItemStack toolItem, float damageMulitiplier, @Nullable TagKey<Block> breakable) {
|
||||||
ResourceLocation id, String adjective, Item craftItem, ItemStack toolItem, float damageMulitiplier,
|
|
||||||
boolean allowEnchantments, TurtleToolDurability consumeDurability, @Nullable TagKey<Block> breakable
|
|
||||||
) {
|
|
||||||
super(id, TurtleUpgradeType.TOOL, adjective, new ItemStack(craftItem));
|
super(id, TurtleUpgradeType.TOOL, adjective, new ItemStack(craftItem));
|
||||||
item = toolItem;
|
item = toolItem;
|
||||||
this.damageMulitiplier = damageMulitiplier;
|
this.damageMulitiplier = damageMulitiplier;
|
||||||
this.allowEnchantments = allowEnchantments;
|
|
||||||
this.consumeDurability = consumeDurability;
|
|
||||||
this.breakable = breakable;
|
this.breakable = breakable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isItemSuitable(ItemStack stack) {
|
public boolean isItemSuitable(ItemStack stack) {
|
||||||
if (consumeDurability == TurtleToolDurability.NEVER && stack.isDamaged()) return false;
|
var tag = stack.getTag();
|
||||||
if (!allowEnchantments && isEnchanted(stack)) return false;
|
if (tag == null || tag.isEmpty()) return true;
|
||||||
|
|
||||||
|
// Check we've not got anything vaguely interesting on the item. We allow other mods to add their
|
||||||
|
// own NBT, with the understanding such details will be lost to the mist of time.
|
||||||
|
if (stack.isDamaged() || stack.isEnchanted()) return false;
|
||||||
|
if (tag.contains("AttributeModifiers", TAG_LIST) && !tag.getList("AttributeModifiers", TAG_COMPOUND).isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isEnchanted(ItemStack stack) {
|
|
||||||
return !stack.isEmpty() && isEnchanted(stack.getTag());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isEnchanted(@Nullable CompoundTag tag) {
|
|
||||||
if (tag == null || tag.isEmpty()) return false;
|
|
||||||
return (tag.contains(ItemStack.TAG_ENCH, TAG_LIST) && !tag.getList(ItemStack.TAG_ENCH, TAG_COMPOUND).isEmpty())
|
|
||||||
|| (tag.contains("AttributeModifiers", TAG_LIST) && !tag.getList("AttributeModifiers", TAG_COMPOUND).isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getUpgradeData(ItemStack stack) {
|
public CompoundTag getUpgradeData(ItemStack stack) {
|
||||||
var upgradeData = super.getUpgradeData(stack);
|
// Just use the current item's tag.
|
||||||
|
|
||||||
// Store the item's current tag.
|
|
||||||
var itemTag = stack.getTag();
|
var itemTag = stack.getTag();
|
||||||
if (itemTag != null) upgradeData.put(TAG_ITEM_TAG, itemTag);
|
return itemTag == null ? new CompoundTag() : itemTag;
|
||||||
|
|
||||||
return upgradeData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getUpgradeItem(CompoundTag upgradeData) {
|
public ItemStack getUpgradeItem(CompoundTag upgradeData) {
|
||||||
// Copy upgrade data back to the item.
|
// Copy upgrade data back to the item.
|
||||||
var item = super.getUpgradeItem(upgradeData).copy();
|
var item = super.getUpgradeItem(upgradeData);
|
||||||
item.setTag(upgradeData.contains(TAG_ITEM_TAG, TAG_COMPOUND) ? upgradeData.getCompound(TAG_ITEM_TAG).copy() : null);
|
if (!upgradeData.isEmpty()) item.setTag(upgradeData);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ItemStack getToolStack(ITurtleAccess turtle, TurtleSide side) {
|
|
||||||
return getUpgradeItem(turtle.getUpgradeNBTData(side));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setToolStack(ITurtleAccess turtle, TurtleSide side, ItemStack stack) {
|
|
||||||
var upgradeData = turtle.getUpgradeNBTData(side);
|
|
||||||
|
|
||||||
var useDurability = switch (consumeDurability) {
|
|
||||||
case NEVER -> false;
|
|
||||||
case WHEN_ENCHANTED ->
|
|
||||||
upgradeData.contains(TAG_ITEM_TAG, TAG_COMPOUND) && isEnchanted(upgradeData.getCompound(TAG_ITEM_TAG));
|
|
||||||
case ALWAYS -> true;
|
|
||||||
};
|
|
||||||
if (!useDurability) return;
|
|
||||||
|
|
||||||
// If the tool has broken, remove the upgrade!
|
|
||||||
if (stack.isEmpty()) {
|
|
||||||
turtle.setUpgradeWithData(side, null);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the tool has changed, no clue what's going on.
|
|
||||||
if (stack.getItem() != item.getItem()) return;
|
|
||||||
|
|
||||||
var itemTag = stack.getTag();
|
|
||||||
|
|
||||||
// Early return if the item hasn't changed to avoid redundant syncs with the client.
|
|
||||||
if (Objects.equals(itemTag, upgradeData.get(TAG_ITEM_TAG))) return;
|
|
||||||
|
|
||||||
if (itemTag == null) {
|
|
||||||
upgradeData.remove(TAG_ITEM_TAG);
|
|
||||||
} else {
|
|
||||||
upgradeData.put(TAG_ITEM_TAG, itemTag);
|
|
||||||
}
|
|
||||||
|
|
||||||
turtle.updateUpgradeNBTData(side);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T withEquippedItem(ITurtleAccess turtle, TurtleSide side, Direction direction, Function<TurtlePlayer, T> action) {
|
|
||||||
var turtlePlayer = TurtlePlayer.getWithPosition(turtle, turtle.getPosition(), direction);
|
|
||||||
turtlePlayer.loadInventory(getToolStack(turtle, side));
|
|
||||||
|
|
||||||
var result = action.apply(turtlePlayer);
|
|
||||||
|
|
||||||
setToolStack(turtle, side, turtlePlayer.player().getItemInHand(InteractionHand.MAIN_HAND));
|
|
||||||
turtlePlayer.player().getInventory().clearContent();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TurtleCommandResult useTool(ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, Direction direction) {
|
public TurtleCommandResult useTool(ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, Direction direction) {
|
||||||
return switch (verb) {
|
return switch (verb) {
|
||||||
case ATTACK -> attack(turtle, side, direction);
|
case ATTACK -> attack(turtle, direction);
|
||||||
case DIG -> dig(turtle, side, direction);
|
case DIG -> dig(turtle, direction);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,14 +102,16 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attack an entity.
|
* Attack an entity. This is a <em>very</em> cut down version of {@link Player#attack(Entity)}, which doesn't handle
|
||||||
|
* enchantments, knockback, etc... Unfortunately we can't call attack directly as damage calculations are rather
|
||||||
|
* different (and we don't want to play sounds/particles).
|
||||||
*
|
*
|
||||||
* @param turtle The current turtle.
|
* @param turtle The current turtle.
|
||||||
* @param side The side the tool is on.
|
|
||||||
* @param direction The direction we're attacking in.
|
* @param direction The direction we're attacking in.
|
||||||
* @return Whether an attack occurred.
|
* @return Whether an attack occurred.
|
||||||
|
* @see Player#attack(Entity)
|
||||||
*/
|
*/
|
||||||
private TurtleCommandResult attack(ITurtleAccess turtle, TurtleSide side, Direction direction) {
|
private TurtleCommandResult attack(ITurtleAccess turtle, Direction direction) {
|
||||||
// Create a fake player, and orient it appropriately
|
// Create a fake player, and orient it appropriately
|
||||||
var world = turtle.getLevel();
|
var world = turtle.getLevel();
|
||||||
var position = turtle.getPosition();
|
var position = turtle.getPosition();
|
||||||
@@ -192,11 +123,10 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
|||||||
var turtlePos = player.position();
|
var turtlePos = player.position();
|
||||||
var rayDir = player.getViewVector(1.0f);
|
var rayDir = player.getViewVector(1.0f);
|
||||||
var hit = WorldUtil.clip(world, turtlePos, rayDir, 1.5, null);
|
var hit = WorldUtil.clip(world, turtlePos, rayDir, 1.5, null);
|
||||||
var attacked = false;
|
|
||||||
if (hit instanceof EntityHitResult entityHit) {
|
if (hit instanceof EntityHitResult entityHit) {
|
||||||
// Load up the turtle's inventory
|
// Load up the turtle's inventory
|
||||||
var stack = getToolStack(turtle, side);
|
var stackCopy = item.copy();
|
||||||
turtlePlayer.loadInventory(stack);
|
turtlePlayer.loadInventory(stackCopy);
|
||||||
|
|
||||||
var hitEntity = entityHit.getEntity();
|
var hitEntity = entityHit.getEntity();
|
||||||
|
|
||||||
@@ -204,120 +134,62 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
|||||||
DropConsumer.set(hitEntity, TurtleUtil.dropConsumer(turtle));
|
DropConsumer.set(hitEntity, TurtleUtil.dropConsumer(turtle));
|
||||||
|
|
||||||
// Attack the entity
|
// Attack the entity
|
||||||
|
var attacked = false;
|
||||||
var result = PlatformHelper.get().canAttackEntity(player, hitEntity);
|
var result = PlatformHelper.get().canAttackEntity(player, hitEntity);
|
||||||
if (result.consumesAction()) {
|
if (result.consumesAction()) {
|
||||||
attacked = true;
|
attacked = true;
|
||||||
} else if (result == InteractionResult.PASS && hitEntity.isAttackable() && !hitEntity.skipAttackInteraction(player)) {
|
} else if (result == InteractionResult.PASS && hitEntity.isAttackable() && !hitEntity.skipAttackInteraction(player)) {
|
||||||
attacked = attack(player, direction, hitEntity);
|
var damage = (float) player.getAttributeValue(Attributes.ATTACK_DAMAGE) * damageMulitiplier;
|
||||||
|
if (damage > 0.0f) {
|
||||||
|
var source = player.damageSources().playerAttack(player);
|
||||||
|
if (hitEntity instanceof ArmorStand) {
|
||||||
|
// Special case for armor stands: attack twice to guarantee destroy
|
||||||
|
hitEntity.hurt(source, damage);
|
||||||
|
if (hitEntity.isAlive()) hitEntity.hurt(source, damage);
|
||||||
|
attacked = true;
|
||||||
|
} else {
|
||||||
|
if (hitEntity.hurt(source, damage)) attacked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop claiming drops
|
// Stop claiming drops
|
||||||
TurtleUtil.stopConsuming(turtle);
|
TurtleUtil.stopConsuming(turtle);
|
||||||
|
|
||||||
// Put everything we collected into the turtles inventory.
|
// Put everything we collected into the turtles inventory, then return
|
||||||
setToolStack(turtle, side, player.getItemInHand(InteractionHand.MAIN_HAND));
|
|
||||||
player.getInventory().clearContent();
|
player.getInventory().clearContent();
|
||||||
|
if (attacked) return TurtleCommandResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
return attacked ? TurtleCommandResult.success() : TurtleCommandResult.failure("Nothing to attack here");
|
return TurtleCommandResult.failure("Nothing to attack here");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private TurtleCommandResult dig(ITurtleAccess turtle, Direction direction) {
|
||||||
* Attack an entity. This is a copy of {@link Player#attack(Entity)}, with some unwanted features removed (sweeping
|
if (PlatformHelper.get().hasToolUsage(item) && TurtlePlaceCommand.deployCopiedItem(item.copy(), turtle, direction, null, null)) {
|
||||||
* edge). This is a little limited.
|
return TurtleCommandResult.success();
|
||||||
* <p>
|
|
||||||
* Ideally we'd use attack directly (if other mods mixin to that method, we won't support their features).
|
|
||||||
* Unfortunately,that doesn't give us any feedback to whether the attack occurred or not (and we don't want to play
|
|
||||||
* sounds/particles).
|
|
||||||
*
|
|
||||||
* @param player The fake player doing the attacking.
|
|
||||||
* @param direction The direction the turtle is attacking.
|
|
||||||
* @param entity The entity to attack.
|
|
||||||
* @return Whether we attacked or not.
|
|
||||||
* @see Player#attack(Entity)
|
|
||||||
*/
|
|
||||||
private boolean attack(ServerPlayer player, Direction direction, Entity entity) {
|
|
||||||
var baseDamage = (float) player.getAttributeValue(Attributes.ATTACK_DAMAGE) * damageMulitiplier;
|
|
||||||
var bonusDamage = EnchantmentHelper.getDamageBonus(
|
|
||||||
player.getItemInHand(InteractionHand.MAIN_HAND), entity instanceof LivingEntity target ? target.getMobType() : MobType.UNDEFINED
|
|
||||||
);
|
|
||||||
var damage = baseDamage + bonusDamage;
|
|
||||||
if (damage <= 0) return false;
|
|
||||||
|
|
||||||
var knockBack = EnchantmentHelper.getKnockbackBonus(player);
|
|
||||||
|
|
||||||
// We follow the logic in Player.attack of setting the entity on fire before attacking, so it's burning when it
|
|
||||||
// (possibly) dies.
|
|
||||||
var fireAspect = EnchantmentHelper.getFireAspect(player);
|
|
||||||
var onFire = false;
|
|
||||||
if (entity instanceof LivingEntity target && fireAspect > 0 && !target.isOnFire()) {
|
|
||||||
onFire = true;
|
|
||||||
target.setSecondsOnFire(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var source = player.damageSources().playerAttack(player);
|
|
||||||
if (!entity.hurt(source, damage)) {
|
|
||||||
// If we failed to damage the entity, undo us setting the entity on fire.
|
|
||||||
if (onFire) entity.clearFire();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for armor stands: attack twice to guarantee destroy
|
|
||||||
if (entity.isAlive() && entity instanceof ArmorStand) entity.hurt(source, damage);
|
|
||||||
|
|
||||||
// Apply knockback
|
|
||||||
if (knockBack > 0) {
|
|
||||||
if (entity instanceof LivingEntity target) {
|
|
||||||
target.knockback(knockBack * 0.5, -direction.getStepX(), -direction.getStepZ());
|
|
||||||
} else {
|
|
||||||
entity.push(direction.getStepX() * knockBack * 0.5, 0.1, direction.getStepZ() * knockBack * 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply remaining enchantments
|
|
||||||
if (entity instanceof LivingEntity target) EnchantmentHelper.doPostHurtEffects(target, player);
|
|
||||||
EnchantmentHelper.doPostDamageEffects(player, entity);
|
|
||||||
|
|
||||||
// Damage the original item stack.
|
|
||||||
if (entity instanceof LivingEntity target) {
|
|
||||||
player.getItemInHand(InteractionHand.MAIN_HAND).hurtEnemy(target, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply fire aspect
|
|
||||||
if (entity instanceof LivingEntity target && fireAspect > 0 && !target.isOnFire()) {
|
|
||||||
target.setSecondsOnFire(4 * fireAspect);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TurtleCommandResult dig(ITurtleAccess turtle, TurtleSide side, Direction direction) {
|
|
||||||
var level = (ServerLevel) turtle.getLevel();
|
var level = (ServerLevel) turtle.getLevel();
|
||||||
|
var turtlePosition = turtle.getPosition();
|
||||||
|
|
||||||
var blockPosition = turtle.getPosition().relative(direction);
|
var blockPosition = turtlePosition.relative(direction);
|
||||||
if (level.isEmptyBlock(blockPosition) || WorldUtil.isLiquidBlock(level, blockPosition)) {
|
if (level.isEmptyBlock(blockPosition) || WorldUtil.isLiquidBlock(level, blockPosition)) {
|
||||||
return TurtleCommandResult.failure("Nothing to dig here");
|
return TurtleCommandResult.failure("Nothing to dig here");
|
||||||
}
|
}
|
||||||
|
|
||||||
return withEquippedItem(turtle, side, direction, turtlePlayer -> {
|
var turtlePlayer = TurtlePlayer.getWithPosition(turtle, turtlePosition, direction);
|
||||||
var stack = turtlePlayer.player().getItemInHand(InteractionHand.MAIN_HAND);
|
turtlePlayer.loadInventory(item.copy());
|
||||||
|
|
||||||
// Right-click the block when using a shovel/hoe.
|
// Check if we can break the block
|
||||||
if (PlatformHelper.get().hasToolUsage(item) && TurtlePlaceCommand.deploy(stack, turtle, turtlePlayer, direction, null, null)) {
|
var breakable = checkBlockBreakable(level, blockPosition, turtlePlayer);
|
||||||
return TurtleCommandResult.success();
|
if (!breakable.isSuccess()) return breakable;
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we can break the block
|
DropConsumer.set(level, blockPosition, TurtleUtil.dropConsumer(turtle));
|
||||||
var breakable = checkBlockBreakable(level, blockPosition, turtlePlayer);
|
var broken = !turtlePlayer.isBlockProtected(level, blockPosition) && turtlePlayer.player().gameMode.destroyBlock(blockPosition);
|
||||||
if (!breakable.isSuccess()) return breakable;
|
TurtleUtil.stopConsuming(turtle);
|
||||||
|
|
||||||
// And break it!
|
// Check spawn protection
|
||||||
DropConsumer.set(level, blockPosition, TurtleUtil.dropConsumer(turtle));
|
return broken ? TurtleCommandResult.success() : TurtleCommandResult.failure("Cannot break protected block");
|
||||||
var broken = !turtlePlayer.isBlockProtected(level, blockPosition) && turtlePlayer.player().gameMode.destroyBlock(blockPosition);
|
|
||||||
TurtleUtil.stopConsuming(turtle);
|
|
||||||
|
|
||||||
return broken ? TurtleCommandResult.success() : TurtleCommandResult.failure("Cannot break protected block");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isTriviallyBreakable(BlockGetter reader, BlockPos pos, BlockState state) {
|
private static boolean isTriviallyBreakable(BlockGetter reader, BlockPos pos, BlockState state) {
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
package dan200.computercraft.shared.turtle.upgrades;
|
package dan200.computercraft.shared.turtle.upgrades;
|
||||||
|
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import dan200.computercraft.api.turtle.TurtleToolDurability;
|
|
||||||
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
import dan200.computercraft.api.turtle.TurtleUpgradeSerialiser;
|
||||||
import dan200.computercraft.api.upgrades.UpgradeBase;
|
import dan200.computercraft.api.upgrades.UpgradeBase;
|
||||||
import dan200.computercraft.shared.platform.RegistryWrappers;
|
import dan200.computercraft.shared.platform.RegistryWrappers;
|
||||||
@@ -29,8 +28,6 @@ public final class TurtleToolSerialiser implements TurtleUpgradeSerialiser<Turtl
|
|||||||
var toolItem = GsonHelper.getAsItem(object, "item");
|
var toolItem = GsonHelper.getAsItem(object, "item");
|
||||||
var craftingItem = GsonHelper.getAsItem(object, "craftingItem", toolItem);
|
var craftingItem = GsonHelper.getAsItem(object, "craftingItem", toolItem);
|
||||||
var damageMultiplier = GsonHelper.getAsFloat(object, "damageMultiplier", 3.0f);
|
var damageMultiplier = GsonHelper.getAsFloat(object, "damageMultiplier", 3.0f);
|
||||||
var allowEnchantments = GsonHelper.getAsBoolean(object, "allowEnchantments", false);
|
|
||||||
var consumeDurability = TurtleToolDurability.CODEC.byName(GsonHelper.getAsString(object, "consumeDurability", null), TurtleToolDurability.NEVER);
|
|
||||||
|
|
||||||
TagKey<Block> breakable = null;
|
TagKey<Block> breakable = null;
|
||||||
if (object.has("breakable")) {
|
if (object.has("breakable")) {
|
||||||
@@ -38,7 +35,7 @@ public final class TurtleToolSerialiser implements TurtleUpgradeSerialiser<Turtl
|
|||||||
breakable = TagKey.create(Registries.BLOCK, tag);
|
breakable = TagKey.create(Registries.BLOCK, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TurtleTool(id, adjective, craftingItem, new ItemStack(toolItem), damageMultiplier, allowEnchantments, consumeDurability, breakable);
|
return new TurtleTool(id, adjective, craftingItem, new ItemStack(toolItem), damageMultiplier, breakable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -49,11 +46,9 @@ public final class TurtleToolSerialiser implements TurtleUpgradeSerialiser<Turtl
|
|||||||
// damageMultiplier and breakable aren't used by the client, but we need to construct the upgrade exactly
|
// damageMultiplier and breakable aren't used by the client, but we need to construct the upgrade exactly
|
||||||
// as otherwise syncing on an SP world will overwrite the (shared) upgrade registry with an invalid upgrade!
|
// as otherwise syncing on an SP world will overwrite the (shared) upgrade registry with an invalid upgrade!
|
||||||
var damageMultiplier = buffer.readFloat();
|
var damageMultiplier = buffer.readFloat();
|
||||||
var allowsEnchantments = buffer.readBoolean();
|
|
||||||
var consumesDurability = buffer.readEnum(TurtleToolDurability.class);
|
|
||||||
|
|
||||||
var breakable = buffer.readBoolean() ? TagKey.create(Registries.BLOCK, buffer.readResourceLocation()) : null;
|
var breakable = buffer.readBoolean() ? TagKey.create(Registries.BLOCK, buffer.readResourceLocation()) : null;
|
||||||
return new TurtleTool(id, adjective, craftingItem, toolItem, damageMultiplier, allowsEnchantments, consumesDurability, breakable);
|
return new TurtleTool(id, adjective, craftingItem, toolItem, damageMultiplier, breakable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -62,8 +57,6 @@ public final class TurtleToolSerialiser implements TurtleUpgradeSerialiser<Turtl
|
|||||||
RegistryWrappers.writeId(buffer, RegistryWrappers.ITEMS, upgrade.getCraftingItem().getItem());
|
RegistryWrappers.writeId(buffer, RegistryWrappers.ITEMS, upgrade.getCraftingItem().getItem());
|
||||||
buffer.writeItem(upgrade.item);
|
buffer.writeItem(upgrade.item);
|
||||||
buffer.writeFloat(upgrade.damageMulitiplier);
|
buffer.writeFloat(upgrade.damageMulitiplier);
|
||||||
buffer.writeBoolean(upgrade.allowEnchantments);
|
|
||||||
buffer.writeEnum(upgrade.consumeDurability);
|
|
||||||
buffer.writeBoolean(upgrade.breakable != null);
|
buffer.writeBoolean(upgrade.breakable != null);
|
||||||
if (upgrade.breakable != null) buffer.writeResourceLocation(upgrade.breakable.location());
|
if (upgrade.breakable != null) buffer.writeResourceLocation(upgrade.breakable.location());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public final class DropConsumer {
|
|||||||
dropConsumer = consumer;
|
dropConsumer = consumer;
|
||||||
remainingDrops = new ArrayList<>();
|
remainingDrops = new ArrayList<>();
|
||||||
dropEntity = entity;
|
dropEntity = entity;
|
||||||
dropWorld = entity.level();
|
dropWorld = entity.level;
|
||||||
dropBounds = new AABB(entity.blockPosition()).inflate(2, 2, 2);
|
dropBounds = new AABB(entity.blockPosition()).inflate(2, 2, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ public final class DropConsumer {
|
|||||||
|
|
||||||
public static boolean onEntitySpawn(Entity entity) {
|
public static boolean onEntitySpawn(Entity entity) {
|
||||||
// Capture any nearby item spawns
|
// Capture any nearby item spawns
|
||||||
if (dropWorld == entity.level() && entity instanceof ItemEntity
|
if (dropWorld == entity.getLevel() && entity instanceof ItemEntity
|
||||||
&& assertNonNull(dropBounds).contains(entity.position())) {
|
&& assertNonNull(dropBounds).contains(entity.position())) {
|
||||||
handleDrops(((ItemEntity) entity).getItem());
|
handleDrops(((ItemEntity) entity).getItem());
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -90,6 +90,6 @@ public final class InventoryUtil {
|
|||||||
if (stack1.getItem() != stack2.getItem()) return false;
|
if (stack1.getItem() != stack2.getItem()) return false;
|
||||||
if (stack1.getDamageValue() != stack2.getDamageValue()) return false;
|
if (stack1.getDamageValue() != stack2.getDamageValue()) return false;
|
||||||
if (stack1.getCount() > stack1.getMaxStackSize()) return false;
|
if (stack1.getCount() > stack1.getMaxStackSize()) return false;
|
||||||
return ItemStack.isSameItemSameTags(stack1, stack2);
|
return ItemStack.tagMatches(stack1, stack2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public final class WorldUtil {
|
|||||||
|
|
||||||
public static boolean isLiquidBlock(Level world, BlockPos pos) {
|
public static boolean isLiquidBlock(Level world, BlockPos pos) {
|
||||||
if (!world.isInWorldBounds(pos)) return false;
|
if (!world.isInWorldBounds(pos)) return false;
|
||||||
return world.getBlockState(pos).liquid();
|
return world.getBlockState(pos).getMaterial().isLiquid();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isVecInside(VoxelShape shape, Vec3 vec) {
|
public static boolean isVecInside(VoxelShape shape, Vec3 vec) {
|
||||||
|
|||||||
@@ -217,15 +217,5 @@
|
|||||||
"gui.computercraft.config.http.enabled.tooltip": "Active l'API \"http\" sur les ordinateurs. Cela désactive également les programmes \"pastebin\" et \"wget\",\nsur lesquels de nombreux utilisateurs comptent. Il est recommandé de laisser cette option activée et\nd'utiliser l'option de configuration \"rules\" pour imposer un contrôle plus précis.",
|
"gui.computercraft.config.http.enabled.tooltip": "Active l'API \"http\" sur les ordinateurs. Cela désactive également les programmes \"pastebin\" et \"wget\",\nsur lesquels de nombreux utilisateurs comptent. Il est recommandé de laisser cette option activée et\nd'utiliser l'option de configuration \"rules\" pour imposer un contrôle plus précis.",
|
||||||
"gui.computercraft.config.peripheral.modem_range.tooltip": "La portée des modems sans fil à basse altitude par temps dégagé, en mètres.\nPlage : 0 ~ 100000",
|
"gui.computercraft.config.peripheral.modem_range.tooltip": "La portée des modems sans fil à basse altitude par temps dégagé, en mètres.\nPlage : 0 ~ 100000",
|
||||||
"gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "La limite de la quantité de données du moniteur pouvant être envoyées *par tick*. Note :\n - La bande passante est mesurée avant la compression, donc les données envoyées\n au client sont plus petites.\n - Cela ignore le nombre de joueurs auxquels un paquet est envoyé. La mise à jour d'un\n moniteur pour un joueur consomme la même limite de bande passante que l'envoi à 20.\n - Un moniteur de taille normale envoie ~25ko de données. Ainsi, la valeur par défaut (1Mo) permet \n à environ 40 moniteurs d'être mis à jour en un seul tick.\nMettre à 0 pour désactiver.\nPlage : > 0",
|
"gui.computercraft.config.peripheral.monitor_bandwidth.tooltip": "La limite de la quantité de données du moniteur pouvant être envoyées *par tick*. Note :\n - La bande passante est mesurée avant la compression, donc les données envoyées\n au client sont plus petites.\n - Cela ignore le nombre de joueurs auxquels un paquet est envoyé. La mise à jour d'un\n moniteur pour un joueur consomme la même limite de bande passante que l'envoi à 20.\n - Un moniteur de taille normale envoie ~25ko de données. Ainsi, la valeur par défaut (1Mo) permet \n à environ 40 moniteurs d'être mis à jour en un seul tick.\nMettre à 0 pour désactiver.\nPlage : > 0",
|
||||||
"gui.computercraft.config.http.rules.tooltip": "Une liste de règles qui contrôlent le comportement de l'API \"http\" pour des domaines\nou des IP spécifiques. Chaque règle est un élément avec un 'hôte' à comparer et une série\nde propriétés. Les règles sont évaluées dans l'ordre, ce qui signifie que les règles antérieures\nremplacent les suivantes.\nL'hôte peut être un nom de domaine (\"pastebin.com\"), un astérisque (\"*.pastebin.com\") ou\nune notation CIDR (\"127.0.0.0/8\").\nS'il n'y a pas de règles, le domaine est bloqué.",
|
"gui.computercraft.config.http.rules.tooltip": "Une liste de règles qui contrôlent le comportement de l'API \"http\" pour des domaines\nou des IP spécifiques. Chaque règle est un élément avec un 'hôte' à comparer et une série\nde propriétés. Les règles sont évaluées dans l'ordre, ce qui signifie que les règles antérieures\nremplacent les suivantes.\nL'hôte peut être un nom de domaine (\"pastebin.com\"), un astérisque (\"*.pastebin.com\") ou\nune notation CIDR (\"127.0.0.0/8\").\nS'il n'y a pas de règles, le domaine est bloqué."
|
||||||
"gui.computercraft.config.http.proxy.host.tooltip": "Le nom d'hôte ou l'adresse IP du serveur proxy.",
|
|
||||||
"gui.computercraft.config.http.proxy.tooltip": "Tunnelise les requêtes HTTP et websocket via un serveur proxy. Affecte uniquement\nles règles HTTP avec \"use_proxy\" défini sur true (désactivé par défaut).\nSi l'authentification est requise pour le proxy, créez un fichier \"computercraft-proxy.pw\"\ndans le même dossier que \"computercraft-server.toml\", contenant le\nnom d'utilisateur et mot de passe séparés par deux-points, par ex. \"monutilisateur:monmotdepasse\". Pour\nProxy SOCKS4, seul le nom d'utilisateur est requis.",
|
|
||||||
"gui.computercraft.config.upload_max_size.tooltip": "La taille limite de téléversement de fichier, en octets. Doit être compris entre 1 Kio et 16 Mio.\nGardez à l'esprit que les téléversements sont traités en un seul clic - les fichiers volumineux ou\nde mauvaises performances réseau peuvent bloquer le thread du réseau. Et attention à l'espace disque !\nPlage : 1024 ~ 16777216",
|
|
||||||
"gui.computercraft.config.http.proxy": "Proxy",
|
|
||||||
"gui.computercraft.config.http.proxy.host": "Nom d'hôte",
|
|
||||||
"gui.computercraft.config.http.proxy.port": "Port",
|
|
||||||
"gui.computercraft.config.http.proxy.port.tooltip": "Le port du serveur proxy.\nPlage : 1 ~ 65536",
|
|
||||||
"gui.computercraft.config.http.proxy.type": "Type de proxy",
|
|
||||||
"gui.computercraft.config.http.proxy.type.tooltip": "Le type de proxy à utiliser.\nValeurs autorisées : HTTP, HTTPS, SOCKS4, SOCKS5",
|
|
||||||
"gui.computercraft.config.upload_max_size": "Taille limite de téléversement de fichiers (octets)"
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,23 +177,5 @@
|
|||||||
"gui.computercraft.config.turtle.need_fuel": "Включить механику топлива",
|
"gui.computercraft.config.turtle.need_fuel": "Включить механику топлива",
|
||||||
"gui.computercraft.config.turtle.normal_fuel_limit": "Лимит топлива Черепашек",
|
"gui.computercraft.config.turtle.normal_fuel_limit": "Лимит топлива Черепашек",
|
||||||
"gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "Лимит топлива для Черепашек.\nОграничение: > 0",
|
"gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "Лимит топлива для Черепашек.\nОграничение: > 0",
|
||||||
"gui.computercraft.config.turtle.tooltip": "Разные настройки, связанные с черепашками.",
|
"gui.computercraft.config.turtle.tooltip": "Разные настройки, связанные с черепашками."
|
||||||
"gui.computercraft.config.http.proxy.port": "Порт",
|
|
||||||
"gui.computercraft.config.http.proxy.port.tooltip": "Порт прокси-сервера.\nДиапазон: 1 ~ 65536",
|
|
||||||
"gui.computercraft.config.http.proxy.host": "Имя хоста",
|
|
||||||
"gui.computercraft.config.http.proxy": "Proxy",
|
|
||||||
"gui.computercraft.config.http.proxy.host.tooltip": "Имя хоста или IP-адрес прокси-сервера.",
|
|
||||||
"gui.computercraft.config.http.proxy.tooltip": "Туннелирует HTTP-запросы и запросы websocket через прокси-сервер. Влияет только на HTTP\nправила с параметром \"use_proxy\" в значении true (отключено по умолчанию).\nЕсли для прокси-сервера требуется аутентификация, создайте \"computercraft-proxy.pw\"\nфайл в том же каталоге, что и \"computercraft-server.toml\", содержащий имя\nпользователя и пароль, разделенные двоеточием, например \"myuser:mypassword\". Для\nпрокси-серверов SOCKS4 требуется только имя пользователя.",
|
|
||||||
"gui.computercraft.config.http.proxy.type": "Тип прокси-сервера",
|
|
||||||
"gui.computercraft.config.http.proxy.type.tooltip": "Тип используемого прокси-сервера.\nДопустимые значения: HTTP, HTTPS, SOCKS4, SOCKS5",
|
|
||||||
"gui.computercraft.upload.no_response.msg": "Ваш компьютер не использовал переданные вами файлы. Возможно, вам потребуется запустить программу %s и повторить попытку.",
|
|
||||||
"tracking_field.computercraft.max": "%s (максимальное)",
|
|
||||||
"tracking_field.computercraft.count": "%s (количество)",
|
|
||||||
"gui.computercraft.config.http.rules": "Разрешающие/запрещающие правила",
|
|
||||||
"gui.computercraft.config.http.websocket_enabled": "Включить веб-сокеты",
|
|
||||||
"gui.computercraft.config.http.websocket_enabled.tooltip": "Включить использование http веб-сокетов. Для этого необходимо, чтобы параметр «http_enable» был true.",
|
|
||||||
"gui.computercraft.config.log_computer_errors": "Регистрировать ошибки компьютера",
|
|
||||||
"gui.computercraft.config.log_computer_errors.tooltip": "Регистрировать исключения, вызванные периферийными устройствами и другими объектами Lua. Это облегчает\nдля авторам модов устранение проблем, но может привести к спаму в логах, если люди будут использовать\nглючные методы.",
|
|
||||||
"gui.computercraft.config.maximum_open_files": "Максимальное количество файлов, открытых на одном компьютере",
|
|
||||||
"gui.computercraft.config.http.rules.tooltip": "Список правил, которые контролируют поведение «http» API для определенных доменов или\nIP-адресов. Каждое правило представляет собой элемент с «узлом» для сопоставления и набором\nсвойств. Правила оцениваются по порядку, то есть более ранние правила перевешивают\nболее поздние.\nХост может быть доменным именем (\"pastebin.com\"), wildcard-сертификатом (\"*.pastebin.com\") или\nнотацией CIDR (\"127.0.0.0/8\").\nЕсли правил нет, домен блокируется."
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"pack": {
|
"pack": {
|
||||||
"pack_format": 15,
|
"pack_format": 12,
|
||||||
"description": "CC: Tweaked"
|
"description": "CC: Tweaked"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import net.minecraft.world.entity.player.Player;
|
|||||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
import net.minecraft.world.inventory.CraftingContainer;
|
import net.minecraft.world.inventory.CraftingContainer;
|
||||||
import net.minecraft.world.inventory.MenuType;
|
import net.minecraft.world.inventory.MenuType;
|
||||||
import net.minecraft.world.item.CreativeModeTab;
|
|
||||||
import net.minecraft.world.item.Item;
|
import net.minecraft.world.item.Item;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
import net.minecraft.world.item.crafting.Recipe;
|
import net.minecraft.world.item.crafting.Recipe;
|
||||||
@@ -170,11 +169,6 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat
|
|||||||
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
throw new UnsupportedOperationException("Cannot interact with the world inside tests");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public CreativeModeTab.Builder newCreativeModeTab() {
|
|
||||||
throw new IllegalStateException("Cannot create creative tab inside tests");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RecipeIngredients getRecipeIngredients() {
|
public RecipeIngredients getRecipeIngredients() {
|
||||||
throw new UnsupportedOperationException("Cannot query recipes inside tests");
|
throw new UnsupportedOperationException("Cannot query recipes inside tests");
|
||||||
|
|||||||
@@ -130,9 +130,7 @@ public class Exporter {
|
|||||||
|
|
||||||
dump.itemNames.put(location.toString(), stack.getHoverName().getString());
|
dump.itemNames.put(location.toString(), stack.getHoverName().getString());
|
||||||
renderer.captureRender(itemDir.resolve(location.getNamespace()).resolve(location.getPath() + ".png"),
|
renderer.captureRender(itemDir.resolve(location.getNamespace()).resolve(location.getPath() + ".png"),
|
||||||
() -> {
|
() -> Minecraft.getInstance().getItemRenderer().renderAndDecorateFakeItem(transform, stack, 0, 0)
|
||||||
// TODO: Minecraft.getInstance().getItemRenderer().ren(transform, stack, 0, 0)
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
renderer.clearState();
|
renderer.clearState();
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package dan200.computercraft.export;
|
|||||||
import com.mojang.blaze3d.pipeline.TextureTarget;
|
import com.mojang.blaze3d.pipeline.TextureTarget;
|
||||||
import com.mojang.blaze3d.platform.NativeImage;
|
import com.mojang.blaze3d.platform.NativeImage;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import com.mojang.blaze3d.vertex.VertexSorting;
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.FogRenderer;
|
import net.minecraft.client.renderer.FogRenderer;
|
||||||
import org.joml.Matrix4f;
|
import org.joml.Matrix4f;
|
||||||
@@ -37,7 +36,7 @@ public class ImageRenderer implements AutoCloseable {
|
|||||||
|
|
||||||
public void setupState() {
|
public void setupState() {
|
||||||
projectionMatrix = RenderSystem.getProjectionMatrix();
|
projectionMatrix = RenderSystem.getProjectionMatrix();
|
||||||
RenderSystem.setProjectionMatrix(new Matrix4f().identity().ortho(0, 16, 0, 16, 1000, 3000), VertexSorting.DISTANCE_TO_ORIGIN);
|
RenderSystem.setProjectionMatrix(new Matrix4f().identity().ortho(0, 16, 0, 16, 1000, 3000));
|
||||||
|
|
||||||
var transform = RenderSystem.getModelViewStack();
|
var transform = RenderSystem.getModelViewStack();
|
||||||
transform.pushPose();
|
transform.pushPose();
|
||||||
@@ -49,7 +48,7 @@ public class ImageRenderer implements AutoCloseable {
|
|||||||
|
|
||||||
public void clearState() {
|
public void clearState() {
|
||||||
if (projectionMatrix == null) throw new IllegalStateException("Not currently rendering");
|
if (projectionMatrix == null) throw new IllegalStateException("Not currently rendering");
|
||||||
RenderSystem.setProjectionMatrix(projectionMatrix, VertexSorting.DISTANCE_TO_ORIGIN);
|
RenderSystem.setProjectionMatrix(projectionMatrix);
|
||||||
RenderSystem.getModelViewStack().popPose();
|
RenderSystem.getModelViewStack().popPose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,36 +58,36 @@ class CCTestCommand {
|
|||||||
|
|
||||||
.then(literal("marker").executes(context -> {
|
.then(literal("marker").executes(context -> {
|
||||||
var player = context.getSource().getPlayerOrException();
|
var player = context.getSource().getPlayerOrException();
|
||||||
var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel());
|
var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.getLevel());
|
||||||
if (pos == null) return error(context.getSource(), "No nearby test");
|
if (pos == null) return error(context.getSource(), "No nearby test");
|
||||||
|
|
||||||
var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos);
|
var structureBlock = (StructureBlockEntity) player.getLevel().getBlockEntity(pos);
|
||||||
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
||||||
var info = GameTestRegistry.getTestFunction(structureBlock.getStructurePath());
|
var info = GameTestRegistry.getTestFunction(structureBlock.getStructurePath());
|
||||||
|
|
||||||
// Kill the existing armor stand
|
// Kill the existing armor stand
|
||||||
player
|
player
|
||||||
.serverLevel().getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(info.getTestName()))
|
.getLevel().getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(info.getTestName()))
|
||||||
.forEach(Entity::kill);
|
.forEach(Entity::kill);
|
||||||
|
|
||||||
// And create a new one
|
// And create a new one
|
||||||
var nbt = new CompoundTag();
|
var nbt = new CompoundTag();
|
||||||
nbt.putBoolean("Marker", true);
|
nbt.putBoolean("Marker", true);
|
||||||
nbt.putBoolean("Invisible", true);
|
nbt.putBoolean("Invisible", true);
|
||||||
var armorStand = assertNonNull(EntityType.ARMOR_STAND.create(player.level()));
|
var armorStand = assertNonNull(EntityType.ARMOR_STAND.create(player.getLevel()));
|
||||||
armorStand.readAdditionalSaveData(nbt);
|
armorStand.readAdditionalSaveData(nbt);
|
||||||
armorStand.copyPosition(player);
|
armorStand.copyPosition(player);
|
||||||
armorStand.setCustomName(Component.literal(info.getTestName()));
|
armorStand.setCustomName(Component.literal(info.getTestName()));
|
||||||
player.level().addFreshEntity(armorStand);
|
player.getLevel().addFreshEntity(armorStand);
|
||||||
return 0;
|
return 0;
|
||||||
}))
|
}))
|
||||||
|
|
||||||
.then(literal("give-computer").executes(context -> {
|
.then(literal("give-computer").executes(context -> {
|
||||||
var player = context.getSource().getPlayerOrException();
|
var player = context.getSource().getPlayerOrException();
|
||||||
var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.serverLevel());
|
var pos = StructureUtils.findNearestStructureBlock(player.blockPosition(), 15, player.getLevel());
|
||||||
if (pos == null) return error(context.getSource(), "No nearby test");
|
if (pos == null) return error(context.getSource(), "No nearby test");
|
||||||
|
|
||||||
var structureBlock = (StructureBlockEntity) player.level().getBlockEntity(pos);
|
var structureBlock = (StructureBlockEntity) player.getLevel().getBlockEntity(pos);
|
||||||
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
if (structureBlock == null) return error(context.getSource(), "No nearby structure block");
|
||||||
var info = GameTestRegistry.getTestFunction(structureBlock.getStructurePath());
|
var info = GameTestRegistry.getTestFunction(structureBlock.getStructurePath());
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import net.minecraft.gametest.framework.GameTestHelper
|
|||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||||
|
import net.minecraft.world.inventory.CraftingContainer
|
||||||
import net.minecraft.world.inventory.MenuType
|
import net.minecraft.world.inventory.MenuType
|
||||||
import net.minecraft.world.inventory.TransientCraftingContainer
|
|
||||||
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.item.crafting.CraftingRecipe
|
import net.minecraft.world.item.crafting.CraftingRecipe
|
||||||
@@ -31,7 +31,7 @@ class Recipe_Test {
|
|||||||
@GameTest(template = Structures.DEFAULT)
|
@GameTest(template = Structures.DEFAULT)
|
||||||
fun Craft_result_has_nbt(context: GameTestHelper) = context.sequence {
|
fun Craft_result_has_nbt(context: GameTestHelper) = context.sequence {
|
||||||
thenExecute {
|
thenExecute {
|
||||||
val container = TransientCraftingContainer(DummyMenu, 3, 3)
|
val container = CraftingContainer(DummyMenu, 3, 3)
|
||||||
container.setItem(0, ItemStack(Items.SKELETON_SKULL))
|
container.setItem(0, ItemStack(Items.SKELETON_SKULL))
|
||||||
container.setItem(1, ItemStack(ModRegistry.Items.COMPUTER_ADVANCED.get()))
|
container.setItem(1, ItemStack(ModRegistry.Items.COMPUTER_ADVANCED.get()))
|
||||||
|
|
||||||
|
|||||||
@@ -7,13 +7,9 @@ package dan200.computercraft.gametest
|
|||||||
import dan200.computercraft.api.detail.BasicItemDetailProvider
|
import dan200.computercraft.api.detail.BasicItemDetailProvider
|
||||||
import dan200.computercraft.api.detail.VanillaDetailRegistries
|
import dan200.computercraft.api.detail.VanillaDetailRegistries
|
||||||
import dan200.computercraft.api.lua.ObjectArguments
|
import dan200.computercraft.api.lua.ObjectArguments
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade
|
|
||||||
import dan200.computercraft.api.turtle.TurtleSide
|
|
||||||
import dan200.computercraft.api.upgrades.UpgradeData
|
|
||||||
import dan200.computercraft.core.apis.PeripheralAPI
|
import dan200.computercraft.core.apis.PeripheralAPI
|
||||||
import dan200.computercraft.gametest.api.*
|
import dan200.computercraft.gametest.api.*
|
||||||
import dan200.computercraft.gametest.core.TestHooks
|
import dan200.computercraft.gametest.core.TestHooks
|
||||||
import dan200.computercraft.impl.TurtleUpgrades
|
|
||||||
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
|
import dan200.computercraft.mixin.gametest.GameTestHelperAccessor
|
||||||
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
|
import dan200.computercraft.mixin.gametest.GameTestInfoAccessor
|
||||||
import dan200.computercraft.shared.ModRegistry
|
import dan200.computercraft.shared.ModRegistry
|
||||||
@@ -34,7 +30,6 @@ import net.minecraft.world.entity.EntityType
|
|||||||
import net.minecraft.world.entity.item.PrimedTnt
|
import net.minecraft.world.entity.item.PrimedTnt
|
||||||
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.item.enchantment.Enchantments
|
|
||||||
import net.minecraft.world.level.block.Blocks
|
import net.minecraft.world.level.block.Blocks
|
||||||
import net.minecraft.world.level.block.FenceBlock
|
import net.minecraft.world.level.block.FenceBlock
|
||||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties
|
||||||
@@ -179,85 +174,6 @@ class Turtle_Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Digging using a pickaxe with `{"consumesDurability": "always"}`, consumes durability.
|
|
||||||
*/
|
|
||||||
@GameTest
|
|
||||||
fun Dig_consume_durability(helper: GameTestHelper) = helper.sequence {
|
|
||||||
thenOnComputer { turtle.dig(Optional.empty()).await() }
|
|
||||||
thenExecute {
|
|
||||||
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 3))
|
|
||||||
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Items.COBBLESTONE)))
|
|
||||||
|
|
||||||
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
|
|
||||||
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
|
|
||||||
assertEquals(TurtleUpgrades.instance().get("cctest:wooden_pickaxe"), upgrade, "Upgrade is a wooden pickaxe")
|
|
||||||
|
|
||||||
val item = ItemStack(Items.WOODEN_PICKAXE)
|
|
||||||
item.damageValue = 1
|
|
||||||
helper.assertUpgradeItem(item, turtle.getUpgradeWithData(TurtleSide.LEFT)!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Digging using a pickaxe with `{"consumesDurability": "always"}` and no durability removes the tool.
|
|
||||||
*/
|
|
||||||
@GameTest
|
|
||||||
fun Dig_breaks_tool(helper: GameTestHelper) = helper.sequence {
|
|
||||||
thenOnComputer { turtle.dig(Optional.empty()).await() }
|
|
||||||
thenExecute {
|
|
||||||
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 3))
|
|
||||||
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Items.COBBLESTONE)))
|
|
||||||
|
|
||||||
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
|
|
||||||
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
|
|
||||||
assertEquals(null, upgrade, "Upgrade broke")
|
|
||||||
|
|
||||||
helper.assertUpgradeItem(
|
|
||||||
ItemStack(Items.WOODEN_PICKAXE),
|
|
||||||
UpgradeData.ofDefault(TurtleUpgrades.instance().get("cctest:wooden_pickaxe")),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Digging using a silk-touch enchanted pickaxe with `{"consumesDurability": "when_enchanted"}`, consumes durability
|
|
||||||
* uses silk touch.
|
|
||||||
*/
|
|
||||||
@GameTest
|
|
||||||
fun Dig_enchanted_consume_durability(helper: GameTestHelper) = helper.sequence {
|
|
||||||
thenOnComputer { turtle.dig(Optional.empty()).await() }
|
|
||||||
thenExecute {
|
|
||||||
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 2, 3))
|
|
||||||
helper.assertContainerExactly(BlockPos(2, 2, 2), listOf(ItemStack(Items.STONE)))
|
|
||||||
|
|
||||||
val turtle = helper.getBlockEntity(BlockPos(2, 2, 2), ModRegistry.BlockEntities.TURTLE_NORMAL.get()).access
|
|
||||||
val upgrade = turtle.getUpgrade(TurtleSide.LEFT)
|
|
||||||
assertEquals(
|
|
||||||
TurtleUpgrades.instance().get("cctest:netherite_pickaxe"),
|
|
||||||
upgrade,
|
|
||||||
"Upgrade is a netherite pickaxe",
|
|
||||||
)
|
|
||||||
|
|
||||||
val item = ItemStack(Items.NETHERITE_PICKAXE)
|
|
||||||
item.damageValue = 1
|
|
||||||
item.enchant(Enchantments.SILK_TOUCH, 1)
|
|
||||||
item.setRepairCost(1)
|
|
||||||
|
|
||||||
helper.assertUpgradeItem(item, turtle.getUpgradeWithData(TurtleSide.LEFT)!!)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun GameTestHelper.assertUpgradeItem(expected: ItemStack, upgrade: UpgradeData<ITurtleUpgrade>) {
|
|
||||||
if (!ItemStack.matches(expected, upgrade.upgradeItem)) {
|
|
||||||
fail("Invalid upgrade item\n Expected => ${expected.tag}\n Actual => ${upgrade.upgradeItem.tag}")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ItemStack.matches(ItemStack(expected.item), upgrade.upgrade.craftingItem)) {
|
|
||||||
fail("Original upgrade item has changed (is now ${upgrade.upgrade.craftingItem})")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks turtles can place monitors
|
* Checks turtles can place monitors
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "computercraft:tool",
|
|
||||||
"item": "minecraft:netherite_pickaxe",
|
|
||||||
"allowEnchantments": true,
|
|
||||||
"consumeDurability": "when_enchanted"
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"type": "computercraft:tool",
|
|
||||||
"item": "minecraft:wooden_pickaxe",
|
|
||||||
"consumeDurability": "always"
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
{
|
|
||||||
DataVersion: 3218,
|
|
||||||
size: [5, 5, 5],
|
|
||||||
data: [
|
|
||||||
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.dig_breaks_tool", LeftUpgrade: "cctest:wooden_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 58}}, On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}},
|
|
||||||
{pos: [2, 1, 3], state: "minecraft:stone"},
|
|
||||||
{pos: [2, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 4], state: "minecraft:air"}
|
|
||||||
],
|
|
||||||
entities: [],
|
|
||||||
palette: [
|
|
||||||
"minecraft:polished_andesite",
|
|
||||||
"minecraft:stone",
|
|
||||||
"minecraft:air",
|
|
||||||
"computercraft:turtle_normal{facing:south,waterlogged:false}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
{
|
|
||||||
DataVersion: 3218,
|
|
||||||
size: [5, 5, 5],
|
|
||||||
data: [
|
|
||||||
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.dig_consume_durability", LeftUpgrade: "cctest:wooden_pickaxe", On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}},
|
|
||||||
{pos: [2, 1, 3], state: "minecraft:stone"},
|
|
||||||
{pos: [2, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 4], state: "minecraft:air"}
|
|
||||||
],
|
|
||||||
entities: [],
|
|
||||||
palette: [
|
|
||||||
"minecraft:polished_andesite",
|
|
||||||
"minecraft:stone",
|
|
||||||
"minecraft:air",
|
|
||||||
"computercraft:turtle_normal{facing:south,waterlogged:false}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
{
|
|
||||||
DataVersion: 3337,
|
|
||||||
size: [5, 5, 5],
|
|
||||||
data: [
|
|
||||||
{pos: [0, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [1, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [2, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [3, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 0], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 1], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 2], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 3], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [4, 0, 4], state: "minecraft:polished_andesite"},
|
|
||||||
{pos: [0, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 1, 2], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 1, Fuel: 80, Items: [], Label: "turtle_test.dig_enchanted_consume_durability", LeftUpgrade: "cctest:netherite_pickaxe", LeftUpgradeNbt: {Tag: {Damage: 0, Enchantments: [{id: "minecraft:silk_touch", lvl: 1s}], RepairCost: 1}}, On: 1b, Owner: {LowerId: -6876936588741668278L, Name: "Dev", UpperId: 4039158846114182220L}, Slot: 0, id: "computercraft:turtle_normal"}},
|
|
||||||
{pos: [2, 1, 3], state: "minecraft:stone"},
|
|
||||||
{pos: [2, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 1, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 2, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 3, 4], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [0, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [1, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [2, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [3, 4, 4], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 0], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 1], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 2], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 3], state: "minecraft:air"},
|
|
||||||
{pos: [4, 4, 4], state: "minecraft:air"}
|
|
||||||
],
|
|
||||||
entities: [],
|
|
||||||
palette: [
|
|
||||||
"minecraft:polished_andesite",
|
|
||||||
"minecraft:stone",
|
|
||||||
"minecraft:air",
|
|
||||||
"computercraft:turtle_normal{facing:south,waterlogged:false}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"pack": {
|
"pack": {
|
||||||
"pack_format": 15,
|
"pack_format": 12,
|
||||||
"description": "CC: Test"
|
"description": "CC: Test"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,8 +132,7 @@ public class OSAPI implements ILuaAPI {
|
|||||||
* @param name The name of the event to queue.
|
* @param name The name of the event to queue.
|
||||||
* @param args The parameters of the event.
|
* @param args The parameters of the event.
|
||||||
* @cc.tparam string name The name of the event to queue.
|
* @cc.tparam string name The name of the event to queue.
|
||||||
* @cc.param ... The parameters of the event. These can be any primitive type (boolean, number, string) as well as
|
* @cc.param ... The parameters of the event.
|
||||||
* tables. Other types (like functions), as well as metatables, will not be preserved.
|
|
||||||
* @cc.see os.pullEvent To pull the event queued
|
* @cc.see os.pullEvent To pull the event queued
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
|
|||||||
@@ -6,14 +6,9 @@ package dan200.computercraft.core.apis.http.options;
|
|||||||
|
|
||||||
import com.google.common.net.InetAddresses;
|
import com.google.common.net.InetAddresses;
|
||||||
|
|
||||||
import java.net.Inet4Address;
|
|
||||||
import java.net.Inet6Address;
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A predicate on an address. Matches against a domain and an ip address.
|
* A predicate on an address. Matches against a domain and an ip address.
|
||||||
@@ -112,48 +107,12 @@ interface AddressPredicate {
|
|||||||
final class PrivatePattern implements AddressPredicate {
|
final class PrivatePattern implements AddressPredicate {
|
||||||
static final PrivatePattern INSTANCE = new PrivatePattern();
|
static final PrivatePattern INSTANCE = new PrivatePattern();
|
||||||
|
|
||||||
private static final Set<InetAddress> additionalAddresses = Arrays.stream(new String[]{
|
|
||||||
// Block various cloud providers internal IPs.
|
|
||||||
"192.0.0.192", // Oracle
|
|
||||||
}).map(InetAddresses::forString).collect(Collectors.toUnmodifiableSet());
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(InetAddress socketAddress) {
|
public boolean matches(InetAddress socketAddress) {
|
||||||
return
|
return socketAddress.isAnyLocalAddress()
|
||||||
socketAddress.isAnyLocalAddress() // 0.0.0.0, ::0
|
|| socketAddress.isLoopbackAddress()
|
||||||
|| socketAddress.isLoopbackAddress() // 127.0.0.0/8, ::1
|
|| socketAddress.isLinkLocalAddress()
|
||||||
|| socketAddress.isLinkLocalAddress() // 169.254.0.0/16, fe80::/10
|
|| socketAddress.isSiteLocalAddress();
|
||||||
|| socketAddress.isSiteLocalAddress() // 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fec0::/10
|
|
||||||
|| socketAddress.isMulticastAddress() // 224.0.0.0/4, ff00::/8
|
|
||||||
|| isUniqueLocalAddress(socketAddress) // fd00::/8
|
|
||||||
|| isCarrierGradeNatAddress(socketAddress) // 100.64.0.0/10
|
|
||||||
|| additionalAddresses.contains(socketAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if an IP address lives inside the ULA address range.
|
|
||||||
*
|
|
||||||
* @param address The IP address to test.
|
|
||||||
* @return Whether this address sits in the ULA address range.
|
|
||||||
* @see <a href="https://en.wikipedia.org/wiki/Unique_local_address">Unique local address on Wikipedia</a>
|
|
||||||
*/
|
|
||||||
private boolean isUniqueLocalAddress(InetAddress address) {
|
|
||||||
// ULA is actually defined as fc00::/7 (so both fc00::/8 and fd00::/8). However, only the latter is actually
|
|
||||||
// defined right now, so let's be conservative.
|
|
||||||
return address instanceof Inet6Address && (address.getAddress()[0] & 0xff) == 0xfd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if an IP address lives within the CGNAT address range (100.64.0.0/10).
|
|
||||||
*
|
|
||||||
* @param address The IP address to test.
|
|
||||||
* @return Whether this address sits in the CGNAT address range.
|
|
||||||
* @see <a href="https://en.wikipedia.org/wiki/Carrier-grade_NAT">Carrier-grade NAT on Wikipedia</a>
|
|
||||||
*/
|
|
||||||
private boolean isCarrierGradeNatAddress(InetAddress address) {
|
|
||||||
if (!(address instanceof Inet4Address)) return false;
|
|
||||||
var bytes = address.getAddress();
|
|
||||||
return bytes[0] == 100 && ((bytes[1] & 0xFF) >= 64 && (bytes[1] & 0xFF) <= 127);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ final class MethodSupplierImpl<T> implements MethodSupplier<T> {
|
|||||||
for (var extra : source.getExtra()) {
|
for (var extra : source.getExtra()) {
|
||||||
var extraMethods = getMethods(extra.getClass());
|
var extraMethods = getMethods(extra.getClass());
|
||||||
if (!extraMethods.isEmpty()) hasMethods = true;
|
if (!extraMethods.isEmpty()) hasMethods = true;
|
||||||
for (var method : extraMethods) consumer.accept(extra, method.name(), method.method(), method);
|
for (var method : extraMethods) consumer.accept(object, method.name(), method.method(), method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,32 +2,13 @@
|
|||||||
--
|
--
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
-- SPDX-License-Identifier: LicenseRef-CCPL
|
||||||
|
|
||||||
--[[- Read and write configuration options for CraftOS and your programs.
|
--- Read and write configuration options for CraftOS and your programs.
|
||||||
|
--
|
||||||
When a computer starts, it reads the current value of settings from the
|
-- By default, the settings API will load its configuration from the
|
||||||
`/.settings` file. These values then may be @{settings.get|read} or
|
-- `/.settings` file. One can then use @{settings.save} to update the file.
|
||||||
@{settings.set|modified}.
|
--
|
||||||
|
-- @module settings
|
||||||
:::caution
|
-- @since 1.78
|
||||||
Calling @{settings.set} does _not_ update the settings file by default. You
|
|
||||||
_must_ call @{settings.save} to persist values.
|
|
||||||
:::
|
|
||||||
|
|
||||||
@module settings
|
|
||||||
@since 1.78
|
|
||||||
@usage Define an basic setting `123` and read its value.
|
|
||||||
|
|
||||||
settings.define("my.setting", {
|
|
||||||
description = "An example setting",
|
|
||||||
default = 123,
|
|
||||||
type = number,
|
|
||||||
})
|
|
||||||
print("my.setting = " .. settings.get("my.setting")) -- 123
|
|
||||||
|
|
||||||
You can then use the `set` program to change its value (e.g. `set my.setting 456`),
|
|
||||||
and then re-run the `example` program to check it has changed.
|
|
||||||
|
|
||||||
]]
|
|
||||||
|
|
||||||
local expect = dofile("rom/modules/main/cc/expect.lua")
|
local expect = dofile("rom/modules/main/cc/expect.lua")
|
||||||
local type, expect, field = type, expect.expect, expect.field
|
local type, expect, field = type, expect.expect, expect.field
|
||||||
@@ -111,19 +92,13 @@ local function set_value(name, new)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[- Set the value of a setting.
|
--- Set the value of a setting.
|
||||||
|
--
|
||||||
:::caution
|
-- @tparam string name The name of the setting to set
|
||||||
Calling @{settings.set} does _not_ update the settings file by default. You
|
-- @param value The setting's value. This cannot be `nil`, and must be
|
||||||
_must_ call @{settings.save} to persist values.
|
-- serialisable by @{textutils.serialize}.
|
||||||
:::
|
-- @throws If this value cannot be serialised
|
||||||
|
-- @see settings.unset
|
||||||
@tparam string name The name of the setting to set
|
|
||||||
@param value The setting's value. This cannot be `nil`, and must be
|
|
||||||
serialisable by @{textutils.serialize}.
|
|
||||||
@throws If this value cannot be serialised
|
|
||||||
@see settings.unset
|
|
||||||
]]
|
|
||||||
function set(name, value)
|
function set(name, value)
|
||||||
expect(1, name, "string")
|
expect(1, name, "string")
|
||||||
expect(2, value, "number", "string", "boolean", "table")
|
expect(2, value, "number", "string", "boolean", "table")
|
||||||
|
|||||||
@@ -1,29 +1,3 @@
|
|||||||
# New features in CC: Tweaked 1.106.1
|
|
||||||
|
|
||||||
Several bug fixes:
|
|
||||||
* Block the CGNAT range (100.64.0.0/10) by default.
|
|
||||||
* Fix conflicts with other mods replacing reach distance.
|
|
||||||
|
|
||||||
# New features in CC: Tweaked 1.106.0
|
|
||||||
|
|
||||||
* Numerous documentation improvements (MCJack123, znepb, penguinencounter).
|
|
||||||
* Port `fs.find` to Lua. This also allows using `?` as a wildcard.
|
|
||||||
* Computers cursors now glow in the dark.
|
|
||||||
* Allow changing turtle upgrades from the GUI.
|
|
||||||
* Add option to serialize Unicode strings to JSON (MCJack123).
|
|
||||||
* Small optimisations to the `window` API.
|
|
||||||
* Turtle upgrades can now preserve NBT from upgrade item stack and when broken.
|
|
||||||
* Add support for tool enchantments and durability via datapacks. This is disabled for the built-in tools.
|
|
||||||
|
|
||||||
Several bug fixes:
|
|
||||||
* Fix turtles rendering incorrectly when upside down.
|
|
||||||
* Fix misplaced calls to IArguments.escapes.
|
|
||||||
* Lua REPL no longer accepts `)(` as a valid expression.
|
|
||||||
* Fix several inconsistencies with `require`/`package.path` in the Lua REPL (Wojbie).
|
|
||||||
* Fix turtle being able to place water buckets outside its reach distance.
|
|
||||||
* Fix private several IP address ranges not being blocked by the `$private` rule.
|
|
||||||
* Improve permission checks in the `/computercraft` command.
|
|
||||||
|
|
||||||
# New features in CC: Tweaked 1.105.0
|
# New features in CC: Tweaked 1.105.0
|
||||||
|
|
||||||
* Optimise JSON string parsing.
|
* Optimise JSON string parsing.
|
||||||
|
|||||||
@@ -1,7 +1,25 @@
|
|||||||
New features in CC: Tweaked 1.106.1
|
New features in CC: Tweaked 1.105.0
|
||||||
|
|
||||||
|
* Optimise JSON string parsing.
|
||||||
|
* Add `colors.fromBlit` (Erb3).
|
||||||
|
* Upload file size limit is now configurable (khankul).
|
||||||
|
* Wired cables no longer have a distance limit.
|
||||||
|
* Java methods now coerce values to strings consistently with Lua.
|
||||||
|
* Add custom timeout support to the HTTP API.
|
||||||
|
* Support custom proxies for HTTP requests (Lemmmy).
|
||||||
|
* The `speaker` program now errors when playing HTML files.
|
||||||
|
* `edit` now shows an error message when editing read-only files.
|
||||||
|
* Update Ukranian translation (SirEdvin).
|
||||||
|
|
||||||
Several bug fixes:
|
Several bug fixes:
|
||||||
* Block the CGNAT range (100.64.0.0/10) by default.
|
* Allow GPS hosts to only be 1 block apart.
|
||||||
* Fix conflicts with other mods replacing reach distance.
|
* Fix "Turn On"/"Turn Off" buttons being inverted in the computer GUI (Erb3).
|
||||||
|
* Fix arrow keys not working in the printout UI.
|
||||||
|
* Several documentation fixes (zyxkad, Lupus590, Commandcracker).
|
||||||
|
* Fix monitor renderer debug text always being visible on Forge.
|
||||||
|
* Fix crash when another mod changes the LoggerContext.
|
||||||
|
* Fix the `monitor_renderer` option not being present in Fabric config files.
|
||||||
|
* Pasting on MacOS/OSX now uses Cmd+V rather than Ctrl+V.
|
||||||
|
* Fix turtles placing blocks upside down when at y<0.
|
||||||
|
|
||||||
Type "help changelog" to see the full version history.
|
Type "help changelog" to see the full version history.
|
||||||
|
|||||||
@@ -31,30 +31,12 @@ public class AddressRuleTest {
|
|||||||
@ValueSource(strings = {
|
@ValueSource(strings = {
|
||||||
"0.0.0.0", "[::]",
|
"0.0.0.0", "[::]",
|
||||||
"localhost", "127.0.0.1.nip.io", "127.0.0.1", "[::1]",
|
"localhost", "127.0.0.1.nip.io", "127.0.0.1", "[::1]",
|
||||||
"172.17.0.1", "192.168.1.114", "[0:0:0:0:0:ffff:c0a8:172]", "10.0.0.1",
|
"172.17.0.1", "192.168.1.114", "[0:0:0:0:0:ffff:c0a8:172]", "10.0.0.1"
|
||||||
// Multicast
|
|
||||||
"224.0.0.1", "ff02::1",
|
|
||||||
// CGNAT
|
|
||||||
"100.64.0.0", "100.127.255.255",
|
|
||||||
// Cloud metadata providers
|
|
||||||
"100.100.100.200", // Alibaba
|
|
||||||
"192.0.0.192", // Oracle
|
|
||||||
"fd00:ec2::254", // AWS
|
|
||||||
"169.254.169.254", // AWS, Digital Ocean, GCP, etc..
|
|
||||||
})
|
})
|
||||||
public void blocksLocalDomains(String domain) {
|
public void blocksLocalDomains(String domain) {
|
||||||
assertEquals(apply(CoreConfig.httpRules, domain, 80).action, Action.DENY);
|
assertEquals(apply(CoreConfig.httpRules, domain, 80).action, Action.DENY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
|
||||||
@ValueSource(strings = {
|
|
||||||
// Ensure either side of the CGNAT range is allowed.
|
|
||||||
"100.63.255.255", "100.128.0.0"
|
|
||||||
})
|
|
||||||
public void allowsNonLocalDomains(String domain) {
|
|
||||||
assertEquals(apply(CoreConfig.httpRules, domain, 80).action, Action.ALLOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Options apply(Iterable<AddressRule> rules, String host, int port) {
|
private Options apply(Iterable<AddressRule> rules, String host, int port) {
|
||||||
return AddressRule.apply(rules, host, new InetSocketAddress(host, port));
|
return AddressRule.apply(rules, host, new InetSocketAddress(host, port));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class MethodTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExtra() {
|
public void testExtra() {
|
||||||
ComputerBootstrap.run("assert(extra.go() == nil, 'go')\nassert(extra.go2() == 456, 'go2')",
|
ComputerBootstrap.run("assert(extra.go, 'go')\nassert(extra.go2, 'go2')",
|
||||||
x -> x.addApi(new ExtraObject()),
|
x -> x.addApi(new ExtraObject()),
|
||||||
50);
|
50);
|
||||||
}
|
}
|
||||||
@@ -163,8 +163,7 @@ public class MethodTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final int go2() {
|
public final void go2() {
|
||||||
return 456;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ fun addRemappedConfiguration(name: String) {
|
|||||||
val ourSourceSet = sourceSets.register(name) {
|
val ourSourceSet = sourceSets.register(name) {
|
||||||
// Try to make this source set as much of a non-entity as possible.
|
// Try to make this source set as much of a non-entity as possible.
|
||||||
listOf(allSource, java, resources, kotlin).forEach { it.setSrcDirs(emptyList<File>()) }
|
listOf(allSource, java, resources, kotlin).forEach { it.setSrcDirs(emptyList<File>()) }
|
||||||
|
runtimeClasspath += sourceSets["client"].runtimeClasspath
|
||||||
}
|
}
|
||||||
val capitalName = name.replaceFirstChar { it.titlecase(Locale.ROOT) }
|
val capitalName = name.replaceFirstChar { it.titlecase(Locale.ROOT) }
|
||||||
loom.addRemapConfiguration("mod$capitalName") {
|
loom.addRemapConfiguration("mod$capitalName") {
|
||||||
@@ -45,6 +46,7 @@ fun addRemappedConfiguration(name: String) {
|
|||||||
|
|
||||||
addRemappedConfiguration("testWithSodium")
|
addRemappedConfiguration("testWithSodium")
|
||||||
addRemappedConfiguration("testWithIris")
|
addRemappedConfiguration("testWithIris")
|
||||||
|
addRemappedConfiguration("integrations")
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
modImplementation(libs.bundles.externalMods.fabric)
|
modImplementation(libs.bundles.externalMods.fabric)
|
||||||
@@ -52,17 +54,15 @@ dependencies {
|
|||||||
exclude("net.fabricmc", "fabric-loader")
|
exclude("net.fabricmc", "fabric-loader")
|
||||||
exclude("net.fabricmc.fabric-api")
|
exclude("net.fabricmc.fabric-api")
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
|
|
||||||
modClientRuntimeOnly(libs.bundles.externalMods.fabric.runtime) {
|
modClientRuntimeOnly(libs.bundles.externalMods.fabric.runtime) {
|
||||||
exclude("net.fabricmc", "fabric-loader")
|
exclude("net.fabricmc", "fabric-loader")
|
||||||
exclude("net.fabricmc.fabric-api")
|
exclude("net.fabricmc.fabric-api")
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
"modTestWithSodium"(libs.sodium)
|
"modTestWithSodium"(libs.sodium)
|
||||||
"modTestWithIris"(libs.iris)
|
"modTestWithIris"(libs.iris)
|
||||||
"modTestWithIris"(libs.sodium)
|
"modTestWithIris"(libs.sodium)
|
||||||
|
"modIntegrations"(libs.libmultipart)
|
||||||
|
|
||||||
include(libs.cobalt)
|
include(libs.cobalt)
|
||||||
include(libs.jzlib)
|
include(libs.jzlib)
|
||||||
@@ -169,6 +169,14 @@ loom {
|
|||||||
property("fabric-api.gametest.report-file", project.buildDir.resolve("test-results/runGametest.xml").absolutePath)
|
property("fabric-api.gametest.report-file", project.buildDir.resolve("test-results/runGametest.xml").absolutePath)
|
||||||
runDir("run/gametest")
|
runDir("run/gametest")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register("clientWithIntegrations") {
|
||||||
|
configName = "Client (+integrations)"
|
||||||
|
runDir("run/integration")
|
||||||
|
client()
|
||||||
|
|
||||||
|
source(sourceSets["integrations"])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,16 @@
|
|||||||
|
|
||||||
package dan200.computercraft.client;
|
package dan200.computercraft.client;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.ComputerCraftAPI;
|
||||||
|
import dan200.computercraft.client.integration.libmultipart.LibMultiPartIntegrationClient;
|
||||||
import dan200.computercraft.client.model.EmissiveComputerModel;
|
import dan200.computercraft.client.model.EmissiveComputerModel;
|
||||||
import dan200.computercraft.client.model.turtle.TurtleModelLoader;
|
import dan200.computercraft.client.model.turtle.TurtleModelLoader;
|
||||||
import dan200.computercraft.shared.ModRegistry;
|
import dan200.computercraft.shared.ModRegistry;
|
||||||
|
import dan200.computercraft.shared.config.ConfigSpec;
|
||||||
|
import dan200.computercraft.shared.integration.LoadedMods;
|
||||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
||||||
|
import dan200.computercraft.shared.platform.FabricConfigFile;
|
||||||
import dan200.computercraft.shared.platform.NetworkHandler;
|
import dan200.computercraft.shared.platform.NetworkHandler;
|
||||||
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
|
||||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
@@ -17,6 +22,7 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
|||||||
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
|
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
|
||||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||||
import net.fabricmc.fabric.api.event.client.player.ClientPickBlockGatherCallback;
|
import net.fabricmc.fabric.api.event.client.player.ClientPickBlockGatherCallback;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.renderer.RenderType;
|
import net.minecraft.client.renderer.RenderType;
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
@@ -68,5 +74,10 @@ public class ComputerCraftClient {
|
|||||||
|
|
||||||
return cable.getCloneItemStack(state, hit, level, pos, player);
|
return cable.getCloneItemStack(state, hit, level, pos, player);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Load config file
|
||||||
|
((FabricConfigFile) ConfigSpec.clientSpec).load(FabricLoader.getInstance().getConfigDir().resolve(ComputerCraftAPI.MOD_ID + "-client.toml"));
|
||||||
|
|
||||||
|
if (LoadedMods.LIB_MULTI_PART) LibMultiPartIntegrationClient.init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package dan200.computercraft.client.integration.libmultipart;
|
||||||
|
|
||||||
|
import alexiil.mc.lib.multipart.api.render.PartStaticModelRegisterEvent;
|
||||||
|
import dan200.computercraft.shared.integration.libmultipart.BlockStateModelKey;
|
||||||
|
import dan200.computercraft.shared.integration.libmultipart.LibMultiPartIntegration;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client-side support for LibMultiPart.
|
||||||
|
*
|
||||||
|
* @see LibMultiPartIntegration
|
||||||
|
*/
|
||||||
|
public class LibMultiPartIntegrationClient {
|
||||||
|
public static void init() {
|
||||||
|
PartStaticModelRegisterEvent.EVENT.register(renderer -> {
|
||||||
|
var baker = Minecraft.getInstance().getBlockRenderer();
|
||||||
|
renderer.register(BlockStateModelKey.class, (key, ctx) ->
|
||||||
|
ctx.bakedModelConsumer().accept(baker.getBlockModel(key.state()), key.state()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requirements": [["has_monitor", "has_the_recipe"]],
|
"requirements": [["has_monitor", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:skull_cloudy"]},
|
"rewards": {"recipes": ["computercraft:skull_cloudy"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requirements": [["has_computer", "has_the_recipe"]],
|
"requirements": [["has_computer", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:skull_dan200"]},
|
"rewards": {"recipes": ["computercraft:skull_dan200"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:cable"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:cable"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_computer", "has_modem", "has_the_recipe"]],
|
"requirements": [["has_computer", "has_modem", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:cable"]},
|
"rewards": {"recipes": ["computercraft:cable"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requirements": [["has_components", "has_the_recipe"]],
|
"requirements": [["has_components", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:computer_advanced"]},
|
"rewards": {"recipes": ["computercraft:computer_advanced"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requirements": [["has_components", "has_the_recipe"]],
|
"requirements": [["has_components", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:computer_advanced_upgrade"]},
|
"rewards": {"recipes": ["computercraft:computer_advanced_upgrade"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requirements": [["has_components", "has_the_recipe"]],
|
"requirements": [["has_components", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:computer_command"]},
|
"rewards": {"recipes": ["computercraft:computer_command"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,5 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"requirements": [["has_redstone", "has_the_recipe"]],
|
"requirements": [["has_redstone", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:computer_normal"]},
|
"rewards": {"recipes": ["computercraft:computer_normal"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_1"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_1"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_1"]},
|
"rewards": {"recipes": ["computercraft:disk_1"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_10"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_10"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_10"]},
|
"rewards": {"recipes": ["computercraft:disk_10"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_11"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_11"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_11"]},
|
"rewards": {"recipes": ["computercraft:disk_11"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_12"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_12"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_12"]},
|
"rewards": {"recipes": ["computercraft:disk_12"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_13"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_13"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_13"]},
|
"rewards": {"recipes": ["computercraft:disk_13"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_14"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_14"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_14"]},
|
"rewards": {"recipes": ["computercraft:disk_14"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_15"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_15"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_15"]},
|
"rewards": {"recipes": ["computercraft:disk_15"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_16"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_16"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_16"]},
|
"rewards": {"recipes": ["computercraft:disk_16"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_2"}, "trigger": "minecraft:recipe_unlocked"}
|
"has_the_recipe": {"conditions": {"recipe": "computercraft:disk_2"}, "trigger": "minecraft:recipe_unlocked"}
|
||||||
},
|
},
|
||||||
"requirements": [["has_drive", "has_the_recipe"]],
|
"requirements": [["has_drive", "has_the_recipe"]],
|
||||||
"rewards": {"recipes": ["computercraft:disk_2"]},
|
"rewards": {"recipes": ["computercraft:disk_2"]}
|
||||||
"sends_telemetry_event": false
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user