mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-15 22:17:39 +00:00
Compare commits
12 Commits
v1.21-1.11
...
v1.21-1.11
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2c740bb904 | ||
![]() |
0e4710a956 | ||
![]() |
aca1d43550 | ||
![]() |
f10e401aea | ||
![]() |
7744d2663b | ||
![]() |
4566cb8273 | ||
![]() |
052e7a7ae5 | ||
![]() |
0895200681 | ||
![]() |
1a1623075f | ||
![]() |
54a95e07a4 | ||
![]() |
09d0f563b7 | ||
![]() |
e188f1d3fa |
6
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
6
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -8,10 +8,8 @@ body:
|
||||
label: Minecraft Version
|
||||
description: What version of Minecraft are you using?
|
||||
options:
|
||||
- 1.16.x
|
||||
- 1.18.x
|
||||
- 1.19.x
|
||||
- 1.20.x
|
||||
- 1.20.1
|
||||
- 1.21.x
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
|
@@ -39,7 +39,7 @@ on is present.
|
||||
```groovy
|
||||
repositories {
|
||||
maven {
|
||||
url "https://squiddev.cc/maven/"
|
||||
url "https://maven.squiddev.cc"
|
||||
content {
|
||||
includeGroup("cc.tweaked")
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ repositories {
|
||||
}
|
||||
}
|
||||
|
||||
maven("https://squiddev.cc/maven") {
|
||||
maven("https://maven.squiddev.cc") {
|
||||
name = "SquidDev"
|
||||
content {
|
||||
includeGroup("cc.tweaked.vanilla-extract")
|
||||
|
@@ -38,7 +38,7 @@ java {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
val mainMaven = maven("https://squiddev.cc/maven") {
|
||||
val mainMaven = maven("https://maven.squiddev.cc/mirror") {
|
||||
name = "SquidDev"
|
||||
}
|
||||
|
||||
@@ -133,8 +133,8 @@ tasks.processResources {
|
||||
tasks.withType(AbstractArchiveTask::class.java).configureEach {
|
||||
isPreserveFileTimestamps = false
|
||||
isReproducibleFileOrder = true
|
||||
dirMode = Integer.valueOf("755", 8)
|
||||
fileMode = Integer.valueOf("664", 8)
|
||||
filePermissions {}
|
||||
dirPermissions {}
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
|
@@ -38,7 +38,7 @@ publishing {
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven("https://squiddev.cc/maven") {
|
||||
maven("https://maven.squiddev.cc") {
|
||||
name = "SquidDev"
|
||||
|
||||
credentials(PasswordCredentials::class)
|
||||
|
@@ -9,6 +9,7 @@ import org.gradle.api.file.FileSystemLocation
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.JavaExec
|
||||
import org.gradle.kotlin.dsl.getByName
|
||||
import org.gradle.process.BaseExecSpec
|
||||
import org.gradle.process.JavaExecSpec
|
||||
import org.gradle.process.ProcessForkOptions
|
||||
@@ -46,6 +47,21 @@ fun JavaExec.copyToFull(spec: JavaExec) {
|
||||
copyToExec(spec)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base this [JavaExec] task on an existing task.
|
||||
*/
|
||||
fun JavaExec.copyFromTask(task: JavaExec) {
|
||||
for (dep in task.dependsOn) dependsOn(dep)
|
||||
task.copyToFull(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Base this [JavaExec] task on an existing task.
|
||||
*/
|
||||
fun JavaExec.copyFromTask(task: String) {
|
||||
copyFromTask(project.tasks.getByName<JavaExec>(task))
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy additional [BaseExecSpec] options which aren't handled by [ProcessForkOptions.copyTo].
|
||||
*/
|
||||
|
@@ -1,62 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package cc.tweaked.gradle
|
||||
|
||||
import net.neoforged.gradle.common.runs.run.RunImpl
|
||||
import net.neoforged.gradle.common.runs.tasks.RunExec
|
||||
import net.neoforged.gradle.dsl.common.extensions.RunnableSourceSet
|
||||
import net.neoforged.gradle.dsl.common.runs.run.Run
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.JavaExec
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.jvm.toolchain.JavaToolchainService
|
||||
import org.gradle.kotlin.dsl.assign
|
||||
import org.gradle.kotlin.dsl.create
|
||||
import org.gradle.kotlin.dsl.findByType
|
||||
import java.nio.file.Files
|
||||
|
||||
/**
|
||||
* Set [JavaExec] task to run a given [RunConfig].
|
||||
*
|
||||
* See also [RunExec].
|
||||
*/
|
||||
fun JavaExec.setRunConfig(config: Run) {
|
||||
mainClass.set(config.mainClass)
|
||||
workingDir = config.workingDirectory.get().asFile
|
||||
argumentProviders.add { config.programArguments.get() }
|
||||
jvmArgumentProviders.add { config.jvmArguments.get() }
|
||||
|
||||
environment(config.environmentVariables.get())
|
||||
systemProperties(config.systemProperties.get())
|
||||
|
||||
config.modSources.all().get().values().forEach { classpath(it.runtimeClasspath) }
|
||||
classpath(config.classpath)
|
||||
classpath(config.dependencies.get().runtimeConfiguration)
|
||||
|
||||
(config as RunImpl).taskDependencies.forEach { dependsOn(it) }
|
||||
|
||||
javaLauncher.set(
|
||||
project.extensions.getByType(JavaToolchainService::class.java)
|
||||
.launcherFor(project.extensions.getByType(JavaPluginExtension::class.java).toolchain),
|
||||
)
|
||||
|
||||
doFirst("Create working directory") { Files.createDirectories(workingDir.toPath()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new [Run.modSource] with a specific mod id.
|
||||
*/
|
||||
fun Run.modSourceAs(sourceSet: SourceSet, mod: String) {
|
||||
// NeoGradle requires a RunnableSourceSet to be present, so we inject it into other project's source sets.
|
||||
val runnable = sourceSet.extensions.findByType<RunnableSourceSet>() ?: run {
|
||||
val extension = sourceSet.extensions.create<RunnableSourceSet>(RunnableSourceSet.NAME, project)
|
||||
extension.modIdentifier = mod
|
||||
extension.modIdentifier.finalizeValueOnRead()
|
||||
extension
|
||||
}
|
||||
if (runnable.modIdentifier.get() != mod) throw IllegalArgumentException("Multiple mod identifiers")
|
||||
|
||||
modSource(sourceSet)
|
||||
}
|
@@ -25,13 +25,13 @@ as documentation for breaking changes and "gotchas" one should look out for betw
|
||||
|
||||
- Update to Lua 5.2:
|
||||
- Support for Lua 5.0's pseudo-argument `arg` has been removed. You should always use `...` for varargs.
|
||||
- Environments are no longer baked into the runtime, and instead use the `_ENV` local or upvalue. `getfenv`/`setfenv`
|
||||
now only work on Lua functions with an `_ENV` upvalue. `getfenv` will return the global environment when called
|
||||
with other functions, and `setfenv` will have no effect.
|
||||
- `load`/`loadstring` defaults to using the global environment (`_G`) rather than the current coroutine's
|
||||
- Environments are no longer baked into the runtime, and instead use the `_ENV` local or upvalue. [`getfenv`]/[`setfenv`]
|
||||
now only work on Lua functions with an `_ENV` upvalue. [`getfenv`] will return the global environment when called
|
||||
with other functions, and [`setfenv`] will have no effect.
|
||||
- [`load`]/[`loadstring`] defaults to using the global environment (`_G`) rather than the current coroutine's
|
||||
environment.
|
||||
- Support for dumping functions (`string.dump`) and loading binary chunks has been removed.
|
||||
- `math.random` now uses Lua 5.4's random number generator.
|
||||
- Support for dumping functions ([`string.dump`]) and loading binary chunks has been removed.
|
||||
- [`math.random`] now uses Lua 5.4's random number generator.
|
||||
|
||||
- File handles, HTTP requests and websockets now always use the original bytes rather than encoding/decoding to UTF-8.
|
||||
|
||||
@@ -44,7 +44,7 @@ as documentation for breaking changes and "gotchas" one should look out for betw
|
||||
`keys.enter` constant was queued when the key was pressed)
|
||||
|
||||
- Minecraft 1.13 removed the concept of item damage and block metadata (see ["The Flattening"][flattening]). As a
|
||||
result `turtle.inspect` no longer provides block metadata, and `turtle.getItemDetail` no longer provides damage.
|
||||
result [`turtle.inspect`] no longer provides block metadata, and [`turtle.getItemDetail`] no longer provides damage.
|
||||
|
||||
- Block states (`turtle.inspect().state`) should provide all the same information as block metadata, but in a much
|
||||
more understandable format.
|
||||
@@ -70,7 +70,7 @@ as documentation for breaking changes and "gotchas" one should look out for betw
|
||||
- Unlabelled computers and turtles now keep their ID when broken, meaning that unlabelled computers/items do not stack.
|
||||
|
||||
## ComputerCraft 1.80pr1 {#cc-1.80}
|
||||
- Programs run via `shell.run` are now started in their own isolated environment. This means globals set by programs
|
||||
- Programs run via [`shell.run`] are now started in their own isolated environment. This means globals set by programs
|
||||
will not be accessible outside of this program.
|
||||
|
||||
- Programs containing `/` are looked up in the current directory and are no longer looked up on the path. For instance,
|
||||
|
@@ -12,7 +12,7 @@ neogradle.subsystems.conventions.runs.enabled=false
|
||||
|
||||
# Mod properties
|
||||
isUnstable=true
|
||||
modVersion=1.111.0
|
||||
modVersion=1.111.1
|
||||
|
||||
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
|
||||
mcVersion=1.21
|
||||
|
@@ -9,7 +9,7 @@
|
||||
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
|
||||
fabric-api = "0.100.3+1.21"
|
||||
fabric-loader = "0.15.11"
|
||||
neoForge = "21.0.21-beta"
|
||||
neoForge = "21.0.42-beta"
|
||||
neoForgeSpi = "8.0.1"
|
||||
mixin = "0.8.5"
|
||||
parchment = "2024.06.16"
|
||||
@@ -60,18 +60,18 @@ checkstyle = "10.14.1"
|
||||
curseForgeGradle = "1.1.18"
|
||||
errorProne-core = "2.27.0"
|
||||
errorProne-plugin = "3.1.0"
|
||||
fabric-loom = "1.6.7"
|
||||
fabric-loom = "1.7.1"
|
||||
githubRelease = "2.5.2"
|
||||
gradleVersions = "0.50.0"
|
||||
ideaExt = "1.1.7"
|
||||
illuaminate = "0.1.0-73-g43ee16c"
|
||||
lwjgl = "3.3.3"
|
||||
minotaur = "2.8.7"
|
||||
neoGradle = "7.0.145"
|
||||
neoGradle = "7.0.152"
|
||||
nullAway = "0.10.25"
|
||||
spotless = "6.23.3"
|
||||
taskTree = "2.1.1"
|
||||
teavm = "0.10.0-SQUID.4"
|
||||
teavm = "0.11.0-SQUID.1"
|
||||
vanillaExtract = "0.1.3"
|
||||
versionCatalogUpdate = "0.8.1"
|
||||
|
||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
2
gradlew
vendored
2
gradlew
vendored
@@ -55,7 +55,7 @@
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
|
@@ -25,6 +25,7 @@ import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import dan200.computercraft.shared.media.items.DiskItem;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.item.ItemColor;
|
||||
@@ -53,6 +54,7 @@ import net.minecraft.world.level.ItemLike;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
@@ -143,15 +145,14 @@ public final class ClientRegistry {
|
||||
register.accept(GuiSprites.initialise(minecraft.getTextureManager()));
|
||||
}
|
||||
|
||||
private static final String[] EXTRA_MODELS = new String[]{
|
||||
"block/turtle_colour",
|
||||
"block/turtle_elf_overlay",
|
||||
"block/turtle_rainbow_overlay",
|
||||
"block/turtle_trans_overlay",
|
||||
private static final ResourceLocation[] EXTRA_MODELS = {
|
||||
TurtleOverlay.ELF_MODEL,
|
||||
TurtleBlockEntityRenderer.COLOUR_TURTLE_MODEL,
|
||||
};
|
||||
|
||||
public static void registerExtraModels(Consumer<ResourceLocation> register) {
|
||||
for (var model : EXTRA_MODELS) register.accept(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, model));
|
||||
public static void registerExtraModels(Consumer<ResourceLocation> register, Collection<ResourceLocation> extraModels) {
|
||||
for (var model : EXTRA_MODELS) register.accept(model);
|
||||
extraModels.forEach(register);
|
||||
TurtleUpgradeModellers.getDependencies().forEach(register);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,68 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.model;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A list of extra models to load on the client.
|
||||
* <p>
|
||||
* This is largely intended for use with {@linkplain TurtleOverlay turtle overlays}. As overlays are stored in a dynamic
|
||||
* registry, they are not available when resources are loaded, and so we need a way to request the overlays' models be
|
||||
* loaded.
|
||||
*
|
||||
* @param models The models to load.
|
||||
*/
|
||||
public record ExtraModels(List<ResourceLocation> models) {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ExtraModels.class);
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
/**
|
||||
* The path where the extra models are listed.
|
||||
*/
|
||||
public static final ResourceLocation PATH = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "extra_models.json");
|
||||
|
||||
/**
|
||||
* The coded used to store the extra model file.
|
||||
*/
|
||||
public static final Codec<ExtraModels> CODEC = ResourceLocation.CODEC.listOf().xmap(ExtraModels::new, ExtraModels::models);
|
||||
|
||||
/**
|
||||
* Get the list of all extra models to load.
|
||||
*
|
||||
* @param resources The current resource manager.
|
||||
* @return A set of all resources to load.
|
||||
*/
|
||||
public static Collection<ResourceLocation> loadAll(ResourceManager resources) {
|
||||
Set<ResourceLocation> out = new HashSet<>();
|
||||
|
||||
for (var path : resources.getResourceStack(PATH)) {
|
||||
ExtraModels models;
|
||||
try (var stream = path.openAsReader()) {
|
||||
models = ExtraModels.CODEC.parse(JsonOps.INSTANCE, GSON.fromJson(stream, JsonElement.class)).getOrThrow(JsonParseException::new);
|
||||
} catch (IOException | RuntimeException e) {
|
||||
LOG.error("Failed to load extra models from {}", path.sourcePackId());
|
||||
continue;
|
||||
}
|
||||
|
||||
out.addAll(models.models());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableCollection(out);
|
||||
}
|
||||
}
|
@@ -12,13 +12,14 @@ import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.render.TurtleBlockEntityRenderer;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import dan200.computercraft.shared.util.DataComponentUtil;
|
||||
import dan200.computercraft.shared.util.Holiday;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
@@ -52,7 +53,7 @@ public final class TurtleModelParts<T> {
|
||||
boolean colour,
|
||||
@Nullable UpgradeData<ITurtleUpgrade> leftUpgrade,
|
||||
@Nullable UpgradeData<ITurtleUpgrade> rightUpgrade,
|
||||
@Nullable ResourceLocation overlay,
|
||||
@Nullable TurtleOverlay overlay,
|
||||
boolean christmas,
|
||||
boolean flip
|
||||
) {
|
||||
@@ -113,10 +114,10 @@ public final class TurtleModelParts<T> {
|
||||
var parts = new ArrayList<BakedModel>(4);
|
||||
parts.add(transform(combo.colour() ? colourModel : familyModel, transformation));
|
||||
|
||||
var overlayModelLocation = TurtleBlockEntityRenderer.getTurtleOverlayModel(combo.overlay(), combo.christmas());
|
||||
if (overlayModelLocation != null) {
|
||||
parts.add(transform(ClientPlatformHelper.get().getModel(modelManager, overlayModelLocation), transformation));
|
||||
}
|
||||
if (combo.overlay() != null) addPart(parts, modelManager, transformation, combo.overlay().model());
|
||||
|
||||
var showChristmas = TurtleOverlay.showElfOverlay(combo.overlay(), combo.christmas());
|
||||
if (showChristmas) addPart(parts, modelManager, transformation, TurtleOverlay.ELF_MODEL);
|
||||
|
||||
addUpgrade(parts, transformation, TurtleSide.LEFT, combo.leftUpgrade());
|
||||
addUpgrade(parts, transformation, TurtleSide.RIGHT, combo.rightUpgrade());
|
||||
@@ -124,6 +125,10 @@ public final class TurtleModelParts<T> {
|
||||
return parts;
|
||||
}
|
||||
|
||||
private void addPart(List<BakedModel> parts, ModelManager modelManager, Transformation transformation, ResourceLocation model) {
|
||||
parts.add(transform(ClientPlatformHelper.get().getModel(modelManager, model), transformation));
|
||||
}
|
||||
|
||||
private void addUpgrade(List<BakedModel> parts, Transformation transformation, TurtleSide side, @Nullable UpgradeData<ITurtleUpgrade> upgrade) {
|
||||
if (upgrade == null) return;
|
||||
var model = TurtleUpgradeModellers.getModel(upgrade.upgrade(), upgrade.data(), side);
|
||||
|
@@ -11,6 +11,7 @@ import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.turtle.TurtleSide;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.Holiday;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -21,14 +22,14 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.CommonColors;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBlockEntity> {
|
||||
private static final ResourceLocation COLOUR_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
|
||||
private static final ResourceLocation ELF_OVERLAY_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_elf_overlay");
|
||||
public static final ResourceLocation COLOUR_TURTLE_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_colour");
|
||||
|
||||
private final BlockEntityRenderDispatcher renderer;
|
||||
private final Font font;
|
||||
@@ -38,12 +39,6 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
||||
font = context.getFont();
|
||||
}
|
||||
|
||||
public static @Nullable ResourceLocation getTurtleOverlayModel(@Nullable ResourceLocation overlay, boolean christmas) {
|
||||
if (overlay != null) return overlay;
|
||||
if (christmas) return ELF_OVERLAY_MODEL;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(TurtleBlockEntity turtle, float partialTicks, PoseStack transform, MultiBufferSource buffers, int lightmapCoord, int overlayLight) {
|
||||
transform.pushPose();
|
||||
@@ -62,13 +57,13 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
||||
transform.pushPose();
|
||||
transform.translate(0.5, 1.2, 0.5);
|
||||
transform.mulPose(mc.getEntityRenderDispatcher().cameraOrientation());
|
||||
transform.scale(-0.025f, -0.025f, 0.025f);
|
||||
transform.scale(0.025f, -0.025f, 0.025f);
|
||||
|
||||
var matrix = transform.last().pose();
|
||||
var opacity = (int) (mc.options.getBackgroundOpacity(0.25f) * 255) << 24;
|
||||
var width = -font.width(label) / 2.0f;
|
||||
font.drawInBatch(label, width, (float) 0, 0x20ffffff, false, matrix, buffers, Font.DisplayMode.SEE_THROUGH, opacity, lightmapCoord);
|
||||
font.drawInBatch(label, width, (float) 0, 0xffffffff, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
||||
font.drawInBatch(label, width, (float) 0, CommonColors.WHITE, false, matrix, buffers, Font.DisplayMode.NORMAL, 0, lightmapCoord);
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
@@ -98,10 +93,11 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
||||
}
|
||||
|
||||
// Render the overlay
|
||||
var overlayModel = getTurtleOverlayModel(overlay, Holiday.getCurrent() == Holiday.CHRISTMAS);
|
||||
if (overlayModel != null) {
|
||||
renderModel(transform, buffers, lightmapCoord, overlayLight, overlayModel, null);
|
||||
}
|
||||
if (overlay != null) renderModel(transform, buffers, lightmapCoord, overlayLight, overlay.model(), null);
|
||||
|
||||
// And the Christmas overlay.
|
||||
var showChristmas = TurtleOverlay.showElfOverlay(overlay, Holiday.getCurrent() == Holiday.CHRISTMAS);
|
||||
if (showChristmas) renderModel(transform, buffers, lightmapCoord, overlayLight, TurtleOverlay.ELF_MODEL, null);
|
||||
|
||||
// Render the upgrades
|
||||
renderUpgrade(transform, buffers, lightmapCoord, overlayLight, turtle, TurtleSide.LEFT, partialTicks);
|
||||
|
@@ -6,15 +6,18 @@ package dan200.computercraft.data.client;
|
||||
|
||||
import dan200.computercraft.client.gui.GuiSprites;
|
||||
import dan200.computercraft.data.DataProviders;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.inventory.UpgradeSlot;
|
||||
import net.minecraft.client.renderer.texture.atlas.SpriteSource;
|
||||
import net.minecraft.client.renderer.texture.atlas.SpriteSources;
|
||||
import net.minecraft.client.renderer.texture.atlas.sources.SingleFile;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
@@ -26,7 +29,7 @@ public final class ClientDataProviders {
|
||||
private ClientDataProviders() {
|
||||
}
|
||||
|
||||
public static void add(DataProviders.GeneratorSink generator) {
|
||||
public static void add(DataProviders.GeneratorSink generator, CompletableFuture<HolderLookup.Provider> registries) {
|
||||
generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> {
|
||||
out.accept(ResourceLocation.withDefaultNamespace("blocks"), List.of(
|
||||
new SingleFile(UpgradeSlot.LEFT_UPGRADE, Optional.empty()),
|
||||
@@ -44,5 +47,12 @@ public final class ClientDataProviders {
|
||||
GuiSprites.COMPUTER_COLOUR.textures()
|
||||
).flatMap(x -> x).<SpriteSource>map(x -> new SingleFile(x, Optional.empty())).toList());
|
||||
});
|
||||
|
||||
generator.add(pack -> new ExtraModelsProvider(pack, registries) {
|
||||
@Override
|
||||
public Stream<ResourceLocation> getModels(HolderLookup.Provider registries) {
|
||||
return registries.lookupOrThrow(TurtleOverlay.REGISTRY).listElements().map(x -> x.value().model());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.data.client;
|
||||
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import dan200.computercraft.client.model.ExtraModels;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.CachedOutput;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* A data provider to generate {@link ExtraModels}.
|
||||
*/
|
||||
abstract class ExtraModelsProvider implements DataProvider {
|
||||
private final Path path;
|
||||
private final CompletableFuture<HolderLookup.Provider> registries;
|
||||
|
||||
ExtraModelsProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
|
||||
path = output.getOutputFolder(PackOutput.Target.RESOURCE_PACK).resolve(ExtraModels.PATH.getNamespace()).resolve(ExtraModels.PATH.getPath());
|
||||
this.registries = registries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a stream of models to load.
|
||||
*
|
||||
* @param registries The current registries.
|
||||
* @return The collection of extra models to load.
|
||||
*/
|
||||
public abstract Stream<ResourceLocation> getModels(HolderLookup.Provider registries);
|
||||
|
||||
@Override
|
||||
public final CompletableFuture<?> run(CachedOutput output) {
|
||||
return registries.thenCompose(registries -> {
|
||||
var models = new ExtraModels(getModels(registries).sorted().toList());
|
||||
var json = ExtraModels.CODEC.encodeStart(JsonOps.INSTANCE, models).getOrThrow(IllegalStateException::new);
|
||||
return DataProvider.saveStable(output, json, path);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return "Extra Models";
|
||||
}
|
||||
}
|
1
projects/common/src/generated/resources/assets/computercraft/extra_models.json
generated
Normal file
1
projects/common/src/generated/resources/assets/computercraft/extra_models.json
generated
Normal file
@@ -0,0 +1 @@
|
||||
["computercraft:block/turtle_rainbow_overlay", "computercraft:block/turtle_trans_overlay"]
|
@@ -3,7 +3,7 @@
|
||||
"criteria": {
|
||||
"has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"},
|
||||
"has_the_recipe": {
|
||||
"conditions": {"recipe": "computercraft:turtle_advanced_overlays/turtle_trans_overlay"},
|
||||
"conditions": {"recipe": "computercraft:turtle_advanced_overlays/rainbow_flag"},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
},
|
||||
"has_turtle": {
|
||||
@@ -12,5 +12,5 @@
|
||||
}
|
||||
},
|
||||
"requirements": [["has_the_recipe", "has_turtle", "has_dye"]],
|
||||
"rewards": {"recipes": ["computercraft:turtle_advanced_overlays/turtle_trans_overlay"]}
|
||||
"rewards": {"recipes": ["computercraft:turtle_advanced_overlays/rainbow_flag"]}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
"criteria": {
|
||||
"has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"},
|
||||
"has_the_recipe": {
|
||||
"conditions": {"recipe": "computercraft:turtle_advanced_overlays/turtle_rainbow_overlay"},
|
||||
"conditions": {"recipe": "computercraft:turtle_advanced_overlays/trans_flag"},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
},
|
||||
"has_turtle": {
|
||||
@@ -12,5 +12,5 @@
|
||||
}
|
||||
},
|
||||
"requirements": [["has_the_recipe", "has_turtle", "has_dye"]],
|
||||
"rewards": {"recipes": ["computercraft:turtle_advanced_overlays/turtle_rainbow_overlay"]}
|
||||
"rewards": {"recipes": ["computercraft:turtle_advanced_overlays/trans_flag"]}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
"criteria": {
|
||||
"has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"},
|
||||
"has_the_recipe": {
|
||||
"conditions": {"recipe": "computercraft:turtle_normal_overlays/turtle_trans_overlay"},
|
||||
"conditions": {"recipe": "computercraft:turtle_normal_overlays/rainbow_flag"},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
},
|
||||
"has_turtle": {
|
||||
@@ -12,5 +12,5 @@
|
||||
}
|
||||
},
|
||||
"requirements": [["has_the_recipe", "has_turtle", "has_dye"]],
|
||||
"rewards": {"recipes": ["computercraft:turtle_normal_overlays/turtle_trans_overlay"]}
|
||||
"rewards": {"recipes": ["computercraft:turtle_normal_overlays/rainbow_flag"]}
|
||||
}
|
@@ -3,7 +3,7 @@
|
||||
"criteria": {
|
||||
"has_dye": {"conditions": {"items": [{"items": "#c:dyes"}]}, "trigger": "minecraft:inventory_changed"},
|
||||
"has_the_recipe": {
|
||||
"conditions": {"recipe": "computercraft:turtle_normal_overlays/turtle_rainbow_overlay"},
|
||||
"conditions": {"recipe": "computercraft:turtle_normal_overlays/trans_flag"},
|
||||
"trigger": "minecraft:recipe_unlocked"
|
||||
},
|
||||
"has_turtle": {
|
||||
@@ -12,5 +12,5 @@
|
||||
}
|
||||
},
|
||||
"requirements": [["has_the_recipe", "has_turtle", "has_dye"]],
|
||||
"rewards": {"recipes": ["computercraft:turtle_normal_overlays/turtle_rainbow_overlay"]}
|
||||
"rewards": {"recipes": ["computercraft:turtle_normal_overlays/trans_flag"]}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
{"model": "computercraft:block/turtle_rainbow_overlay", "show_elf_overlay": true}
|
@@ -0,0 +1 @@
|
||||
{"model": "computercraft:block/turtle_trans_overlay", "show_elf_overlay": true}
|
@@ -20,7 +20,7 @@
|
||||
{"item": "computercraft:turtle_advanced"}
|
||||
],
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_rainbow_overlay"},
|
||||
"components": {"computercraft:overlay": "computercraft:rainbow_flag"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_advanced"
|
||||
}
|
@@ -17,7 +17,7 @@
|
||||
{"item": "computercraft:turtle_advanced"}
|
||||
],
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_trans_overlay"},
|
||||
"components": {"computercraft:overlay": "computercraft:trans_flag"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_advanced"
|
||||
}
|
@@ -20,7 +20,7 @@
|
||||
{"item": "computercraft:turtle_normal"}
|
||||
],
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_rainbow_overlay"},
|
||||
"components": {"computercraft:overlay": "computercraft:rainbow_flag"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_normal"
|
||||
}
|
@@ -17,7 +17,7 @@
|
||||
{"item": "computercraft:turtle_normal"}
|
||||
],
|
||||
"result": {
|
||||
"components": {"computercraft:overlay": "computercraft:block/turtle_trans_overlay"},
|
||||
"components": {"computercraft:overlay": "computercraft:trans_flag"},
|
||||
"count": 1,
|
||||
"id": "computercraft:turtle_normal"
|
||||
}
|
@@ -7,6 +7,7 @@ package dan200.computercraft.data;
|
||||
import com.mojang.serialization.Codec;
|
||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.RegistrySetBuilder;
|
||||
@@ -38,6 +39,7 @@ public final class DataProviders {
|
||||
Util.make(new RegistrySetBuilder(), builder -> {
|
||||
builder.add(ITurtleUpgrade.REGISTRY, TurtleUpgradeProvider::addUpgrades);
|
||||
builder.add(IPocketUpgrade.REGISTRY, PocketUpgradeProvider::addUpgrades);
|
||||
builder.add(TurtleOverlay.REGISTRY, TurtleOverlays::register);
|
||||
}));
|
||||
var fullRegistries = fullRegistryPatch.thenApply(RegistrySetBuilder.PatchedRegistries::full);
|
||||
|
||||
@@ -57,7 +59,8 @@ public final class DataProviders {
|
||||
// and invoke that.
|
||||
try {
|
||||
Class.forName("dan200.computercraft.data.client.ClientDataProviders")
|
||||
.getMethod("add", GeneratorSink.class).invoke(null, generator);
|
||||
.getMethod("add", GeneratorSink.class, CompletableFuture.class)
|
||||
.invoke(null, generator, fullRegistries);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@@ -28,6 +28,7 @@ import dan200.computercraft.shared.recipe.ImpostorShapelessRecipe;
|
||||
import dan200.computercraft.shared.recipe.TransformShapedRecipe;
|
||||
import dan200.computercraft.shared.recipe.TransformShapelessRecipe;
|
||||
import dan200.computercraft.shared.recipe.function.CopyComponents;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||
import dan200.computercraft.shared.util.ColourUtils;
|
||||
@@ -45,6 +46,7 @@ import net.minecraft.data.recipes.RecipeCategory;
|
||||
import net.minecraft.data.recipes.RecipeOutput;
|
||||
import net.minecraft.data.recipes.ShapedRecipeBuilder;
|
||||
import net.minecraft.data.recipes.ShapelessRecipeBuilder;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.tags.TagKey;
|
||||
@@ -96,7 +98,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
diskColours(add);
|
||||
pocketUpgrades(add, registries);
|
||||
turtleUpgrades(add, registries);
|
||||
turtleOverlays(add);
|
||||
turtleOverlays(add, registries);
|
||||
|
||||
addSpecial(add, new DiskRecipe(CraftingBookCategory.MISC));
|
||||
addSpecial(add, new ColourableRecipe(CraftingBookCategory.MISC));
|
||||
@@ -189,8 +191,8 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private void turtleOverlays(RecipeOutput add) {
|
||||
turtleOverlay(add, "turtle_trans_overlay", x -> x
|
||||
private void turtleOverlays(RecipeOutput add, HolderLookup.Provider registries) {
|
||||
turtleOverlay(add, registries, TurtleOverlays.TRANS_FLAG, x -> x
|
||||
.unlockedBy("has_dye", inventoryChange(itemPredicate(ingredients.dye())))
|
||||
.requires(ColourUtils.getDyeTag(DyeColor.LIGHT_BLUE))
|
||||
.requires(ColourUtils.getDyeTag(DyeColor.PINK))
|
||||
@@ -198,7 +200,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.requires(Items.STICK)
|
||||
);
|
||||
|
||||
turtleOverlay(add, "turtle_rainbow_overlay", x -> x
|
||||
turtleOverlay(add, registries, TurtleOverlays.RAINBOW_FLAG, x -> x
|
||||
.unlockedBy("has_dye", inventoryChange(itemPredicate(ingredients.dye())))
|
||||
.requires(ColourUtils.getDyeTag(DyeColor.RED))
|
||||
.requires(ColourUtils.getDyeTag(DyeColor.ORANGE))
|
||||
@@ -210,14 +212,14 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
);
|
||||
}
|
||||
|
||||
private void turtleOverlay(RecipeOutput add, String overlay, Consumer<ShapelessSpecBuilder> build) {
|
||||
var overlayId = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/" + overlay);
|
||||
private void turtleOverlay(RecipeOutput add, HolderLookup.Provider registries, ResourceKey<TurtleOverlay> overlay, Consumer<ShapelessSpecBuilder> build) {
|
||||
var holder = registries.lookupOrThrow(overlay.registryKey()).getOrThrow(overlay);
|
||||
|
||||
for (var turtleItem : turtleItems()) {
|
||||
var name = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, turtleItem);
|
||||
|
||||
var builder = ShapelessSpecBuilder
|
||||
.shapeless(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.OVERLAY.get(), overlayId))
|
||||
.shapeless(RecipeCategory.REDSTONE, DataComponentUtil.createStack(turtleItem, ModRegistry.DataComponents.OVERLAY.get(), holder))
|
||||
.group(name.withSuffix("_overlay").toString())
|
||||
.unlockedBy("has_turtle", inventoryChange(turtleItem));
|
||||
build.accept(builder);
|
||||
@@ -226,7 +228,7 @@ final class RecipeProvider extends net.minecraft.data.recipes.RecipeProvider {
|
||||
.build(s -> new TransformShapelessRecipe(s, List.of(
|
||||
CopyComponents.builder(turtleItem).exclude(ModRegistry.DataComponents.OVERLAY.get()).build()
|
||||
)))
|
||||
.save(add, name.withSuffix("_overlays/" + overlay));
|
||||
.save(add, name.withSuffix("_overlays/" + overlay.location().getPath()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,38 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.data;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import net.minecraft.data.worldgen.BootstrapContext;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Built-in turtle overlays.
|
||||
*/
|
||||
final class TurtleOverlays {
|
||||
public static final ResourceKey<TurtleOverlay> RAINBOW_FLAG = create("rainbow_flag");
|
||||
public static final ResourceKey<TurtleOverlay> TRANS_FLAG = create("trans_flag");
|
||||
|
||||
private static ResourceKey<TurtleOverlay> create(String name) {
|
||||
return ResourceKey.create(TurtleOverlay.REGISTRY, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name));
|
||||
}
|
||||
|
||||
private TurtleOverlays() {
|
||||
}
|
||||
|
||||
public static void register(BootstrapContext<TurtleOverlay> registry) {
|
||||
registry.register(RAINBOW_FLAG, new TurtleOverlay(
|
||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_rainbow_overlay"),
|
||||
true
|
||||
));
|
||||
|
||||
registry.register(TRANS_FLAG, new TurtleOverlay(
|
||||
ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_trans_overlay"),
|
||||
true
|
||||
));
|
||||
}
|
||||
}
|
@@ -72,6 +72,7 @@ import dan200.computercraft.shared.recipe.*;
|
||||
import dan200.computercraft.shared.recipe.function.CopyComponents;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import dan200.computercraft.shared.turtle.FurnaceRefuelHandler;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
||||
@@ -95,7 +96,6 @@ import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.flag.FeatureFlags;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
@@ -320,8 +320,8 @@ public final class ModRegistry {
|
||||
/**
|
||||
* The overlay on a turtle.
|
||||
*/
|
||||
public static final RegistryEntry<DataComponentType<ResourceLocation>> OVERLAY = register("overlay", b -> b
|
||||
.persistent(ResourceLocation.CODEC).networkSynchronized(ResourceLocation.STREAM_CODEC)
|
||||
public static final RegistryEntry<DataComponentType<Holder<TurtleOverlay>>> OVERLAY = register("overlay", b -> b
|
||||
.persistent(TurtleOverlay.CODEC).networkSynchronized(TurtleOverlay.STREAM_CODEC)
|
||||
);
|
||||
|
||||
/**
|
||||
|
@@ -7,7 +7,6 @@ package dan200.computercraft.shared.computer.core;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import dan200.computercraft.api.filesystem.FileOperationException;
|
||||
import dan200.computercraft.core.filesystem.ArchiveMount;
|
||||
import dan200.computercraft.core.filesystem.FileSystem;
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
@@ -65,9 +64,10 @@ public final class ResourceMount extends ArchiveMount<ResourceMount.FileEntry> {
|
||||
existingNamespace = file.getNamespace();
|
||||
|
||||
if (!file.getNamespace().equals(namespace)) continue;
|
||||
if (!FileSystem.contains(subPath, file.getPath())) continue; // Some packs seem to include the parent?
|
||||
|
||||
var localPath = FileSystem.toLocal(file.getPath(), subPath);
|
||||
var localPath = getLocalPath(file.getPath(), subPath);
|
||||
if (localPath == null) continue;
|
||||
|
||||
try {
|
||||
getOrCreateChild(newRoot, localPath, this::createEntry);
|
||||
} catch (ResourceLocationException e) {
|
||||
|
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.turtle;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.util.Holiday;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.RegistryFileCodec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* A cosmetic overlay on a turtle.
|
||||
*
|
||||
* @param model The path to the overlay's model.
|
||||
* @param showElfOverlay Whether this overlay is compatible with the {@linkplain #ELF_MODEL Christmas elf model}.
|
||||
* @see ModRegistry.DataComponents#OVERLAY
|
||||
*/
|
||||
public record TurtleOverlay(ResourceLocation model, boolean showElfOverlay) {
|
||||
/**
|
||||
* The registry turtle overlays are stored in.
|
||||
*/
|
||||
public static final ResourceKey<Registry<TurtleOverlay>> REGISTRY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "turtle_overlay"));
|
||||
|
||||
/**
|
||||
* The codec used to read/write turtle overlay definitions from datapacks.
|
||||
*/
|
||||
public static final Codec<TurtleOverlay> DIRECT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
ResourceLocation.CODEC.fieldOf("model").forGetter(TurtleOverlay::model),
|
||||
Codec.BOOL.optionalFieldOf("show_elf_overlay", false).forGetter(TurtleOverlay::showElfOverlay)
|
||||
).apply(instance, TurtleOverlay::new));
|
||||
|
||||
/**
|
||||
* The codec used for {@link TurtleOverlay} instances.
|
||||
*
|
||||
* @see ModRegistry.DataComponents#OVERLAY
|
||||
*/
|
||||
public static final Codec<Holder<TurtleOverlay>> CODEC = RegistryFileCodec.create(REGISTRY, DIRECT_CODEC);
|
||||
|
||||
/**
|
||||
* The stream codec used for {@link TurtleOverlay} instances.
|
||||
*/
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, Holder<TurtleOverlay>> STREAM_CODEC = ByteBufCodecs.holder(REGISTRY, StreamCodec.composite(
|
||||
ResourceLocation.STREAM_CODEC, TurtleOverlay::model,
|
||||
ByteBufCodecs.BOOL, TurtleOverlay::showElfOverlay,
|
||||
TurtleOverlay::new
|
||||
));
|
||||
|
||||
/**
|
||||
* An additional overlay that is rendered on all turtles at {@linkplain Holiday#CHRISTMAS Christmas}.
|
||||
*
|
||||
* @see #showElfOverlay()
|
||||
* @see #showElfOverlay(TurtleOverlay, boolean)
|
||||
*/
|
||||
public static final ResourceLocation ELF_MODEL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "block/turtle_elf_overlay");
|
||||
|
||||
/**
|
||||
* Determine whether we should show the {@linkplain #ELF_MODEL elf overlay}.
|
||||
*
|
||||
* @param overlay The current {@link TurtleOverlay}.
|
||||
* @param christmas Whether it is Christmas.
|
||||
* @return Whether we should show the elf overlay.
|
||||
*/
|
||||
public static boolean showElfOverlay(@Nullable TurtleOverlay overlay, boolean christmas) {
|
||||
return christmas && (overlay == null || overlay.showElfOverlay());
|
||||
}
|
||||
}
|
@@ -20,6 +20,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.container.BasicContainer;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.apis.TurtleAPI;
|
||||
import dan200.computercraft.shared.turtle.core.TurtleBrain;
|
||||
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
|
||||
@@ -30,7 +31,6 @@ import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.core.component.DataComponentMap;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
@@ -222,8 +222,9 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
|
||||
return brain.getColour();
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getOverlay() {
|
||||
return brain.getOverlay();
|
||||
public @Nullable TurtleOverlay getOverlay() {
|
||||
var overlay = brain.getOverlay();
|
||||
return overlay == null ? null : overlay.value();
|
||||
}
|
||||
|
||||
public ITurtleAccess getAccess() {
|
||||
|
@@ -20,6 +20,7 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.container.InventoryDelegate;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.BlockEntityHelpers;
|
||||
import dan200.computercraft.shared.util.Holiday;
|
||||
@@ -32,7 +33,6 @@ import net.minecraft.core.component.DataComponentPatch;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.world.Container;
|
||||
@@ -74,7 +74,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
private int selectedSlot = 0;
|
||||
private int fuelLevel = 0;
|
||||
private int colourHex = -1;
|
||||
private @Nullable ResourceLocation overlay = null;
|
||||
private @Nullable Holder<TurtleOverlay> overlay = null;
|
||||
|
||||
private TurtleAnimation animation = TurtleAnimation.NONE;
|
||||
private int animationProgress = 0;
|
||||
@@ -134,7 +134,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
// Read fields
|
||||
colourHex = nbt.contains(NBT_COLOUR) ? nbt.getInt(NBT_COLOUR) : -1;
|
||||
fuelLevel = nbt.contains(NBT_FUEL) ? nbt.getInt(NBT_FUEL) : 0;
|
||||
overlay = nbt.contains(NBT_OVERLAY) ? ResourceLocation.parse(nbt.getString(NBT_OVERLAY)) : null;
|
||||
overlay = nbt.contains(NBT_OVERLAY) ? NBTUtil.decodeFrom(TurtleOverlay.CODEC, registries, nbt, NBT_OVERLAY) : null;
|
||||
|
||||
// Read upgrades
|
||||
setUpgradeDirect(TurtleSide.LEFT, NBTUtil.decodeFrom(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE));
|
||||
@@ -144,7 +144,7 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
nbt.putInt(NBT_FUEL, fuelLevel);
|
||||
if (colourHex != -1) nbt.putInt(NBT_COLOUR, colourHex);
|
||||
if (overlay != null) nbt.putString(NBT_OVERLAY, overlay.toString());
|
||||
if (overlay != null) NBTUtil.encodeTo(TurtleOverlay.CODEC, registries, nbt, NBT_OVERLAY, overlay);
|
||||
|
||||
// Write upgrades
|
||||
NBTUtil.encodeTo(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT));
|
||||
@@ -418,11 +418,11 @@ public class TurtleBrain implements TurtleAccessInternal {
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getOverlay() {
|
||||
public @Nullable Holder<TurtleOverlay> getOverlay() {
|
||||
return overlay;
|
||||
}
|
||||
|
||||
public void setOverlay(@Nullable ResourceLocation overlay) {
|
||||
public void setOverlay(@Nullable Holder<TurtleOverlay> overlay) {
|
||||
if (!Objects.equals(this.overlay, overlay)) {
|
||||
this.overlay = overlay;
|
||||
BlockEntityHelpers.updateBlock(owner);
|
||||
|
@@ -12,11 +12,11 @@ import dan200.computercraft.api.upgrades.UpgradeData;
|
||||
import dan200.computercraft.impl.TurtleUpgrades;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.computer.items.AbstractComputerItem;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlock;
|
||||
import net.minecraft.core.cauldron.CauldronInteraction;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.ItemInteractionResult;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.LayeredCauldronBlock;
|
||||
@@ -74,8 +74,9 @@ public class TurtleItem extends AbstractComputerItem {
|
||||
return stack.get(side == TurtleSide.LEFT ? ModRegistry.DataComponents.LEFT_TURTLE_UPGRADE.get() : ModRegistry.DataComponents.RIGHT_TURTLE_UPGRADE.get());
|
||||
}
|
||||
|
||||
public static @Nullable ResourceLocation getOverlay(ItemStack stack) {
|
||||
return stack.get(ModRegistry.DataComponents.OVERLAY.get());
|
||||
public static @Nullable TurtleOverlay getOverlay(ItemStack stack) {
|
||||
var overlay = stack.get(ModRegistry.DataComponents.OVERLAY.get());
|
||||
return overlay == null ? null : overlay.value();
|
||||
}
|
||||
|
||||
public static int getFuelLevel(ItemStack stack) {
|
||||
|
@@ -82,7 +82,8 @@ public class ComponentizationFixers {
|
||||
|
||||
if (item.is(TURTLES)) {
|
||||
item.moveTagToComponent("Fuel", "computercraft:fuel");
|
||||
item.moveTagToComponent("Overlay", "computercraft:overlay");
|
||||
|
||||
item.removeTag("Overlay").result().ifPresent(x -> item.setComponent("computercraft:overlay", fixOverlay(x)));
|
||||
|
||||
moveUpgradeToComponent(item, ops, "LeftUpgrade", "LeftUpgradeNbt", "computercraft:left_turtle_upgrade");
|
||||
moveUpgradeToComponent(item, ops, "RightUpgrade", "RightUpgradeNbt", "computercraft:right_turtle_upgrade");
|
||||
@@ -152,6 +153,7 @@ public class ComponentizationFixers {
|
||||
return typed -> typed.updateTyped(input, output, typed2 -> typed2.update(DSL.remainderFinder(), x -> {
|
||||
x = moveUpgradeData(x, "LeftUpgrade", "LeftUpgradeNbt");
|
||||
x = moveUpgradeData(x, "RightUpgrade", "RightUpgradeNbt");
|
||||
x = x.update("Overlay", ComponentizationFixers::fixOverlay);
|
||||
return x;
|
||||
}));
|
||||
}
|
||||
@@ -164,6 +166,20 @@ public class ComponentizationFixers {
|
||||
return ops.set(key, createUpgradeData(ops, upgradeId, ops.get(dataKey))).remove(dataKey);
|
||||
}
|
||||
|
||||
private static Dynamic<?> fixOverlay(Dynamic<?> overlay) {
|
||||
// Rewrite known overlays to their new ids.
|
||||
var overlayId = overlay.asString(null);
|
||||
if (overlayId == null) return overlay;
|
||||
|
||||
return switch (overlayId) {
|
||||
// Map known overlays to their new id.
|
||||
case "computercraft:block/turtle_trans_overlay" -> overlay.createString("computercraft:trans_flag");
|
||||
case "computercraft:block/turtle_rainbow_overlay" -> overlay.createString("computercraft:rainbow_flag");
|
||||
// And unknown overlays to a direct entry.
|
||||
default -> overlay.emptyMap().set("model", overlay);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new upgrade data.
|
||||
*
|
||||
|
@@ -1,38 +1,37 @@
|
||||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"particle": "computercraft:block/turtle_rainbow_overlay",
|
||||
"texture": "computercraft:block/turtle_rainbow_overlay"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Flag",
|
||||
"from": [1.5, 13, 10.5],
|
||||
"to": [2, 16.5, 15.5],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 6], "texture": "#texture"},
|
||||
"east": {"uv": [0, 0, 7, 6], "texture": "#texture"},
|
||||
"south": {"uv": [0, 0, 1, 6], "texture": "#texture"},
|
||||
"west": {"uv": [0, 0, 7, 6], "texture": "#texture"},
|
||||
"up": {"uv": [15, 0, 16, 6], "texture": "#texture"},
|
||||
"down": {"uv": [8, 0, 9, 6], "texture": "#texture"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Stick",
|
||||
"from": [1.5, 10.5, 10.5],
|
||||
"to": [2, 13, 11],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"east": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"south": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"west": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"up": {"uv": [12, 6, 13, 7], "texture": "#texture"},
|
||||
"down": {"uv": [13, 6, 14, 7], "texture": "#texture"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {}
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"particle": "computercraft:block/turtle_rainbow_overlay",
|
||||
"texture": "computercraft:block/turtle_rainbow_overlay"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Flag",
|
||||
"from": [1.5, 13.5, 10.5],
|
||||
"to": [2, 16.5, 15.5],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 6], "texture": "#texture"},
|
||||
"east": {"uv": [0, 0, 7, 6], "texture": "#texture"},
|
||||
"south": {"uv": [0, 0, 1, 6], "texture": "#texture"},
|
||||
"west": {"uv": [0, 0, 7, 6], "texture": "#texture"},
|
||||
"up": {"uv": [15, 0, 16, 6], "texture": "#texture"},
|
||||
"down": {"uv": [8, 0, 9, 6], "texture": "#texture"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Stick",
|
||||
"from": [1.5, 10.5, 10.5],
|
||||
"to": [2, 13.5, 11],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"east": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"south": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"west": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"up": {"uv": [12, 6, 13, 7], "texture": "#texture"},
|
||||
"down": {"uv": [13, 6, 14, 7], "texture": "#texture"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,38 +1,37 @@
|
||||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"particle": "computercraft:block/turtle_trans_overlay",
|
||||
"texture": "computercraft:block/turtle_trans_overlay"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Flag",
|
||||
"from": [1.5, 13.5, 10.5],
|
||||
"to": [2, 16.5, 15.5],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 5], "texture": "#texture"},
|
||||
"east": {"uv": [0, 0, 7, 5], "texture": "#texture"},
|
||||
"south": {"uv": [0, 0, 1, 5], "texture": "#texture"},
|
||||
"west": {"uv": [0, 0, 7, 5], "texture": "#texture"},
|
||||
"up": {"uv": [15, 0, 16, 5], "texture": "#texture"},
|
||||
"down": {"uv": [15, 0, 16, 5], "texture": "#texture"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Stick",
|
||||
"from": [1.5, 10.5, 10.5],
|
||||
"to": [2, 13.5, 11],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"east": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"south": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"west": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"up": {"uv": [12, 6, 13, 7], "texture": "#texture"},
|
||||
"down": {"uv": [13, 6, 14, 7], "texture": "#texture"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {}
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"particle": "computercraft:block/turtle_trans_overlay",
|
||||
"texture": "computercraft:block/turtle_trans_overlay"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"name": "Flag",
|
||||
"from": [1.5, 13.5, 10.5],
|
||||
"to": [2, 16, 15.5],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 1, 5], "texture": "#texture"},
|
||||
"east": {"uv": [0, 0, 7, 5], "texture": "#texture"},
|
||||
"south": {"uv": [0, 0, 1, 5], "texture": "#texture"},
|
||||
"west": {"uv": [0, 0, 7, 5], "texture": "#texture"},
|
||||
"up": {"uv": [15, 0, 16, 5], "texture": "#texture"},
|
||||
"down": {"uv": [15, 0, 16, 5], "texture": "#texture"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Stick",
|
||||
"from": [1.5, 10.5, 10.5],
|
||||
"to": [2, 13.5, 11],
|
||||
"rotation": {"angle": 22.5, "axis": "x", "origin": [2, 11, 10.75]},
|
||||
"faces": {
|
||||
"north": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"east": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"south": {"uv": [12, 0, 13, 6], "texture": "#texture"},
|
||||
"west": {"uv": [13, 0, 14, 6], "texture": "#texture"},
|
||||
"up": {"uv": [12, 6, 13, 7], "texture": "#texture"},
|
||||
"down": {"uv": [13, 6, 14, 7], "texture": "#texture"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@
|
||||
|
||||
package dan200.computercraft.gametest
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI
|
||||
import dan200.computercraft.api.detail.BasicItemDetailProvider
|
||||
import dan200.computercraft.api.detail.VanillaDetailRegistries
|
||||
import dan200.computercraft.api.lua.ObjectArguments
|
||||
@@ -21,7 +22,9 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableBlock
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlock
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorEdgeState
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay
|
||||
import dan200.computercraft.shared.turtle.apis.TurtleAPI
|
||||
import dan200.computercraft.shared.turtle.items.TurtleItem
|
||||
import dan200.computercraft.shared.util.WaterloggableHelpers
|
||||
import dan200.computercraft.test.core.assertArrayEquals
|
||||
import dan200.computercraft.test.core.computer.LuaTaskContext
|
||||
@@ -654,6 +657,27 @@ class Turtle_Test {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a structure created on an older version of the game, and checks that data fixers have been applied.
|
||||
*/
|
||||
@GameTest
|
||||
fun Data_fixers(helper: GameTestHelper) = helper.sequence {
|
||||
thenExecute {
|
||||
val overlay = helper.level.registryAccess().registryOrThrow(TurtleOverlay.REGISTRY)
|
||||
.get(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "trans_flag"))!!
|
||||
val upgrade = helper.level.registryAccess().registryOrThrow(ITurtleUpgrade.REGISTRY)
|
||||
.get(ResourceLocation.withDefaultNamespace("diamond_pickaxe"))!!
|
||||
|
||||
val turtleBe = helper.getBlockEntity(BlockPos(1, 2, 1), ModRegistry.BlockEntities.TURTLE_NORMAL.get())
|
||||
assertEquals(overlay, turtleBe.overlay)
|
||||
assertEquals(upgrade, turtleBe.getUpgrade(TurtleSide.LEFT))
|
||||
|
||||
val turtleItem = turtleBe.getItem(0)
|
||||
assertEquals(overlay, TurtleItem.getOverlay(turtleItem))
|
||||
assertEquals(upgrade, TurtleItem.getUpgrade(turtleItem, TurtleSide.LEFT))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `turtle.suck` only pulls for the current side.
|
||||
*/
|
||||
|
39
projects/common/src/testMod/resources/data/cctest/structures/turtle_test.data_fixers.snbt
generated
Normal file
39
projects/common/src/testMod/resources/data/cctest/structures/turtle_test.data_fixers.snbt
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
DataVersion: 3465,
|
||||
size: [3, 3, 3],
|
||||
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: [1, 0, 0], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 1], state: "minecraft:polished_andesite"},
|
||||
{pos: [1, 0, 2], 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: [0, 1, 0], state: "minecraft:air"},
|
||||
{pos: [0, 1, 1], state: "minecraft:air"},
|
||||
{pos: [0, 1, 2], state: "minecraft:air"},
|
||||
{pos: [1, 1, 0], state: "minecraft:air"},
|
||||
{pos: [1, 1, 1], state: "computercraft:turtle_normal{facing:south,waterlogged:false}", nbt: {ComputerId: 123, Fuel: 0, Items: [{Count: 1b, Slot: 0b, id: "computercraft:turtle_normal", tag: {ComputerId: 123, LeftUpgrade: "minecraft:diamond_pickaxe", Overlay: "computercraft:block/turtle_trans_overlay"}}], LeftUpgrade: "minecraft:diamond_pickaxe", LeftUpgradeNbt: {}, On: 0b, Overlay: "computercraft:block/turtle_trans_overlay", Owner: {LowerId: -4770154215762454977L, Name: "Player436", UpperId: 114963728012426084L}, Slot: 0, id: "computercraft:turtle_normal"}},
|
||||
{pos: [1, 1, 2], state: "minecraft:air"},
|
||||
{pos: [2, 1, 0], state: "minecraft:air"},
|
||||
{pos: [2, 1, 1], state: "minecraft:air"},
|
||||
{pos: [2, 1, 2], 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: [1, 2, 0], state: "minecraft:air"},
|
||||
{pos: [1, 2, 1], state: "minecraft:air"},
|
||||
{pos: [1, 2, 2], state: "minecraft:air"},
|
||||
{pos: [2, 2, 0], state: "minecraft:air"},
|
||||
{pos: [2, 2, 1], state: "minecraft:air"},
|
||||
{pos: [2, 2, 2], state: "minecraft:air"}
|
||||
],
|
||||
entities: [],
|
||||
palette: [
|
||||
"minecraft:polished_andesite",
|
||||
"minecraft:air",
|
||||
"computercraft:turtle_normal{facing:south,waterlogged:false}"
|
||||
]
|
||||
}
|
@@ -175,9 +175,9 @@ public class OSAPI implements ILuaAPI {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an alarm that will fire at the specified in-game time. When it
|
||||
* fires, * an {@code alarm} event will be added to the event queue with the
|
||||
* ID * returned from this function as the first parameter.
|
||||
* Sets an alarm that will fire at the specified {@linkplain #time(IArguments) in-game time}.
|
||||
* When it fires, an {@code alarm} event will be added to the event queue with the
|
||||
* ID returned from this function as the first parameter.
|
||||
*
|
||||
* @param time The time at which to fire the alarm, in the range [0.0, 24.0).
|
||||
* @return The ID of the new alarm. This can be used to filter the
|
||||
|
@@ -5,6 +5,7 @@
|
||||
package dan200.computercraft.core.computer.computerthread;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.errorprone.annotations.Keep;
|
||||
import dan200.computercraft.core.ComputerContext;
|
||||
import dan200.computercraft.core.Logging;
|
||||
import dan200.computercraft.core.computer.TimeoutState;
|
||||
@@ -774,6 +775,7 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
/**
|
||||
* The current state of this worker.
|
||||
*/
|
||||
@Keep
|
||||
private volatile ExecutorState $state = ExecutorState.IDLE;
|
||||
|
||||
/**
|
||||
@@ -784,6 +786,7 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
* {@linkplain #afterWork()} finishes executing, we set this back to null and compute the difference between the
|
||||
* two, updating the {@link Metrics#JAVA_ALLOCATION} metric.
|
||||
*/
|
||||
@Keep
|
||||
private volatile @Nullable ThreadAllocation $threadAllocation = null;
|
||||
|
||||
/**
|
||||
|
@@ -8,6 +8,7 @@ import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import dan200.computercraft.core.apis.handles.ArrayByteChannel;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -82,6 +83,24 @@ public abstract class ArchiveMount<T extends ArchiveMount.FileEntry<T>> extends
|
||||
*/
|
||||
protected abstract byte[] getFileContents(String path, T file) throws IOException;
|
||||
|
||||
/**
|
||||
* Convert an absolute path to one relative to {@code root}. If this path is not a child of {@code root}, return
|
||||
* {@code null}.
|
||||
*
|
||||
* @param path The full path.
|
||||
* @param root The root directory to be relative to.
|
||||
* @return The relativised path, or {@code null}.
|
||||
*/
|
||||
protected static @Nullable String getLocalPath(String path, String root) {
|
||||
// Some packs seem to include files not under the root, so drop them immediately.
|
||||
if (!path.startsWith(root)) return null;
|
||||
|
||||
if (path.length() == root.length()) return "";
|
||||
|
||||
if (path.charAt(root.length()) != '/') return null;
|
||||
return path.substring(root.length() + 1);
|
||||
}
|
||||
|
||||
protected static class FileEntry<T extends FileEntry<T>> extends AbstractInMemoryMount.FileEntry<T> {
|
||||
long size = -1;
|
||||
}
|
||||
|
@@ -224,11 +224,11 @@ public class FileSystem {
|
||||
public synchronized void copy(String sourcePath, String destPath) throws FileSystemException {
|
||||
sourcePath = sanitizePath(sourcePath);
|
||||
destPath = sanitizePath(destPath);
|
||||
if (isReadOnly(destPath)) throw new FileSystemException("/" + destPath + ": " + ACCESS_DENIED);
|
||||
if (!exists(sourcePath)) throw new FileSystemException("/" + sourcePath + ": " + NO_SUCH_FILE);
|
||||
if (exists(destPath)) throw new FileSystemException("/" + destPath + ": " + FILE_EXISTS);
|
||||
if (isReadOnly(destPath)) throw new FileSystemException(destPath, ACCESS_DENIED);
|
||||
if (!exists(sourcePath)) throw new FileSystemException(sourcePath, NO_SUCH_FILE);
|
||||
if (exists(destPath)) throw new FileSystemException(destPath, FILE_EXISTS);
|
||||
if (contains(sourcePath, destPath)) {
|
||||
throw new FileSystemException("/" + sourcePath + ": Can't copy a directory inside itself");
|
||||
throw new FileSystemException(sourcePath, "Can't copy a directory inside itself");
|
||||
}
|
||||
copyRecursive(sourcePath, getMount(sourcePath), destPath, getMount(destPath), 0);
|
||||
}
|
||||
@@ -341,7 +341,7 @@ public class FileSystem {
|
||||
}
|
||||
}
|
||||
if (match == null) {
|
||||
throw new FileSystemException("/" + path + ": Invalid Path");
|
||||
throw new FileSystemException(path, "Invalid Path");
|
||||
}
|
||||
return match;
|
||||
}
|
||||
@@ -404,7 +404,7 @@ public class FileSystem {
|
||||
return String.join("/", outputParts);
|
||||
}
|
||||
|
||||
public static boolean contains(String pathA, String pathB) {
|
||||
private static boolean contains(String pathA, String pathB) {
|
||||
pathA = sanitizePath(pathA).toLowerCase(Locale.ROOT);
|
||||
pathB = sanitizePath(pathB).toLowerCase(Locale.ROOT);
|
||||
|
||||
@@ -421,7 +421,7 @@ public class FileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
public static String toLocal(String path, String location) {
|
||||
static String toLocal(String path, String location) {
|
||||
path = sanitizePath(path);
|
||||
location = sanitizePath(location);
|
||||
|
||||
|
@@ -13,8 +13,12 @@ public class FileSystemException extends Exception {
|
||||
@Serial
|
||||
private static final long serialVersionUID = -2500631644868104029L;
|
||||
|
||||
FileSystemException(String s) {
|
||||
super(s);
|
||||
FileSystemException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
FileSystemException(String path, String message) {
|
||||
this("/" + path + ": " + message);
|
||||
}
|
||||
|
||||
public static FileSystemException of(IOException e) {
|
||||
|
@@ -49,10 +49,9 @@ public final class JarMount extends ArchiveMount<JarMount.FileEntry> implements
|
||||
while (zipEntries.hasMoreElements()) {
|
||||
var entry = zipEntries.nextElement();
|
||||
|
||||
var entryPath = entry.getName();
|
||||
if (!entryPath.startsWith(subPath)) continue;
|
||||
var localPath = getLocalPath(entry.getName(), subPath);
|
||||
if (localPath == null) continue;
|
||||
|
||||
var localPath = FileSystem.toLocal(entryPath, subPath);
|
||||
getOrCreateChild(root, localPath, x -> new FileEntry()).setup(entry);
|
||||
}
|
||||
}
|
||||
|
@@ -129,7 +129,7 @@ class MountWrapper {
|
||||
}
|
||||
|
||||
public void makeDirectory(String path) throws FileSystemException {
|
||||
if (writableMount == null) throw exceptionOf(path, ACCESS_DENIED);
|
||||
if (writableMount == null) throw new FileSystemException(path, ACCESS_DENIED);
|
||||
|
||||
path = toLocal(path);
|
||||
try {
|
||||
@@ -140,7 +140,7 @@ class MountWrapper {
|
||||
}
|
||||
|
||||
public void delete(String path) throws FileSystemException {
|
||||
if (writableMount == null) throw exceptionOf(path, ACCESS_DENIED);
|
||||
if (writableMount == null) throw new FileSystemException(path, ACCESS_DENIED);
|
||||
|
||||
path = toLocal(path);
|
||||
try {
|
||||
@@ -151,7 +151,7 @@ class MountWrapper {
|
||||
}
|
||||
|
||||
public void rename(String source, String dest) throws FileSystemException {
|
||||
if (writableMount == null) throw exceptionOf(source, ACCESS_DENIED);
|
||||
if (writableMount == null) throw new FileSystemException(source, ACCESS_DENIED);
|
||||
|
||||
source = toLocal(source);
|
||||
dest = toLocal(dest);
|
||||
@@ -168,7 +168,7 @@ class MountWrapper {
|
||||
}
|
||||
|
||||
public SeekableByteChannel openForWrite(String path, Set<OpenOption> options) throws FileSystemException {
|
||||
if (writableMount == null) throw exceptionOf(path, ACCESS_DENIED);
|
||||
if (writableMount == null) throw new FileSystemException(path, ACCESS_DENIED);
|
||||
|
||||
path = toLocal(path);
|
||||
try {
|
||||
@@ -206,10 +206,6 @@ class MountWrapper {
|
||||
|
||||
private FileSystemException localExceptionOf(String path, String message) {
|
||||
if (!location.isEmpty()) path = path.isEmpty() ? location : location + "/" + path;
|
||||
return exceptionOf(path, message);
|
||||
}
|
||||
|
||||
private static FileSystemException exceptionOf(String path, String message) {
|
||||
return new FileSystemException("/" + path + ": " + message);
|
||||
return new FileSystemException(path, message);
|
||||
}
|
||||
}
|
||||
|
@@ -1,3 +1,13 @@
|
||||
# New features in CC: Tweaked 1.111.1
|
||||
|
||||
* Add support for data-driven turtle upgrades.
|
||||
|
||||
Several bug fixes:
|
||||
* Fix monitors not rendering on NeoForge.
|
||||
* Fix turtle labels not rendering.
|
||||
* Fix compatibility with newer versions of NeoForge.
|
||||
* Fix heights of turtle flags.
|
||||
|
||||
# New features in CC: Tweaked 1.111.0
|
||||
|
||||
* Update several translations (Ale32bit).
|
||||
|
@@ -1,13 +1,11 @@
|
||||
New features in CC: Tweaked 1.111.0
|
||||
New features in CC: Tweaked 1.111.1
|
||||
|
||||
* Update several translations (Ale32bit).
|
||||
* Split up turtle textures into individual textures.
|
||||
* Add `r+`/`w+` support to the `io` library.
|
||||
* Warn when capabilities are not registered and Optifine is installed.
|
||||
* Add support for data-driven turtle upgrades.
|
||||
|
||||
Several bug fixes:
|
||||
* Allow planks to be used for building in "adventure" (dan200).
|
||||
* Fix `disk.getAudioTitle()` returning untranslated strings for some modded discs.
|
||||
* Fix crash when right clicking turtles in spectator.
|
||||
* Fix monitors not rendering on NeoForge.
|
||||
* Fix turtle labels not rendering.
|
||||
* Fix compatibility with newer versions of NeoForge.
|
||||
* Fix heights of turtle flags.
|
||||
|
||||
Type "help changelog" to see the full version history.
|
||||
|
@@ -53,7 +53,7 @@ public class ComputerCraftClient {
|
||||
ClientRegistry.registerMainThread(ItemProperties::register);
|
||||
|
||||
PreparableModelLoadingPlugin.register(CustomModelLoader::prepare, (state, context) -> {
|
||||
ClientRegistry.registerExtraModels(context::addModels);
|
||||
ClientRegistry.registerExtraModels(context::addModels, state.getExtraModels());
|
||||
context.resolveModel().register(ctx -> state.loadModel(ctx.id()));
|
||||
context.modifyModelAfterBake().register((model, ctx) -> model == null ? null : state.wrapModel(ctx, model));
|
||||
});
|
||||
|
@@ -25,6 +25,7 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -46,13 +47,15 @@ public final class CustomModelLoader {
|
||||
|
||||
private final Map<ResourceLocation, UnbakedModel> models = new HashMap<>();
|
||||
private final Map<ResourceLocation, String> emissiveModels = new HashMap<>();
|
||||
private final Collection<ResourceLocation> extraModels;
|
||||
|
||||
private CustomModelLoader() {
|
||||
private CustomModelLoader(Collection<ResourceLocation> extraModels) {
|
||||
this.extraModels = extraModels;
|
||||
}
|
||||
|
||||
public static CompletableFuture<CustomModelLoader> prepare(ResourceManager resources, Executor executor) {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
var loader = new CustomModelLoader();
|
||||
var loader = new CustomModelLoader(ExtraModels.loadAll(resources));
|
||||
for (var resource : resources.listResources("models", x -> x.getNamespace().equals(ComputerCraftAPI.MOD_ID) && x.getPath().endsWith(".json")).entrySet()) {
|
||||
loader.loadModel(resource.getKey(), resource.getValue());
|
||||
}
|
||||
@@ -85,6 +88,10 @@ public final class CustomModelLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<ResourceLocation> getExtraModels() {
|
||||
return extraModels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a custom model. This searches for CC models with a custom {@code loader} field.
|
||||
*
|
||||
|
@@ -25,6 +25,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEnt
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity;
|
||||
import dan200.computercraft.shared.platform.FabricConfigFile;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
@@ -70,6 +71,7 @@ public class ComputerCraft {
|
||||
|
||||
DynamicRegistries.registerSynced(ITurtleUpgrade.REGISTRY, TurtleUpgrades.instance().upgradeCodec());
|
||||
DynamicRegistries.registerSynced(IPocketUpgrade.REGISTRY, PocketUpgrades.instance().upgradeCodec());
|
||||
DynamicRegistries.registerSynced(TurtleOverlay.REGISTRY, TurtleOverlay.DIRECT_CODEC);
|
||||
|
||||
ModRegistry.register();
|
||||
ModRegistry.registerMainThread();
|
||||
|
@@ -40,7 +40,7 @@ runs {
|
||||
systemProperty("forge.logging.console.level", "debug")
|
||||
|
||||
cct.sourceDirectories.get().forEach {
|
||||
if (it.classes) modSourceAs(it.sourceSet, "computercraft")
|
||||
if (it.classes) modSources.add("computercraft", it.sourceSet)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -74,7 +74,7 @@ runs {
|
||||
|
||||
modSource(sourceSets.testMod.get())
|
||||
modSource(sourceSets.testFixtures.get())
|
||||
modSourceAs(project(":core").sourceSets.testFixtures.get(), "cctest")
|
||||
modSources.add("cctest", project(":core").sourceSets.testFixtures.get())
|
||||
|
||||
jvmArgument("-ea")
|
||||
|
||||
@@ -199,7 +199,7 @@ val runGametest by tasks.registering(JavaExec::class) {
|
||||
dependsOn("cleanRunGametest")
|
||||
usesService(MinecraftRunnerService.get(gradle))
|
||||
|
||||
setRunConfig(runs["gameTestServer"])
|
||||
copyFromTask("runGameTestServer")
|
||||
|
||||
systemProperty("forge.logging.console.level", "info")
|
||||
systemProperty("cctest.gametest-report", layout.buildDirectory.dir("test-results/$name.xml").getAbsolutePath())
|
||||
|
@@ -6,6 +6,7 @@ package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.turtle.RegisterTurtleModellersEvent;
|
||||
import dan200.computercraft.client.model.ExtraModels;
|
||||
import dan200.computercraft.client.model.turtle.TurtleModelLoader;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -57,7 +58,8 @@ public final class ForgeClientRegistry {
|
||||
@SubscribeEvent
|
||||
public static void registerModels(ModelEvent.RegisterAdditional event) {
|
||||
gatherModellers();
|
||||
ClientRegistry.registerExtraModels(x -> event.register(ModelResourceLocation.standalone(x)));
|
||||
var extraModels = ExtraModels.loadAll(Minecraft.getInstance().getResourceManager());
|
||||
ClientRegistry.registerExtraModels(x -> event.register(ModelResourceLocation.standalone(x)), extraModels);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@@ -33,6 +33,7 @@ import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEnt
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity;
|
||||
import dan200.computercraft.shared.platform.ForgeConfigFile;
|
||||
import dan200.computercraft.shared.recipe.function.RecipeFunction;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@@ -92,6 +93,7 @@ public final class ComputerCraft {
|
||||
public static void registerDynamicRegistries(DataPackRegistryEvent.NewRegistry event) {
|
||||
event.dataPackRegistry(ITurtleUpgrade.REGISTRY, TurtleUpgrades.instance().upgradeCodec(), TurtleUpgrades.instance().upgradeCodec());
|
||||
event.dataPackRegistry(IPocketUpgrade.REGISTRY, PocketUpgrades.instance().upgradeCodec(), PocketUpgrades.instance().upgradeCodec());
|
||||
event.dataPackRegistry(TurtleOverlay.REGISTRY, TurtleOverlay.DIRECT_CODEC, TurtleOverlay.DIRECT_CODEC);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@@ -38,7 +38,7 @@ public class ForgeCommonHooks {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onServerTick(ServerTickEvent.Post event) {
|
||||
CommonHooks.onServerTickStart(event.getServer());
|
||||
CommonHooks.onServerTickEnd();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@@ -54,8 +54,8 @@ import net.neoforged.neoforge.capabilities.BlockCapability;
|
||||
import net.neoforged.neoforge.capabilities.BlockCapabilityCache;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.common.CommonHooks;
|
||||
import net.neoforged.neoforge.common.ItemAbilities;
|
||||
import net.neoforged.neoforge.common.Tags;
|
||||
import net.neoforged.neoforge.common.ToolActions;
|
||||
import net.neoforged.neoforge.common.extensions.IMenuTypeExtension;
|
||||
import net.neoforged.neoforge.event.EventHooks;
|
||||
import net.neoforged.neoforge.items.wrapper.InvWrapper;
|
||||
@@ -211,7 +211,7 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
|
||||
@Override
|
||||
public boolean hasToolUsage(ItemStack stack) {
|
||||
return stack.canPerformAction(ToolActions.SHOVEL_FLATTEN) || stack.canPerformAction(ToolActions.HOE_TILL);
|
||||
return stack.canPerformAction(ItemAbilities.SHOVEL_FLATTEN) || stack.canPerformAction(ItemAbilities.HOE_TILL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -360,13 +360,13 @@ public class Main {
|
||||
|
||||
// And our VBA
|
||||
var termVertexArray = gl.createVertexArray("Terminal VAO");
|
||||
glEnableVertexArrayAttrib(termVertexArray, 0);
|
||||
glVertexArrayAttribFormat(termVertexArray, 0, 2, GL_FLOAT, false, 0); // Position
|
||||
glEnableVertexArrayAttrib(termVertexArray, 1);
|
||||
glVertexArrayAttribFormat(termVertexArray, 1, 2, GL_FLOAT, false, 8); // UV
|
||||
glEnableVertexArrayAttrib(termVertexArray, ATTRIBUTE_POSITION);
|
||||
glVertexArrayAttribFormat(termVertexArray, ATTRIBUTE_POSITION, 2, GL_FLOAT, false, 0); // Position
|
||||
glEnableVertexArrayAttrib(termVertexArray, ATTRIBUTE_UV);
|
||||
glVertexArrayAttribFormat(termVertexArray, ATTRIBUTE_UV, 2, GL_FLOAT, false, 8); // UV
|
||||
// FIXME: Can we merge this into one call?
|
||||
glVertexArrayVertexBuffer(termVertexArray, 0, termVertices, 0, 16);
|
||||
glVertexArrayVertexBuffer(termVertexArray, 1, termVertices, 0, 16);
|
||||
glVertexArrayVertexBuffer(termVertexArray, ATTRIBUTE_POSITION, termVertices, 0, 16);
|
||||
glVertexArrayVertexBuffer(termVertexArray, ATTRIBUTE_UV, termVertices, 0, 16);
|
||||
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
|
@@ -27,7 +27,7 @@ pluginManagement {
|
||||
}
|
||||
}
|
||||
|
||||
maven("https://squiddev.cc/maven") {
|
||||
maven("https://maven.squiddev.cc") {
|
||||
name = "SquidDev"
|
||||
content {
|
||||
includeGroup("cc.tweaked.vanilla-extract")
|
||||
|
Reference in New Issue
Block a user