diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 56263f1c2..0b7a516e6 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -11,6 +11,7 @@ body: - 1.16.x - 1.18.x - 1.19.x + - 1.20.x validations: required: true - type: input diff --git a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts index 9279f11aa..d8dfb6b4e 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.java-convention.gradle.kts @@ -104,6 +104,7 @@ tasks.withType(JavaCompile::class.java).configureEach { tasks.processResources { exclude("**/*.license") + exclude(".cache") } tasks.withType(AbstractArchiveTask::class.java).configureEach { diff --git a/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts index ecd66e9c3..605a4b1a7 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.mod-publishing.gradle.kts @@ -33,7 +33,6 @@ val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) { enabled = apiToken != "" val mainFile = upload("282001", modPublishing.output.get().archiveFile) - dependsOn(modPublishing.output) // See https://github.com/Darkhax/CurseForgeGradle/pull/7. mainFile.changelog = "Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)." mainFile.changelogType = "markdown" diff --git a/buildSrc/src/main/kotlin/cc-tweaked.publishing.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.publishing.gradle.kts index 8b1ae5523..08cec53e8 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.publishing.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.publishing.gradle.kts @@ -2,8 +2,6 @@ // // SPDX-License-Identifier: MPL-2.0 -import org.gradle.kotlin.dsl.`maven-publish` - plugins { `java-library` `maven-publish` diff --git a/gradle.properties b/gradle.properties index f395aa0f3..31d73d2bb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -10,7 +10,7 @@ kotlin.jvm.target.validation.mode=error # Mod properties isUnstable=false -modVersion=1.104.0 +modVersion=1.105.0 # Minecraft properties: We want to configure this here so we can read it in settings.gradle mcVersion=1.19.4 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fa3ffc7c3..e13ca1c60 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -50,7 +50,7 @@ junit = "5.9.2" # Build tools cctJavadoc = "1.7.0" checkstyle = "10.3.4" -curseForgeGradle = "1.0.11" +curseForgeGradle = "1.0.14" errorProne-core = "2.18.0" errorProne-plugin = "3.0.1" fabric-loom = "1.1.10" diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java index 761b8b6be..3ef11c7ab 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -75,7 +75,9 @@ public interface ITurtleAccess { * @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); /** @@ -84,7 +86,9 @@ public interface ITurtleAccess { * @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); /** diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java index 8797aee88..7178e8a3a 100644 --- a/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java +++ b/projects/common-api/src/main/java/dan200/computercraft/api/upgrades/UpgradeDataProvider.java @@ -24,6 +24,7 @@ import org.apache.logging.log4j.Logger; import javax.annotation.Nullable; import java.util.ArrayList; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -104,7 +105,7 @@ public abstract class UpgradeDataProvider> addUpgrade); @Override - public final CompletableFuture run(CachedOutput cache) { + public CompletableFuture run(CachedOutput cache) { var base = output.getOutputFolder().resolve("data"); Set seen = new HashSet<>(); @@ -127,7 +128,7 @@ public abstract class UpgradeDataProvider * Each message written gets a special {@link GuiMessageTag}, so we can remove the previous table of the same - * {@link TableBuilder#getId() id}. + * {@linkplain TableBuilder#getId() id}. */ public class ClientTableFormatter implements TableFormatter { public static final ClientTableFormatter INSTANCE = new ClientTableFormatter(); diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/TurtleScreen.java b/projects/common/src/client/java/dan200/computercraft/client/gui/TurtleScreen.java index f99bc32ac..f31ff8ab1 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/gui/TurtleScreen.java +++ b/projects/common/src/client/java/dan200/computercraft/client/gui/TurtleScreen.java @@ -26,9 +26,11 @@ public class TurtleScreen extends AbstractComputerScreen { private static final ResourceLocation BACKGROUND_NORMAL = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/turtle_normal.png"); private static final ResourceLocation BACKGROUND_ADVANCED = new ResourceLocation(ComputerCraftAPI.MOD_ID, "textures/gui/turtle_advanced.png"); - private static final int TEX_WIDTH = 254; + private static final int TEX_WIDTH = 278; private static final int TEX_HEIGHT = 217; + private static final int FULL_TEX_SIZE = 512; + public TurtleScreen(TurtleMenu container, Inventory player, Component title) { super(container, player, title, BORDER); @@ -45,16 +47,16 @@ public class TurtleScreen extends AbstractComputerScreen { protected void renderBg(PoseStack transform, float partialTicks, int mouseX, int mouseY) { var advanced = family == ComputerFamily.ADVANCED; RenderSystem.setShaderTexture(0, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL); - blit(transform, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0, TEX_WIDTH, TEX_HEIGHT); + blit(transform, leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0, 0, TEX_WIDTH, TEX_HEIGHT, FULL_TEX_SIZE, FULL_TEX_SIZE); + // Render selected slot var slot = getMenu().getSelectedSlot(); if (slot >= 0) { - RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); var slotX = slot % 4; var slotY = slot / 4; blit(transform, - leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, - 0, 217, 24, 24 + 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 ); } diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java b/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java index 7f53bb569..6d6588e7e 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java +++ b/projects/common/src/client/java/dan200/computercraft/client/gui/widgets/TerminalWidget.java @@ -15,6 +15,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.narration.NarratedElementType; import net.minecraft.client.gui.narration.NarrationElementOutput; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.network.chat.Component; import org.lwjgl.glfw.GLFW; @@ -81,6 +82,11 @@ public class TerminalWidget extends AbstractWidget { @Override public boolean keyPressed(int key, int scancode, int modifiers) { if (key == GLFW.GLFW_KEY_ESCAPE) return false; + if (Screen.isPaste(key)) { + paste(); + return true; + } + if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0) { switch (key) { case GLFW.GLFW_KEY_T -> { @@ -92,32 +98,6 @@ public class TerminalWidget extends AbstractWidget { case GLFW.GLFW_KEY_R -> { if (rebootTimer < 0) rebootTimer = 0; } - case GLFW.GLFW_KEY_V -> { - // Ctrl+V for paste - var clipboard = Minecraft.getInstance().keyboardHandler.getClipboard(); - if (clipboard != null) { - // Clip to the first occurrence of \r or \n - var newLineIndex1 = clipboard.indexOf("\r"); - var newLineIndex2 = clipboard.indexOf("\n"); - if (newLineIndex1 >= 0 && newLineIndex2 >= 0) { - clipboard = clipboard.substring(0, Math.min(newLineIndex1, newLineIndex2)); - } else if (newLineIndex1 >= 0) { - clipboard = clipboard.substring(0, newLineIndex1); - } else if (newLineIndex2 >= 0) { - clipboard = clipboard.substring(0, newLineIndex2); - } - - // Filter the string - clipboard = SharedConstants.filterText(clipboard); - if (!clipboard.isEmpty()) { - // Clip to 512 characters and queue the event - if (clipboard.length() > 512) clipboard = clipboard.substring(0, 512); - computer.queueEvent("paste", new Object[]{ clipboard }); - } - - return true; - } - } } } @@ -131,6 +111,29 @@ public class TerminalWidget extends AbstractWidget { return true; } + private void paste() { + var clipboard = Minecraft.getInstance().keyboardHandler.getClipboard(); + + // Clip to the first occurrence of \r or \n + var newLineIndex1 = clipboard.indexOf('\r'); + var newLineIndex2 = clipboard.indexOf('\n'); + if (newLineIndex1 >= 0 && newLineIndex2 >= 0) { + clipboard = clipboard.substring(0, Math.min(newLineIndex1, newLineIndex2)); + } else if (newLineIndex1 >= 0) { + clipboard = clipboard.substring(0, newLineIndex1); + } else if (newLineIndex2 >= 0) { + clipboard = clipboard.substring(0, newLineIndex2); + } + + // Filter the string + clipboard = SharedConstants.filterText(clipboard); + if (!clipboard.isEmpty()) { + // Clip to 512 characters and queue the event + if (clipboard.length() > 512) clipboard = clipboard.substring(0, 512); + computer.queueEvent("paste", new Object[]{ clipboard }); + } + } + @Override public boolean keyReleased(int key, int scancode, int modifiers) { // Queue the "key_up" event and remove from the down set diff --git a/projects/common/src/client/java/dan200/computercraft/data/client/ClientDataProviders.java b/projects/common/src/client/java/dan200/computercraft/data/client/ClientDataProviders.java new file mode 100644 index 000000000..61d4dd6cf --- /dev/null +++ b/projects/common/src/client/java/dan200/computercraft/data/client/ClientDataProviders.java @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.data.client; + +import dan200.computercraft.data.DataProviders; +import dan200.computercraft.shared.turtle.inventory.UpgradeSlot; +import net.minecraft.client.renderer.texture.atlas.SpriteSources; +import net.minecraft.client.renderer.texture.atlas.sources.SingleFile; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; + +import java.util.List; +import java.util.Optional; + +/** + * A version of {@link DataProviders} which relies on client-side classes. + *

+ * This is called from {@link DataProviders#add(DataProviders.GeneratorSink)}. + */ +public final class ClientDataProviders { + private ClientDataProviders() { + } + + public static void add(DataProviders.GeneratorSink generator) { + generator.addFromCodec("Block atlases", PackType.CLIENT_RESOURCES, "atlases", SpriteSources.FILE_CODEC, out -> { + out.accept(new ResourceLocation("blocks"), List.of( + new SingleFile(UpgradeSlot.LEFT_UPGRADE, Optional.empty()), + new SingleFile(UpgradeSlot.RIGHT_UPGRADE, Optional.empty()) + )); + }); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/data/BlockModelProvider.java b/projects/common/src/main/java/dan200/computercraft/data/BlockModelProvider.java index 7b40cd2dd..d05d8c308 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/BlockModelProvider.java +++ b/projects/common/src/main/java/dan200/computercraft/data/BlockModelProvider.java @@ -37,6 +37,14 @@ import static net.minecraft.data.models.model.ModelLocationUtils.getModelLocatio import static net.minecraft.data.models.model.TextureMapping.getBlockTexture; class BlockModelProvider { + private static final TextureSlot CURSOR = TextureSlot.create("cursor"); + + private static final ModelTemplate COMPUTER_ON = new ModelTemplate( + Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/computer_on")), + Optional.empty(), + TextureSlot.FRONT, TextureSlot.SIDE, TextureSlot.TOP, CURSOR + ); + private static final ModelTemplate MONITOR_BASE = new ModelTemplate( Optional.of(new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/monitor_base")), Optional.empty(), @@ -142,11 +150,18 @@ class BlockModelProvider { private static void registerComputer(BlockModelGenerators generators, ComputerBlock block) { generators.blockStateOutput.accept(MultiVariantGenerator.multiVariant(block) .with(createHorizontalFacingDispatch()) - .with(createModelDispatch(ComputerBlock.STATE, state -> ModelTemplates.CUBE_ORIENTABLE.createWithSuffix( - block, "_" + state.getSerializedName(), - TextureMapping.orientableCube(block).put(TextureSlot.FRONT, getBlockTexture(block, "_front" + state.getTexture())), - generators.modelOutput - ))) + .with(createModelDispatch(ComputerBlock.STATE, state -> switch (state) { + case OFF -> ModelTemplates.CUBE_ORIENTABLE.createWithSuffix( + block, "_" + state.getSerializedName(), + TextureMapping.orientableCube(block), + generators.modelOutput + ); + case ON, BLINKING -> COMPUTER_ON.createWithSuffix( + block, "_" + state.getSerializedName(), + TextureMapping.orientableCube(block).put(CURSOR, new ResourceLocation(ComputerCraftAPI.MOD_ID, "block/computer" + state.getTexture())), + generators.modelOutput + ); + })) ); generators.delegateItemModel(block, getModelLocation(block, "_blinking")); } diff --git a/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java b/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java index 5f4223f8e..c5f8aa661 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java +++ b/projects/common/src/main/java/dan200/computercraft/data/DataProviders.java @@ -4,16 +4,20 @@ package dan200.computercraft.data; +import com.mojang.serialization.Codec; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.data.loot.LootTableProvider.SubProviderEntry; import net.minecraft.data.models.BlockModelGenerators; import net.minecraft.data.models.ItemModelGenerators; import net.minecraft.data.tags.TagsProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import java.util.List; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -37,11 +41,22 @@ public final class DataProviders { generator.models(BlockModelProvider::addBlockModels, ItemModelProvider::addItemModels); generator.add(out -> new LanguageProvider(out, turtleUpgrades, pocketUpgrades)); + + // Unfortunately we rely on some client-side classes in this code. We just load in the client side data provider + // and invoke that. + try { + Class.forName("dan200.computercraft.data.client.ClientDataProviders") + .getMethod("add", GeneratorSink.class).invoke(null, generator); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } } - interface GeneratorSink { + public interface GeneratorSink { T add(DataProvider.Factory factory); + void addFromCodec(String name, PackType type, String directory, Codec codec, Consumer> output); + void lootTable(List tables); TagsProvider blockTags(Consumer> tags); diff --git a/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java b/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java index 9b8b545aa..c5dcdb70d 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java +++ b/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java @@ -230,6 +230,11 @@ public final class LanguageProvider implements DataProvider { addConfigEntry(ConfigSpec.httpDownloadBandwidth, "Global download limit"); addConfigEntry(ConfigSpec.httpUploadBandwidth, "Global upload limit"); + addConfigGroup(ConfigSpec.serverSpec, "http.proxy", "Proxy"); + addConfigEntry(ConfigSpec.httpProxyHost, "Host name"); + addConfigEntry(ConfigSpec.httpProxyPort, "Port"); + addConfigEntry(ConfigSpec.httpProxyType, "Proxy type"); + addConfigGroup(ConfigSpec.serverSpec, "peripheral", "Peripherals"); addConfigEntry(ConfigSpec.commandBlockEnabled, "Enable command block peripheral"); addConfigEntry(ConfigSpec.modemRange, "Modem range (default)"); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index e233bfa49..7c67aab14 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -213,8 +213,10 @@ public final class CommandComputerCraft { getMetricsInstance(context.getSource()).start(); var stopCommand = "/computercraft track stop"; - Object[] args = new Object[]{ link(text(stopCommand), stopCommand, Component.translatable("commands.computercraft.track.stop.action")) }; - context.getSource().sendSuccess(Component.translatable("commands.computercraft.track.start.stop", args), false); + context.getSource().sendSuccess(Component.translatable( + "commands.computercraft.track.start.stop", + link(text(stopCommand), stopCommand, Component.translatable("commands.computercraft.track.stop.action")) + ), false); return 1; })) diff --git a/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java b/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java index 5b63e827a..6680725da 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/container/BasicContainer.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.container; import net.minecraft.core.NonNullList; import net.minecraft.world.Container; import net.minecraft.world.ContainerHelper; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; /** @@ -16,24 +15,6 @@ import net.minecraft.world.item.ItemStack; public interface BasicContainer extends Container { NonNullList getContents(); - @Override - default int getMaxStackSize() { - return 64; - } - - @Override - default void startOpen(Player player) { - } - - @Override - default void stopOpen(Player player) { - } - - @Override - default boolean canPlaceItem(int slot, ItemStack stack) { - return true; - } - @Override default int getContainerSize() { return getContents().size(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java b/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java index d1d4dcfe4..b37396d0b 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/details/ItemDetails.java @@ -5,14 +5,11 @@ package dan200.computercraft.shared.details; import com.google.gson.JsonParseException; -import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.platform.RegistryWrappers; import dan200.computercraft.shared.util.NBTUtil; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.EnchantedBookItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.enchantment.EnchantmentHelper; @@ -45,7 +42,9 @@ public class ItemDetails { } data.put("tags", DetailHelpers.getTags(stack.getTags())); - data.put("itemGroups", getItemGroups(stack)); + + // Include deprecated itemGroups field + data.put("itemGroups", List.of()); var tag = stack.getTag(); if (tag != null && tag.contains("display", Tag.TAG_COMPOUND)) { @@ -84,27 +83,6 @@ public class ItemDetails { } } - /** - * Retrieve all item groups an item stack pertains to. - * - * @param stack Stack to analyse - * @return A filled list that contains pairs of item group IDs and their display names. - */ - private static List> getItemGroups(ItemStack stack) { - return CreativeModeTabs.allTabs().stream() - .filter(x -> x.shouldDisplay() && x.getType() == CreativeModeTab.Type.CATEGORY && x.contains(stack)) - .map(group -> { - Map groupData = new HashMap<>(2); - - var id = PlatformHelper.get().getCreativeTabId(group); - if (id != null) groupData.put("id", id.toString()); - - groupData.put("displayName", group.getDisplayName().getString()); - return groupData; - }) - .toList(); - } - /** * Retrieve all visible enchantments from given stack. Try to follow all tooltip rules : order and visibility. * diff --git a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java index 9064ea644..c68e4ad71 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java @@ -190,7 +190,7 @@ public abstract class SpeakerPeripheral implements IPeripheral { * The speaker supports [all of Minecraft's noteblock instruments](https://minecraft.fandom.com/wiki/Note_Block#Instruments). * These are: *

- * {@code "harp"}, {@code "basedrum"}, {@code "snare"}, {@code "hat"}, {@code "bass"}, @code "flute"}, + * {@code "harp"}, {@code "basedrum"}, {@code "snare"}, {@code "hat"}, {@code "bass"}, {@code "flute"}, * {@code "bell"}, {@code "guitar"}, {@code "chime"}, {@code "xylophone"}, {@code "iron_xylophone"}, * {@code "cow_bell"}, {@code "didgeridoo"}, {@code "bit"}, {@code "banjo"} and {@code "pling"}. * diff --git a/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java b/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java index d05c0baaa..faba05862 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/platform/PlatformHelper.java @@ -33,7 +33,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.DyeColor; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -273,15 +272,6 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper */ int getBurnTime(ItemStack stack); - /** - * Get a unique identifier for this creative tab. - * - * @param tab The tab to get - * @return The unique identifier, or {@code null} if not available. - */ - @Nullable - ResourceLocation getCreativeTabId(CreativeModeTab tab); - /** * Get the "container" item to be returned after crafting. For instance, crafting with a lava bucket should return * an empty bucket. diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java index 447e7a456..1e9c9357a 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -168,7 +168,7 @@ public class TurtlePlaceCommand implements TurtleCommand { if (Math.abs(hitY - 0.5f) < 0.01f) hitY = 0.45f; // Check if there's something suitable to place onto - var hit = new BlockHitResult(new Vec3(hitX, hitY, hitZ), side, position, false); + var hit = new BlockHitResult(new Vec3(position.getX() + hitX, position.getY() + hitY, position.getZ() + hitZ), side, position, false); var context = new UseOnContext(turtlePlayer.player(), InteractionHand.MAIN_HAND, hit); if (!canDeployOnBlock(new BlockPlaceContext(context), turtle, turtlePlayer, position, side, adjacent, outErrorMessage)) { return false; diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/TurtleMenu.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/TurtleMenu.java index 77116234b..61d2e67d8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/TurtleMenu.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/TurtleMenu.java @@ -4,6 +4,7 @@ package dan200.computercraft.shared.turtle.inventory; +import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; @@ -29,12 +30,13 @@ public final class TurtleMenu extends AbstractComputerMenu { public static final int PLAYER_START_Y = 134; public static final int TURTLE_START_X = SIDEBAR_WIDTH + 175; public static final int PLAYER_START_X = SIDEBAR_WIDTH + BORDER; + public static final int UPGRADE_START_X = SIDEBAR_WIDTH + 254; private final ContainerData data; private TurtleMenu( int id, Predicate canUse, ComputerFamily family, @Nullable ServerComputer computer, @Nullable ComputerContainerData menuData, - Inventory playerInventory, Container inventory, ContainerData data + Inventory playerInventory, Container inventory, Container turtleUpgrades, ContainerData data ) { super(ModRegistry.Menus.TURTLE.get(), id, canUse, family, computer, menuData); this.data = data; @@ -58,19 +60,24 @@ public final class TurtleMenu extends AbstractComputerMenu { for (var x = 0; x < 9; x++) { addSlot(new Slot(playerInventory, x, PLAYER_START_X + x * 18, PLAYER_START_Y + 3 * 18 + 5)); } + + // Turtle upgrades + addSlot(new UpgradeSlot(turtleUpgrades, TurtleSide.LEFT, 0, UPGRADE_START_X, PLAYER_START_Y + 1)); + addSlot(new UpgradeSlot(turtleUpgrades, TurtleSide.RIGHT, 1, UPGRADE_START_X, PLAYER_START_Y + 1 + 18)); } public static TurtleMenu ofBrain(int id, Inventory player, TurtleBrain turtle) { return new TurtleMenu( // Laziness in turtle.getOwner() is important here! id, p -> turtle.getOwner().stillValid(p), turtle.getFamily(), turtle.getOwner().createServerComputer(), null, - player, turtle.getInventory(), (SingleContainerData) turtle::getSelectedSlot + player, turtle.getInventory(), new UpgradeContainer(turtle), (SingleContainerData) turtle::getSelectedSlot ); } public static TurtleMenu ofMenuData(int id, Inventory player, ComputerContainerData data) { return new TurtleMenu( - id, x -> true, data.family(), null, data, player, new SimpleContainer(TurtleBlockEntity.INVENTORY_SIZE), new SimpleContainerData(1) + id, x -> true, data.family(), null, data, + player, new SimpleContainer(TurtleBlockEntity.INVENTORY_SIZE), new SimpleContainer(2), new SimpleContainerData(1) ); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeContainer.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeContainer.java new file mode 100644 index 000000000..22d918626 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeContainer.java @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.turtle.inventory; + +import dan200.computercraft.api.turtle.ITurtleAccess; +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.impl.TurtleUpgrades; +import net.minecraft.core.NonNullList; +import net.minecraft.world.Container; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +import java.util.Arrays; +import java.util.List; + +/** + * A fake {@link Container} which exposes the {@linkplain ITurtleAccess#getUpgrade(TurtleSide) upgrades} a turtle has. + * + * @see TurtleMenu + * @see UpgradeSlot + */ +class UpgradeContainer implements Container { + private static final int SIZE = 2; + + private final ITurtleAccess turtle; + + private final List lastUpgrade = Arrays.asList(null, null); + private final NonNullList lastStack = NonNullList.withSize(2, ItemStack.EMPTY); + + UpgradeContainer(ITurtleAccess turtle) { + this.turtle = turtle; + } + + private TurtleSide getSide(int slot) { + return switch (slot) { + case 0 -> TurtleSide.LEFT; + case 1 -> TurtleSide.RIGHT; + default -> throw new IllegalArgumentException("Invalid slot " + slot); + }; + } + + @Override + public ItemStack getItem(int slot) { + var upgrade = turtle.getUpgrade(getSide(slot)); + + // We don't want to return getCraftingItem directly here, as consumers may mutate the stack (they shouldn't!, + // but if they do it's a pain to track down). To avoid recreating the stack each tick, we maintain a simple + // cache. + if (upgrade == lastUpgrade.get(slot)) return lastStack.get(slot); + + var stack = upgrade == null ? ItemStack.EMPTY : upgrade.getCraftingItem().copy(); + lastUpgrade.set(slot, upgrade); + lastStack.set(slot, stack); + return stack; + } + + @Override + public void setItem(int slot, ItemStack itemStack) { + turtle.setUpgrade(getSide(slot), TurtleUpgrades.instance().get(itemStack)); + } + + @Override + public int getContainerSize() { + return SIZE; + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Override + public boolean isEmpty() { + for (var i = 0; i < SIZE; i++) { + if (!getItem(i).isEmpty()) return false; + } + return true; + } + + @Override + public ItemStack removeItem(int slot, int count) { + return count <= 0 ? ItemStack.EMPTY : removeItemNoUpdate(slot); + } + + @Override + public ItemStack removeItemNoUpdate(int slot) { + var current = getItem(slot); + setItem(slot, ItemStack.EMPTY); + return current; + } + + @Override + public void setChanged() { + } + + @Override + public boolean stillValid(Player player) { + return true; + } + + @Override + public void clearContent() { + for (var i = 0; i < SIZE; i++) setItem(i, ItemStack.EMPTY); + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeSlot.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeSlot.java new file mode 100644 index 000000000..7947785e1 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/inventory/UpgradeSlot.java @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.turtle.inventory; + +import com.mojang.datafixers.util.Pair; +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.impl.TurtleUpgrades; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; + +import javax.annotation.Nullable; + +/** + * A slot in the turtle UI which holds the turtle's current upgrade. + * + * @see TurtleMenu + */ +public class UpgradeSlot extends Slot { + public static final ResourceLocation LEFT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_left"); + public static final ResourceLocation RIGHT_UPGRADE = new ResourceLocation(ComputerCraftAPI.MOD_ID, "gui/turtle_upgrade_right"); + + private final TurtleSide side; + + public UpgradeSlot(Container container, TurtleSide side, int slot, int xPos, int yPos) { + super(container, slot, xPos, yPos); + this.side = side; + } + + @Override + public boolean mayPlace(ItemStack stack) { + return TurtleUpgrades.instance().get(stack) != null; + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Nullable + @Override + public Pair getNoItemIcon() { + return Pair.of(InventoryMenu.BLOCK_ATLAS, side == TurtleSide.LEFT ? LEFT_UPGRADE : RIGHT_UPGRADE); + } +} diff --git a/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json b/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json index 3fd443ace..8495d2376 100644 --- a/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json +++ b/projects/common/src/main/resources/assets/computercraft/lang/ru_ru.json @@ -115,5 +115,67 @@ "upgrade.minecraft.diamond_pickaxe.adjective": "Добывающая", "upgrade.minecraft.diamond_shovel.adjective": "Копающая", "upgrade.minecraft.diamond_sword.adjective": "Боевая", - "gui.computercraft.pocket_computer_overlay": "Карманный компьютер открыт. Чтобы закрыть, нажми ESC." + "gui.computercraft.pocket_computer_overlay": "Карманный компьютер открыт. Чтобы закрыть, нажми ESC.", + "gui.computercraft.config.command_require_creative.tooltip": "Требовать творческий режим и права оператора для взаимодействия с\nкомандными компьютерами. Это поведение по умолчанию для Командных блоков ванильной игры.", + "gui.computercraft.config.default_computer_settings.tooltip": "Разделенный запятыми список системных настроек по умолчанию на новых компьютерах.\nНапример: \"shell.autocomplete=false,lua.autocomplete=false,edit.autocomplete=false\"\nотключит всё автодополнение.", + "gui.computercraft.config.execution.computer_threads.tooltip": "Устанавливает количество потоков, на которых работают компьютеры. Большее число\nозначает, что больше компьютеров сможет работать одновременно, но может привести к лагу.\nОбратите внимание, что некоторые моды могут не работать с более чем одним потоком. Используйте с осторожностью.\nОграничение: > 1", + "gui.computercraft.config.execution.max_main_computer_time.tooltip": "Идеальный максимум времени, которое отведено компьютеру на выполнение задач, в миллисекундах.\nМы вполне возможно выйдем за этот лимит, так как невозможно предсказать сколько\nвремени будет затрачено на выполнение задач, это лишь верхний лимит среднего значения времени.\nОграничение: > 1", + "gui.computercraft.config.execution.max_main_global_time.tooltip": "Максимум времени, которое может быть потрачено на выполнение задач за один тик, в \nмиллисекундах. \nМы вполне возможно выйдем за этот лимит, так как невозможно предсказать сколько\nвремени будет затрачено на выполнение задач, это лишь верхний лимит среднего значения времени.\nОграничение: > 1", + "gui.computercraft.config.http.bandwidth.global_download": "Глобальный лимит на скачивание", + "gui.computercraft.config.http.bandwidth.global_download.tooltip": "Количество байтов, которое можно скачать за секунду. Все компьютеры делят эту пропускную способность. (байты в секунду)\nОграничение: > 1", + "gui.computercraft.config.http.bandwidth.global_upload.tooltip": "Количество байтов, которое можно загрузить за секунду. Все компьютеры делят эту пропускную способность. (байты в секунду)\nОграничение: > 1", + "tracking_field.computercraft.http_requests.name": "HTTP запросы", + "tracking_field.computercraft.turtle_ops.name": "Операции Черепашек", + "gui.computercraft.config.http.enabled.tooltip": "Включить API \"http\" на Компьютерах. Это также отключает программы \"pastebin\" и \"wget\", \nкоторые нужны многим пользователям. Рекомендуется оставить это включенным и использовать \nконфиг \"rules\" для более тонкой настройки.", + "gui.computercraft.config.http.max_websockets.tooltip": "Количество одновременно открытых веб-сокетов, которые может иметь компьютер. Установите на 0 для неограниченных веб-сокетов.\nОграничение: > 1", + "gui.computercraft.config.term_sizes": "Размер терминала", + "gui.computercraft.config.term_sizes.computer.height": "Высота терминала", + "gui.computercraft.config.term_sizes.monitor.height": "Максимальная высота монитора", + "gui.computercraft.config.term_sizes.monitor.width.tooltip": "Ограничение: 1 ~ 32", + "gui.computercraft.config.turtle.advanced_fuel_limit": "Лимит топлива Продвинутых Черепашек", + "gui.computercraft.config.turtle.need_fuel.tooltip": "Устанавливает, нуждаются ли Черепашки в топливе для передвижения.", + "gui.computercraft.terminal": "Компьютерный терминал", + "tracking_field.computercraft.computer_tasks.name": "Задачи", + "tracking_field.computercraft.server_tasks.name": "Серверные задачи", + "gui.computercraft.upload.no_response": "Перенос файлов", + "tracking_field.computercraft.avg": "%s (среднее)", + "gui.computercraft.config.command_require_creative": "Для использования командных компьютеров нужен творческий режим", + "gui.computercraft.config.computer_space_limit": "Лимит места на компьютерах (в байтах)", + "gui.computercraft.config.computer_space_limit.tooltip": "Лимит места на дисках компьютеров и черепашек, в байтах.", + "gui.computercraft.config.default_computer_settings": "Настройки Компьютера по умолчанию", + "gui.computercraft.config.disable_lua51_features": "Отключить функции Lua 5.1", + "gui.computercraft.config.disable_lua51_features.tooltip": "Поставьте, чтобы отключить функции из Lua 5.1, которые будут убраны в будущих\nобновлениях. Полезно для того, чтобы улучшить совместимость вперед ваших программ.", + "gui.computercraft.config.execution": "Выполнение", + "gui.computercraft.config.execution.computer_threads": "Потоки компьютера", + "gui.computercraft.config.execution.max_main_global_time": "Глобальный лимит времени на тик сервера", + "gui.computercraft.config.execution.tooltip": "Контролирует поведение выполнения задач компьютеров. Эта настройка преднезначается для \nтонкой настройки серверов, и в основном не должна быть изменена.", + "gui.computercraft.config.floppy_space_limit": "Лимит места на дискетах (байты)", + "gui.computercraft.config.floppy_space_limit.tooltip": "Лимит места для хранения информации на дискетах, в байтах.", + "gui.computercraft.config.http": "HTTP", + "gui.computercraft.config.http.bandwidth": "Пропускная способность", + "gui.computercraft.config.http.bandwidth.global_upload": "Глобальный лимит загрузки", + "gui.computercraft.config.http.bandwidth.tooltip": "Ограничивает пропускную способность, используемую компьютерами.", + "gui.computercraft.config.http.enabled": "Включить HTTP API", + "gui.computercraft.config.http.max_requests": "Максимум одновременных запросов", + "gui.computercraft.config.http.max_requests.tooltip": "Количество http-запросов, которые компьютер может сделать одновременно. Дополнительные запросы \nбудут поставлены в очередь, и отправлены когда существующие запросы будут выполнены. Установите на 0 для \nнеограниченных запросов.\nОграничение: > 0", + "gui.computercraft.config.http.max_websockets": "Максимум одновременных веб-сокетов", + "gui.computercraft.config.term_sizes.computer": "Компьютер", + "gui.computercraft.config.term_sizes.computer.height.tooltip": "Ограничение: 1 ~ 255", + "gui.computercraft.config.term_sizes.computer.tooltip": "Размер терминала на компьютерах.", + "gui.computercraft.config.term_sizes.computer.width": "Ширина терминала", + "gui.computercraft.config.term_sizes.computer.width.tooltip": "Ограничение: 1 ~ 255", + "gui.computercraft.config.term_sizes.monitor": "Монитор", + "gui.computercraft.config.term_sizes.monitor.height.tooltip": "Ограничение: 1 ~ 32", + "gui.computercraft.config.term_sizes.monitor.tooltip": "Максимальный размер мониторов (в блоках).", + "gui.computercraft.config.term_sizes.monitor.width": "Максимальная ширина мониторов", + "gui.computercraft.config.term_sizes.pocket_computer.height": "Высота терминала", + "gui.computercraft.config.term_sizes.pocket_computer.height.tooltip": "Ограничение: 1 ~ 255", + "gui.computercraft.config.term_sizes.pocket_computer.width": "Ширина терминала", + "gui.computercraft.config.term_sizes.pocket_computer.width.tooltip": "Ограничение: 1 ~ 255", + "gui.computercraft.config.turtle": "Черепашки", + "gui.computercraft.config.turtle.advanced_fuel_limit.tooltip": "Лимит топлива для Продвинутых Черепашек.\nОграничение: > 0", + "gui.computercraft.config.turtle.need_fuel": "Включить механику топлива", + "gui.computercraft.config.turtle.normal_fuel_limit": "Лимит топлива Черепашек", + "gui.computercraft.config.turtle.normal_fuel_limit.tooltip": "Лимит топлива для Черепашек.\nОграничение: > 0", + "gui.computercraft.config.turtle.tooltip": "Разные настройки, связанные с черепашками." } diff --git a/projects/common/src/main/resources/assets/computercraft/models/block/computer_on.json b/projects/common/src/main/resources/assets/computercraft/models/block/computer_on.json new file mode 100644 index 000000000..485bc526f --- /dev/null +++ b/projects/common/src/main/resources/assets/computercraft/models/block/computer_on.json @@ -0,0 +1,39 @@ +{ + "parent": "minecraft:block/block", + "render_type": "cutout", + "textures": { + "particle": "#front" + }, + "display": { + "firstperson_righthand": { + "rotation": [ 0, 135, 0 ], + "translation": [ 0, 0, 0 ], + "scale": [ 0.40, 0.40, 0.40 ] + } + }, + "elements": [ + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "texture": "#top", "cullface": "down" }, + "up": { "texture": "#top", "cullface": "up" }, + "north": { "texture": "#front", "cullface": "north" }, + "south": { "texture": "#side", "cullface": "south" }, + "west": { "texture": "#side", "cullface": "west" }, + "east": { "texture": "#side", "cullface": "east" } + } + }, + { + "from": [ 0, 0, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "north": { + "texture": "#cursor", + "cullface": "north", + "forge_data": {"block_light": 15, "sky_light": 15} + } + } + } + ] +} diff --git a/projects/common/src/main/resources/assets/computercraft/models/block/computer_on.json.license b/projects/common/src/main/resources/assets/computercraft/models/block/computer_on.json.license new file mode 100644 index 000000000..05aed57f6 --- /dev/null +++ b/projects/common/src/main/resources/assets/computercraft/models/block/computer_on.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers + +SPDX-License-Identifier: MPL-2.0 diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_blink.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_blink.png deleted file mode 100644 index 8c29b0e49..000000000 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_blink.png and /dev/null differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_on.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_on.png deleted file mode 100644 index 49fea014b..000000000 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_on.png and /dev/null differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_blink.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_blink.png new file mode 100644 index 000000000..0cb8a6c95 Binary files /dev/null and b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_blink.png differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_blink.png.mcmeta b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_blink.png.mcmeta similarity index 100% rename from projects/common/src/main/resources/assets/computercraft/textures/block/computer_advanced_front_blink.png.mcmeta rename to projects/common/src/main/resources/assets/computercraft/textures/block/computer_blink.png.mcmeta diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_blink.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_blink.png deleted file mode 100644 index be746fcb3..000000000 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_blink.png and /dev/null differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_blink.png.mcmeta b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_blink.png.mcmeta deleted file mode 100644 index e962dcee6..000000000 --- a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_blink.png.mcmeta +++ /dev/null @@ -1,6 +0,0 @@ -{ - "animation": { - "frametime": 8, - "frames": [ 0, 1 ] - } -} diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_on.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_on.png deleted file mode 100644 index 1d5d38f75..000000000 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_command_front_on.png and /dev/null differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_blink.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_blink.png deleted file mode 100644 index ba62d067e..000000000 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_blink.png and /dev/null differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_blink.png.mcmeta b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_blink.png.mcmeta deleted file mode 100644 index e962dcee6..000000000 --- a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_blink.png.mcmeta +++ /dev/null @@ -1,6 +0,0 @@ -{ - "animation": { - "frametime": 8, - "frames": [ 0, 1 ] - } -} diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_on.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_on.png deleted file mode 100644 index d87bcac8f..000000000 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_normal_front_on.png and /dev/null differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/block/computer_on.png b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_on.png new file mode 100644 index 000000000..3ad187b99 Binary files /dev/null and b/projects/common/src/main/resources/assets/computercraft/textures/block/computer_on.png differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_advanced.png b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_advanced.png index 74a149a47..8f7d66500 100644 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_advanced.png and b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_advanced.png differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_normal.png b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_normal.png index 83b6a882e..f676c56b2 100644 Binary files a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_normal.png and b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_normal.png differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_left.png b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_left.png new file mode 100644 index 000000000..5c76e88be Binary files /dev/null and b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_left.png differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_left.png.license b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_left.png.license new file mode 100644 index 000000000..05aed57f6 --- /dev/null +++ b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_left.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers + +SPDX-License-Identifier: MPL-2.0 diff --git a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_right.png b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_right.png new file mode 100644 index 000000000..ab877ab72 Binary files /dev/null and b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_right.png differ diff --git a/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_right.png.license b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_right.png.license new file mode 100644 index 000000000..05aed57f6 --- /dev/null +++ b/projects/common/src/main/resources/assets/computercraft/textures/gui/turtle_upgrade_right.png.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers + +SPDX-License-Identifier: MPL-2.0 diff --git a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java index 60b016e9c..552e63756 100644 --- a/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java +++ b/projects/common/src/test/java/dan200/computercraft/TestPlatformHelper.java @@ -36,7 +36,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Recipe; @@ -165,13 +164,6 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat throw new UnsupportedOperationException("Cannot interact with the world inside tests"); } - - @Nullable - @Override - public ResourceLocation getCreativeTabId(CreativeModeTab tab) { - return null; - } - @Override public RecipeIngredients getRecipeIngredients() { throw new UnsupportedOperationException("Cannot query recipes inside tests"); diff --git a/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java index fd75c2f92..c300bd0df 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/projects/core/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -443,28 +443,6 @@ public class FSAPI implements ILuaAPI { } } - /** - * Searches for files matching a string with wildcards. - *

- * This string is formatted like a normal path string, but can include any - * number of wildcards ({@code *}) to look for files matching anything. - * For example, rom/*/command* will look for any path starting with - * {@code command} inside any subdirectory of {@code /rom}. - * - * @param path The wildcard-qualified path to search for. - * @return A list of paths that match the search string. - * @throws LuaException If the path doesn't exist. - * @cc.since 1.6 - */ - @LuaFunction - public final String[] find(String path) throws LuaException { - try (var ignored = environment.time(Metrics.FS_OPS)) { - return getFileSystem().find(path); - } catch (FileSystemException e) { - throw new LuaException(e.getMessage()); - } - } - /** * Returns the capacity of the drive the path is located on. * diff --git a/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index d43918aaa..139e69e2f 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/projects/core/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -166,47 +166,6 @@ public class FileSystem { return array; } - private void findIn(String dir, List matches, Pattern wildPattern) throws FileSystemException { - var list = list(dir); - for (var entry : list) { - var entryPath = dir.isEmpty() ? entry : dir + "/" + entry; - if (wildPattern.matcher(entryPath).matches()) { - matches.add(entryPath); - } - if (isDir(entryPath)) { - findIn(entryPath, matches, wildPattern); - } - } - } - - public synchronized String[] find(String wildPath) throws FileSystemException { - // Match all the files on the system - wildPath = sanitizePath(wildPath, true); - - // If we don't have a wildcard at all just check the file exists - var starIndex = wildPath.indexOf('*'); - if (starIndex == -1) { - return exists(wildPath) ? new String[]{ wildPath } : new String[0]; - } - - // Find the all non-wildcarded directories. For instance foo/bar/baz* -> foo/bar - var prevDir = wildPath.substring(0, starIndex).lastIndexOf('/'); - var startDir = prevDir == -1 ? "" : wildPath.substring(0, prevDir); - - // If this isn't a directory then just abort - if (!isDir(startDir)) return new String[0]; - - // Scan as normal, starting from this directory - var wildPattern = Pattern.compile("^\\Q" + wildPath.replaceAll("\\*", "\\\\E[^\\\\/]*\\\\Q") + "\\E$"); - List matches = new ArrayList<>(); - findIn(startDir, matches, wildPattern); - - // Return matches - var array = new String[matches.size()]; - matches.toArray(array); - return array; - } - public synchronized boolean exists(String path) throws FileSystemException { path = sanitizePath(path); var mount = getMount(path); @@ -400,21 +359,20 @@ public class FileSystem { private static final Pattern threeDotsPattern = Pattern.compile("^\\.{3,}$"); + // IMPORTANT: Both arrays are sorted by ASCII value. + private static final char[] specialChars = new char[]{ '"', '*', ':', '<', '>', '?', '|' }; + private static final char[] specialCharsAllowWildcards = new char[]{ '"', ':', '<', '>', '|' }; + public static String sanitizePath(String path, boolean allowWildcards) { // Allow windowsy slashes path = path.replace('\\', '/'); // Clean the path or illegal characters. - final var specialChars = new char[]{ - '"', ':', '<', '>', '?', '|', // Sorted by ascii value (important) - }; - var cleanName = new StringBuilder(); + var allowedChars = allowWildcards ? specialCharsAllowWildcards : specialChars; for (var i = 0; i < path.length(); i++) { var c = path.charAt(i); - if (c >= 32 && Arrays.binarySearch(specialChars, c) < 0 && (allowWildcards || c != '*')) { - cleanName.append(c); - } + if (c >= 32 && Arrays.binarySearch(allowedChars, c) < 0) cleanName.append(c); } path = cleanName.toString(); diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/apis/fs.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/fs.lua index 1a0fb4b53..0643fd120 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/apis/fs.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/apis/fs.lua @@ -133,6 +133,93 @@ function fs.complete(sPath, sLocation, bIncludeFiles, bIncludeDirs) return {} end +local function find_aux(path, parts, i, out) + local part = parts[i] + if not part then + -- If we're at the end of the pattern, ensure our path exists and append it. + if fs.exists(path) then out[#out + 1] = path end + elseif part.exact then + -- If we're an exact match, just recurse into this directory. + return find_aux(fs.combine(path, part.contents), parts, i + 1, out) + else + -- Otherwise we're a pattern. Check we're a directory, then recurse into each + -- matching file. + if not fs.isDir(path) then return end + + local files = fs.list(path) + for j = 1, #files do + local file = files[j] + if file:find(part.contents) then find_aux(fs.combine(path, file), parts, i + 1, out) end + end + end +end + +local find_escape = { + -- Escape standard Lua pattern characters + ["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%", + ["."] = "%.", ["["] = "%[", ["]"] = "%]", ["+"] = "%+", ["-"] = "%-", + -- Aside from our wildcards. + ["*"] = ".*", + ["?"] = ".", +} + +--[[- Searches for files matching a string with wildcards. + +This string looks like a normal path string, but can include wildcards, which +can match multiple paths: + + - "?" matches any single character in a file name. + - "*" matches any number of characters. + +For example, `rom/*/command*` will look for any path starting with `command` +inside any subdirectory of `/rom`. + +Note that these wildcards match a single segment of the path. For instance +`rom/*.lua` will include `rom/startup.lua` but _not_ include `rom/programs/list.lua`. + +@tparam string path The wildcard-qualified path to search for. +@treturn { string... } A list of paths that match the search string. +@throws If the supplied path was invalid. +@since 1.6 +@changed 1.106.0 Added support for the `?` wildcard. + +@usage List all Markdown files in the help folder + + fs.find("rom/help/*.md") +]] +function fs.find(pattern) + expect(1, pattern, "string") + + pattern = fs.combine(pattern) -- Normalise the path, removing ".."s. + + -- If the pattern is trying to search outside the computer root, just abort. + -- This will fail later on anyway. + if pattern == ".." or pattern:sub(1, 3) == "../" then + error("/" .. pattern .. ": Invalid Path", 2) + end + + -- If we've no wildcards, just check the file exists. + if not pattern:find("[*?]") then + if fs.exists(pattern) then return { pattern } else return {} end + end + + local parts = {} + for part in pattern:gmatch("[^/]+") do + if part:find("[*?]") then + parts[#parts + 1] = { + exact = false, + contents = "^" .. part:gsub(".", find_escape) .. "$", + } + else + parts[#parts + 1] = { exact = true, contents = part } + end + end + + local out = {} + find_aux("", parts, 1, out) + return out +end + --- Returns true if a path is mounted to the parent filesystem. -- -- The root filesystem "/" is considered a mount, along with disk folders and diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/help/changelog.md b/projects/core/src/main/resources/data/computercraft/lua/rom/help/changelog.md index a776f31c3..098267351 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/help/changelog.md +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/help/changelog.md @@ -1,3 +1,27 @@ +# 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: +* Allow GPS hosts to only be 1 block apart. +* 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. + # New features in CC: Tweaked 1.104.0 * Update to Minecraft 1.19.4. diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md b/projects/core/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md index 4973b3df2..1512a2ae6 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md @@ -1,31 +1,25 @@ -New features in CC: Tweaked 1.104.0 +New features in CC: Tweaked 1.105.0 -* Update to Minecraft 1.19.4. -* Turtles can now right click items "into" certain blocks (cauldrons and hives by default, configurable with the `computercraft:turtle_can_use` block tag). -* Update Cobalt to 0.7: - * `table` methods and `ipairs` now use metamethods. - * Type errors now use the `__name` metatag. - * Coroutines no longer run on multiple threads. - * Timeout errors should be thrown more reliably. -* `speaker` program now reports an error on common unsupported audio formats. -* `multishell` now hides the implementation details of its terminal redirect from programs. -* Use VBO monitor renderer by default. -* Improve syntax errors when missing commas in tables, and on trailing commas in parameter lists. -* Turtles can now hold flags. -* Update several translations (Alessandro, chesiren, Erlend, RomanPlayer22). +* 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: -* `settings.load` now ignores malformed values created by editing the `.settings` file by hand. -* Fix introduction dates on `os.cancelAlarm` and `os.cancelTimer` (MCJack123). -* Fix the REPL syntax reporting crashing on valid parses. -* Make writes to the ID file atomic. -* Obey stack limits when transferring items with Fabric's APIs. -* Ignore metatables in `textutils.serialize`. -* Correctly recurse into NBT lists when computing the NBT hash (Lemmmy). -* Fix advanced pocket computers rendering as greyscale. -* Fix stack overflow when using `shell` as a hashbang program. -* Fix websocket messages being empty when using a non-default compression settings. -* Fix `gps.locate` returning `nan` when receiving a duplicate location (Wojbie). -* Remove several thread safety issues inside Java-side argument parsing code. +* Allow GPS hosts to only be 1 block apart. +* 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. diff --git a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua b/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua index 2df2ed962..154332f22 100644 --- a/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua +++ b/projects/core/src/main/resources/data/computercraft/lua/rom/modules/main/cc/image/nft.lua @@ -2,7 +2,7 @@ -- -- SPDX-License-Identifier: MPL-2.0 ---- Read and draw nbt ("Nitrogen Fingers Text") images. +--- Read and draw nft ("Nitrogen Fingers Text") images. -- -- nft ("Nitrogen Fingers Text") is a file format for drawing basic images. -- Unlike the images that @{paintutils.parseImage} uses, nft supports coloured diff --git a/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua index ca540985f..156dafdd5 100644 --- a/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua +++ b/projects/core/src/test/resources/test-rom/spec/apis/fs_spec.lua @@ -87,6 +87,53 @@ describe("The fs library", function() end) end) + describe("fs.find", function() + it("fails on invalid paths", function() + expect.error(fs.find, ".."):eq("/..: Invalid Path") + expect.error(fs.find, "../foo/bar"):eq("/../foo/bar: Invalid Path") + end) + + it("returns nothing on non-existent files", function() + expect(fs.find("no/such/file")):same {} + expect(fs.find("no/such/*")):same {} + expect(fs.find("no/*/file")):same {} + end) + + it("returns a single file", function() + expect(fs.find("rom")):same { "rom" } + expect(fs.find("rom/motd.txt")):same { "rom/motd.txt" } + end) + + it("supports the '*' wildcard", function() + expect(fs.find("rom/*")):same { + "rom/apis", + "rom/autorun", + "rom/help", + "rom/modules", + "rom/motd.txt", + "rom/programs", + "rom/startup.lua", + } + expect(fs.find("rom/*/command")):same { + "rom/apis/command", + "rom/modules/command", + "rom/programs/command", + } + + expect(fs.find("rom/*/lua*")):same { + "rom/help/lua.txt", + "rom/programs/lua.lua", + } + end) + + it("supports the '?' wildcard", function() + expect(fs.find("rom/programs/mo??.lua")):same { + "rom/programs/motd.lua", + "rom/programs/move.lua", + } + end) + end) + describe("fs.combine", function() it("removes . and ..", function() expect(fs.combine("./a/b")):eq("a/b") diff --git a/projects/fabric/build.gradle.kts b/projects/fabric/build.gradle.kts index 576bac769..7d07fc9e2 100644 --- a/projects/fabric/build.gradle.kts +++ b/projects/fabric/build.gradle.kts @@ -119,7 +119,7 @@ loom { register("data") { configName = "Datagen" - server() + client() runDir("run/dataGen") property("cct.pretty-json") @@ -165,7 +165,6 @@ tasks.processResources { filesMatching("fabric.mod.json") { expand(mapOf("version" to modVersion)) } - exclude(".cache") } tasks.jar { @@ -251,3 +250,7 @@ publishing { } } } + +modrinth { + required.project("fabric-api") +} diff --git a/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java b/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java index 292d1ea9a..170034086 100644 --- a/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java +++ b/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java @@ -4,6 +4,7 @@ package dan200.computercraft.client; +import dan200.computercraft.client.model.EmissiveComputerModel; import dan200.computercraft.client.model.turtle.TurtleModelLoader; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.network.client.ClientNetworkContext; @@ -35,9 +36,12 @@ public class ComputerCraftClient { ClientRegistry.registerItemColours(ColorProviderRegistry.ITEM::register); ClientRegistry.registerMainThread(); - ModelLoadingRegistry.INSTANCE.registerModelProvider((manager, out) -> ClientRegistry.registerExtraModels(out)); ModelLoadingRegistry.INSTANCE.registerResourceProvider(loader -> (path, ctx) -> TurtleModelLoader.load(loader, path)); + ModelLoadingRegistry.INSTANCE.registerResourceProvider(loader -> (path, ctx) -> EmissiveComputerModel.load(loader, path)); + BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.COMPUTER_NORMAL.get(), RenderType.cutout()); + BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.COMPUTER_COMMAND.get(), RenderType.cutout()); + BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.COMPUTER_ADVANCED.get(), RenderType.cutout()); BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.MONITOR_NORMAL.get(), RenderType.cutout()); BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.MONITOR_ADVANCED.get(), RenderType.cutout()); diff --git a/projects/fabric/src/client/java/dan200/computercraft/client/model/EmissiveComputerModel.java b/projects/fabric/src/client/java/dan200/computercraft/client/model/EmissiveComputerModel.java new file mode 100644 index 000000000..27db7a75b --- /dev/null +++ b/projects/fabric/src/client/java/dan200/computercraft/client/model/EmissiveComputerModel.java @@ -0,0 +1,172 @@ +// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.client.model; + +import com.google.gson.JsonObject; +import com.mojang.datafixers.util.Either; +import dan200.computercraft.api.ComputerCraftAPI; +import net.fabricmc.fabric.api.client.model.ModelProviderException; +import net.fabricmc.fabric.api.client.model.ModelResourceProvider; +import net.fabricmc.fabric.api.renderer.v1.RendererAccess; +import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel; +import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.client.renderer.block.model.BlockModel; +import net.minecraft.client.renderer.block.model.ItemTransforms; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.resources.model.*; +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.util.GsonHelper; +import net.minecraft.util.RandomSource; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockAndTintGetter; +import net.minecraft.world.level.block.state.BlockState; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; + +/** + * Wraps a computer's {@link BlockModel}/{@link BakedModel} to render the computer's cursor as an emissive quad. + *

+ * While Fabric has a quite advanced rendering extension API (including support for custom materials), but unlike Forge + * it doesn't expose this in the model JSON (though externals mods like JMX + * do handle this). + *

+ * Instead, we support emissive quads by injecting a custom {@linkplain ModelResourceProvider model loader/provider} + * which targets a hard-coded list of computer models, and wraps the returned model in a custom + * {@linkplain FabricBakedModel} implementation which renders specific quads as emissive. + *

+ * See also the assets/computercraft/models/block/computer_on.json model, which is the base for all + * emissive computer models. + */ +public final class EmissiveComputerModel { + private static final Set MODELS = Set.of( + "item/computer_advanced", + "block/computer_advanced_on", + "block/computer_advanced_blinking", + "item/computer_command", + "block/computer_command_on", + "block/computer_command_blinking", + "item/computer_normal", + "block/computer_normal_on", + "block/computer_normal_blinking" + ); + + private EmissiveComputerModel() { + } + + public static @Nullable UnbakedModel load(ResourceManager resources, ResourceLocation path) throws ModelProviderException { + if (!path.getNamespace().equals(ComputerCraftAPI.MOD_ID) || !MODELS.contains(path.getPath())) return null; + + JsonObject json; + try (var reader = resources.openAsReader(new ResourceLocation(path.getNamespace(), "models/" + path.getPath() + ".json"))) { + json = GsonHelper.parse(reader).getAsJsonObject(); + } catch (IOException e) { + throw new ModelProviderException("Failed loading model " + path, e); + } + + // Parse a subset of the model JSON + var parent = new ResourceLocation(GsonHelper.getAsString(json, "parent")); + + Map> textures = new HashMap<>(); + if (json.has("textures")) { + var jsonObject = GsonHelper.getAsJsonObject(json, "textures"); + + for (var entry : jsonObject.entrySet()) { + var texture = entry.getValue().getAsString(); + textures.put(entry.getKey(), texture.startsWith("#") + ? Either.right(texture.substring(1)) + : Either.left(new Material(InventoryMenu.BLOCK_ATLAS, new ResourceLocation(texture))) + ); + } + } + + return new Unbaked(parent, textures); + } + + /** + * An {@link UnbakedModel} which wraps the returned model using {@link Baked}. + *

+ * This subclasses {@link BlockModel} to allow using these models as a parent of other models. + */ + private static final class Unbaked extends BlockModel { + Unbaked(ResourceLocation parent, Map> materials) { + super(parent, List.of(), materials, null, null, ItemTransforms.NO_TRANSFORMS, List.of()); + } + + @Override + public BakedModel bake(ModelBaker baker, Function spriteGetter, ModelState state, ResourceLocation location) { + var baked = super.bake(baker, spriteGetter, state, location); + if (!hasTexture("cursor")) return baked; + + var render = RendererAccess.INSTANCE.getRenderer(); + if (render == null) return baked; + + return new Baked( + baked, + spriteGetter.apply(getMaterial("cursor")), + render.materialFinder().find(), + render.materialFinder().emissive(0, true).find() + ); + } + } + + /** + * A {@link FabricBakedModel} which renders quads using the {@code "cursor"} texture as emissive. + */ + private static final class Baked extends ForwardingBakedModel { + private final TextureAtlasSprite cursor; + private final RenderMaterial defaultMaterial; + private final RenderMaterial emissiveMaterial; + + Baked(BakedModel wrapped, TextureAtlasSprite cursor, RenderMaterial defaultMaterial, RenderMaterial emissiveMaterial) { + this.wrapped = wrapped; + this.cursor = cursor; + this.defaultMaterial = defaultMaterial; + this.emissiveMaterial = emissiveMaterial; + } + + @Override + public boolean isVanillaAdapter() { + return false; + } + + @Override + public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier randomSupplier, RenderContext context) { + emitQuads(context, state, randomSupplier.get()); + } + + @Override + public void emitItemQuads(ItemStack stack, Supplier randomSupplier, RenderContext context) { + emitQuads(context, null, randomSupplier.get()); + } + + private void emitQuads(RenderContext context, @Nullable BlockState state, RandomSource random) { + var emitter = context.getEmitter(); + for (var faceIdx = 0; faceIdx <= ModelHelper.NULL_FACE_ID; faceIdx++) { + var cullFace = ModelHelper.faceFromIndex(faceIdx); + var quads = wrapped.getQuads(state, cullFace, random); + + var count = quads.size(); + for (var i = 0; i < count; i++) { + final var q = quads.get(i); + emitter.fromVanilla(q, q.getSprite() == cursor ? emissiveMaterial : defaultMaterial, cullFace); + emitter.emit(); + } + } + } + } +} diff --git a/projects/fabric/src/generated/resources/assets/computercraft/lang/en_us.json b/projects/fabric/src/generated/resources/assets/computercraft/lang/en_us.json index 4c1351f43..845d71ec6 100644 --- a/projects/fabric/src/generated/resources/assets/computercraft/lang/en_us.json +++ b/projects/fabric/src/generated/resources/assets/computercraft/lang/en_us.json @@ -104,6 +104,14 @@ "gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.\nRange: > 0", "gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets", "gui.computercraft.config.http.max_websockets.tooltip": "The number of websockets a computer can have open at one time. Set to 0 for unlimited.\nRange: > 1", + "gui.computercraft.config.http.proxy": "Proxy", + "gui.computercraft.config.http.proxy.host": "Host name", + "gui.computercraft.config.http.proxy.host.tooltip": "The hostname or IP address of the proxy server.", + "gui.computercraft.config.http.proxy.port": "Port", + "gui.computercraft.config.http.proxy.port.tooltip": "The port of the proxy server.\nRange: 1 ~ 65536", + "gui.computercraft.config.http.proxy.tooltip": "Tunnels HTTP and websocket requests through a proxy server. Only affects HTTP\nrules with \"use_proxy\" set to true (off by default).\nIf authentication is required for the proxy, create a \"computercraft-proxy.pw\"\nfile in the same directory as \"computercraft-server.toml\", containing the\nusername and password separated by a colon, e.g. \"myuser:mypassword\". For\nSOCKS4 proxies only the username is required.", + "gui.computercraft.config.http.proxy.type": "Proxy type", + "gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5", "gui.computercraft.config.http.rules": "Allow/deny rules", "gui.computercraft.config.http.rules.tooltip": "A list of rules which control behaviour of the \"http\" API for specific domains or\nIPs. Each rule is an item with a 'host' to match against, and a series of\nproperties. Rules are evaluated in order, meaning earlier rules override later\nones.\nThe host may be a domain name (\"pastebin.com\"), wildcard (\"*.pastebin.com\") or\nCIDR notation (\"127.0.0.0/8\").\nIf no rules, the domain is blocked.", "gui.computercraft.config.http.tooltip": "Controls the HTTP API", diff --git a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json index e9fccca86..652f58ae1 100644 --- a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json +++ b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_advanced_front_blink", + "cursor": "computercraft:block/computer_blink", + "front": "computercraft:block/computer_advanced_front", "side": "computercraft:block/computer_advanced_side", "top": "computercraft:block/computer_advanced_top" } diff --git a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json index 497c1337d..fb7ab4898 100644 --- a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json +++ b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_advanced_front_on", + "cursor": "computercraft:block/computer_on", + "front": "computercraft:block/computer_advanced_front", "side": "computercraft:block/computer_advanced_side", "top": "computercraft:block/computer_advanced_top" } diff --git a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json index 62d746878..2177d9c7a 100644 --- a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json +++ b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_command_front_blink", + "cursor": "computercraft:block/computer_blink", + "front": "computercraft:block/computer_command_front", "side": "computercraft:block/computer_command_side", "top": "computercraft:block/computer_command_top" } diff --git a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_on.json b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_on.json index 36c6f0fa6..e4c5d608b 100644 --- a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_on.json +++ b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_command_on.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_command_front_on", + "cursor": "computercraft:block/computer_on", + "front": "computercraft:block/computer_command_front", "side": "computercraft:block/computer_command_side", "top": "computercraft:block/computer_command_top" } diff --git a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json index 7250268d7..a2f258290 100644 --- a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json +++ b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_normal_front_blink", + "cursor": "computercraft:block/computer_blink", + "front": "computercraft:block/computer_normal_front", "side": "computercraft:block/computer_normal_side", "top": "computercraft:block/computer_normal_top" } diff --git a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json index da2e671fe..e8dc8eb0c 100644 --- a/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json +++ b/projects/fabric/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_normal_front_on", + "cursor": "computercraft:block/computer_on", + "front": "computercraft:block/computer_normal_front", "side": "computercraft:block/computer_normal_side", "top": "computercraft:block/computer_normal_top" } diff --git a/projects/fabric/src/generated/resources/assets/minecraft/atlases/blocks.json b/projects/fabric/src/generated/resources/assets/minecraft/atlases/blocks.json new file mode 100644 index 000000000..d9d236296 --- /dev/null +++ b/projects/fabric/src/generated/resources/assets/minecraft/atlases/blocks.json @@ -0,0 +1,6 @@ +{ + "sources": [ + {"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_left"}, + {"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_right"} + ] +} diff --git a/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java b/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java index 40e5135a8..8c9340bca 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java +++ b/projects/fabric/src/main/java/dan200/computercraft/data/FabricDataGenerators.java @@ -4,21 +4,25 @@ package dan200.computercraft.data; +import com.mojang.serialization.Codec; import dan200.computercraft.shared.platform.RegistryWrappers; import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint; import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator; import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput; +import net.fabricmc.fabric.api.datagen.v1.provider.FabricCodecDataProvider; import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider; import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider; import net.fabricmc.fabric.api.datagen.v1.provider.SimpleFabricLootTableProvider; import net.minecraft.core.HolderLookup; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; +import net.minecraft.data.PackOutput; import net.minecraft.data.loot.LootTableProvider; import net.minecraft.data.models.BlockModelGenerators; import net.minecraft.data.models.ItemModelGenerators; import net.minecraft.data.tags.TagsProvider; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; @@ -43,6 +47,27 @@ public class FabricDataGenerators implements DataGeneratorEntrypoint { return generator.addProvider(factory); } + @Override + public void addFromCodec(String name, PackType type, String directory, Codec codec, Consumer> output) { + generator.addProvider((FabricDataOutput out) -> { + var ourType = switch (type) { + case SERVER_DATA -> PackOutput.Target.DATA_PACK; + case CLIENT_RESOURCES -> PackOutput.Target.RESOURCE_PACK; + }; + return new FabricCodecDataProvider(out, ourType, directory, codec) { + @Override + public String getName() { + return name; + } + + @Override + protected void configure(BiConsumer provider) { + output.accept(provider); + } + }; + }); + } + @Override public void lootTable(List tables) { for (var table : tables) { diff --git a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java index 1cf67972b..0c08744c4 100644 --- a/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java +++ b/projects/fabric/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java @@ -256,12 +256,6 @@ public class PlatformHelperImpl implements PlatformHelper { return fuel == null ? 0 : fuel; } - @Nullable - @Override - public ResourceLocation getCreativeTabId(CreativeModeTab tab) { - return tab.getId(); - } - @Override public ItemStack getCraftingRemainingItem(ItemStack stack) { return stack.getRecipeRemainder(); diff --git a/projects/forge/src/generated/resources/assets/computercraft/lang/en_us.json b/projects/forge/src/generated/resources/assets/computercraft/lang/en_us.json index 4c1351f43..845d71ec6 100644 --- a/projects/forge/src/generated/resources/assets/computercraft/lang/en_us.json +++ b/projects/forge/src/generated/resources/assets/computercraft/lang/en_us.json @@ -104,6 +104,14 @@ "gui.computercraft.config.http.max_requests.tooltip": "The number of http requests a computer can make at one time. Additional requests\nwill be queued, and sent when the running requests have finished. Set to 0 for\nunlimited.\nRange: > 0", "gui.computercraft.config.http.max_websockets": "Maximum concurrent websockets", "gui.computercraft.config.http.max_websockets.tooltip": "The number of websockets a computer can have open at one time. Set to 0 for unlimited.\nRange: > 1", + "gui.computercraft.config.http.proxy": "Proxy", + "gui.computercraft.config.http.proxy.host": "Host name", + "gui.computercraft.config.http.proxy.host.tooltip": "The hostname or IP address of the proxy server.", + "gui.computercraft.config.http.proxy.port": "Port", + "gui.computercraft.config.http.proxy.port.tooltip": "The port of the proxy server.\nRange: 1 ~ 65536", + "gui.computercraft.config.http.proxy.tooltip": "Tunnels HTTP and websocket requests through a proxy server. Only affects HTTP\nrules with \"use_proxy\" set to true (off by default).\nIf authentication is required for the proxy, create a \"computercraft-proxy.pw\"\nfile in the same directory as \"computercraft-server.toml\", containing the\nusername and password separated by a colon, e.g. \"myuser:mypassword\". For\nSOCKS4 proxies only the username is required.", + "gui.computercraft.config.http.proxy.type": "Proxy type", + "gui.computercraft.config.http.proxy.type.tooltip": "The type of proxy to use.\nAllowed Values: HTTP, HTTPS, SOCKS4, SOCKS5", "gui.computercraft.config.http.rules": "Allow/deny rules", "gui.computercraft.config.http.rules.tooltip": "A list of rules which control behaviour of the \"http\" API for specific domains or\nIPs. Each rule is an item with a 'host' to match against, and a series of\nproperties. Rules are evaluated in order, meaning earlier rules override later\nones.\nThe host may be a domain name (\"pastebin.com\"), wildcard (\"*.pastebin.com\") or\nCIDR notation (\"127.0.0.0/8\").\nIf no rules, the domain is blocked.", "gui.computercraft.config.http.tooltip": "Controls the HTTP API", diff --git a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json index e9fccca86..652f58ae1 100644 --- a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json +++ b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_blinking.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_advanced_front_blink", + "cursor": "computercraft:block/computer_blink", + "front": "computercraft:block/computer_advanced_front", "side": "computercraft:block/computer_advanced_side", "top": "computercraft:block/computer_advanced_top" } diff --git a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json index 497c1337d..fb7ab4898 100644 --- a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json +++ b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_advanced_on.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_advanced_front_on", + "cursor": "computercraft:block/computer_on", + "front": "computercraft:block/computer_advanced_front", "side": "computercraft:block/computer_advanced_side", "top": "computercraft:block/computer_advanced_top" } diff --git a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json index 62d746878..2177d9c7a 100644 --- a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json +++ b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_blinking.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_command_front_blink", + "cursor": "computercraft:block/computer_blink", + "front": "computercraft:block/computer_command_front", "side": "computercraft:block/computer_command_side", "top": "computercraft:block/computer_command_top" } diff --git a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_on.json b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_on.json index 36c6f0fa6..e4c5d608b 100644 --- a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_on.json +++ b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_command_on.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_command_front_on", + "cursor": "computercraft:block/computer_on", + "front": "computercraft:block/computer_command_front", "side": "computercraft:block/computer_command_side", "top": "computercraft:block/computer_command_top" } diff --git a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json index 7250268d7..a2f258290 100644 --- a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json +++ b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_blinking.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_normal_front_blink", + "cursor": "computercraft:block/computer_blink", + "front": "computercraft:block/computer_normal_front", "side": "computercraft:block/computer_normal_side", "top": "computercraft:block/computer_normal_top" } diff --git a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json index da2e671fe..e8dc8eb0c 100644 --- a/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json +++ b/projects/forge/src/generated/resources/assets/computercraft/models/block/computer_normal_on.json @@ -1,7 +1,8 @@ { - "parent": "minecraft:block/orientable", + "parent": "computercraft:block/computer_on", "textures": { - "front": "computercraft:block/computer_normal_front_on", + "cursor": "computercraft:block/computer_on", + "front": "computercraft:block/computer_normal_front", "side": "computercraft:block/computer_normal_side", "top": "computercraft:block/computer_normal_top" } diff --git a/projects/forge/src/generated/resources/assets/minecraft/atlases/blocks.json b/projects/forge/src/generated/resources/assets/minecraft/atlases/blocks.json new file mode 100644 index 000000000..d9d236296 --- /dev/null +++ b/projects/forge/src/generated/resources/assets/minecraft/atlases/blocks.json @@ -0,0 +1,6 @@ +{ + "sources": [ + {"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_left"}, + {"type": "minecraft:single", "resource": "computercraft:gui/turtle_upgrade_right"} + ] +} diff --git a/projects/forge/src/main/java/dan200/computercraft/data/Generators.java b/projects/forge/src/main/java/dan200/computercraft/data/Generators.java index 840ae1acd..2ddaf757d 100644 --- a/projects/forge/src/main/java/dan200/computercraft/data/Generators.java +++ b/projects/forge/src/main/java/dan200/computercraft/data/Generators.java @@ -4,6 +4,8 @@ package dan200.computercraft.data; +import com.mojang.serialization.Codec; +import com.mojang.serialization.JsonOps; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.shared.platform.RegistryWrappers; import net.minecraft.core.HolderLookup; @@ -14,18 +16,24 @@ import net.minecraft.data.models.BlockModelGenerators; import net.minecraft.data.models.ItemModelGenerators; import net.minecraft.data.tags.ItemTagsProvider; import net.minecraft.data.tags.TagsProvider; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.PackType; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraftforge.common.data.BlockTagsProvider; import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.common.data.JsonCodecProvider; import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.CompletableFuture; +import java.util.function.BiConsumer; import java.util.function.Consumer; @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) @@ -46,6 +54,15 @@ public class Generators { return generator.addProvider(factory); } + @Override + public void addFromCodec(String name, PackType type, String directory, Codec codec, Consumer> output) { + generator.addProvider(out -> { + Map map = new HashMap<>(); + output.accept(map::put); + return new JsonCodecProvider<>(out, existingFiles, ComputerCraftAPI.MOD_ID, JsonOps.INSTANCE, type, directory, codec, map); + }); + } + @Override public void lootTable(List tables) { add(out -> new LootTableProvider(out, Set.of(), tables)); diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 3ca480232..290b8e09f 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -96,13 +96,18 @@ public class InventoryMethods implements GenericPeripheral { *

* The returned information contains the same information as each item in * {@link #list}, as well as additional details like the display name - * (`displayName`), item groups (`itemGroups`), which are the creative tabs - * an item will appear under, and item and item durability (`damage`, - * `maxDamage`, `durability`). + * (`displayName`), and item and item durability (`damage`, `maxDamage`, `durability`). *

* Some items include more information (such as enchantments) - it is * recommended to print it out using @{textutils.serialize} or in the Lua * REPL, to explore what is available. + *

+ * :::info Deprecated fields + * Older versions of CC: Tweaked exposed an {@code itemGroups} field, listing the + * creative tabs an item was available under. This information is no longer available on + * more recent versions of the game, and so this field will always be empty. Do not use this + * field in new code! + * ::: * * @param inventory The current inventory. * @param slot The slot to get information about. @@ -119,10 +124,6 @@ public class InventoryMethods implements GenericPeripheral { * print(("%s (%s)"):format(item.displayName, item.name)) * print(("Count: %d/%d"):format(item.count, item.maxCount)) * - * for _, group in pairs(item.itemGroups) do - * print(("Group: %s"):format(group.displayName)) - * end - * * if item.damage then * print(("Damage: %d/%d"):format(item.damage, item.maxDamage)) * end diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java b/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java index 250ccbc2d..41154448c 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/platform/PlatformHelperImpl.java @@ -38,7 +38,6 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.UseOnContext; @@ -52,7 +51,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.CreativeModeTabRegistry; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.Tags; import net.minecraftforge.common.ToolActions; @@ -258,12 +256,6 @@ public class PlatformHelperImpl implements PlatformHelper { return ForgeHooks.getBurnTime(stack, null); } - @Nullable - @Override - public ResourceLocation getCreativeTabId(CreativeModeTab tab) { - return CreativeModeTabRegistry.getName(tab); - } - @Override public ItemStack getCraftingRemainingItem(ItemStack stack) { return stack.getCraftingRemainingItem();