mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2026-09-19 15:50:43 +00:00
Update to Minecraft 26.2
- Move block and item ids into separate API-accessible classes, to match vanilla. - Switch to Fabric's built-in permission API. We no longer need to optionally support fabric-permission-api, which makes things a bit simpler. - Lots of rendering changes. Crucially, switch monitor rendering back to using VBOs, using the new FeatureRenderer system. This currently requires mixins on Fabric, but there's a PR open to add an API for it in the future.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.api;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
/**
|
||||
* The identifiers of blocks provided by ComputerCraft.
|
||||
*
|
||||
* @see net.minecraft.references.BlockIds
|
||||
* @see ComputerCraftBlockItemIds
|
||||
*/
|
||||
public final class ComputerCraftBlockIds {
|
||||
public static final ResourceKey<Block> COMPUTER_NORMAL = ComputerCraftBlockItemIds.COMPUTER_NORMAL.block();
|
||||
public static final ResourceKey<Block> COMPUTER_ADVANCED = ComputerCraftBlockItemIds.COMPUTER_ADVANCED.block();
|
||||
public static final ResourceKey<Block> COMPUTER_COMMAND = ComputerCraftBlockItemIds.COMPUTER_COMMAND.block();
|
||||
|
||||
public static final ResourceKey<Block> TURTLE_NORMAL = ComputerCraftBlockItemIds.TURTLE_NORMAL.block();
|
||||
public static final ResourceKey<Block> TURTLE_ADVANCED = ComputerCraftBlockItemIds.TURTLE_ADVANCED.block();
|
||||
|
||||
public static final ResourceKey<Block> CABLE = create("cable");
|
||||
public static final ResourceKey<Block> DISK_DRIVE = ComputerCraftBlockItemIds.DISK_DRIVE.block();
|
||||
public static final ResourceKey<Block> MONITOR_ADVANCED = ComputerCraftBlockItemIds.MONITOR_ADVANCED.block();
|
||||
public static final ResourceKey<Block> MONITOR_NORMAL = ComputerCraftBlockItemIds.MONITOR_NORMAL.block();
|
||||
public static final ResourceKey<Block> PRINTER = ComputerCraftBlockItemIds.PRINTER.block();
|
||||
public static final ResourceKey<Block> REDSTONE_RELAY = ComputerCraftBlockItemIds.REDSTONE_RELAY.block();
|
||||
public static final ResourceKey<Block> SPEAKER = ComputerCraftBlockItemIds.SPEAKER.block();
|
||||
public static final ResourceKey<Block> WIRED_MODEM_FULL = ComputerCraftBlockItemIds.WIRED_MODEM_FULL.block();
|
||||
public static final ResourceKey<Block> WIRELESS_MODEM_ADVANCED = ComputerCraftBlockItemIds.WIRELESS_MODEM_ADVANCED.block();
|
||||
public static final ResourceKey<Block> WIRELESS_MODEM_NORMAL = ComputerCraftBlockItemIds.WIRELESS_MODEM_NORMAL.block();
|
||||
|
||||
public static final ResourceKey<Block> LECTERN = create("lectern");
|
||||
|
||||
private static ResourceKey<Block> create(String id) {
|
||||
return ResourceKey.create(Registries.BLOCK, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, id));
|
||||
}
|
||||
|
||||
private ComputerCraftBlockIds() {
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.api;
|
||||
|
||||
import net.minecraft.references.BlockItemId;
|
||||
import net.minecraft.resources.Identifier;
|
||||
|
||||
/**
|
||||
* The identifiers of blocks and items provided by ComputerCraft.
|
||||
*
|
||||
* @see net.minecraft.references.BlockItemIds
|
||||
* @see ComputerCraftBlockIds
|
||||
* @see ComputerCraftItemIds
|
||||
*/
|
||||
public final class ComputerCraftBlockItemIds {
|
||||
public static final BlockItemId COMPUTER_NORMAL = create("computer_normal");
|
||||
public static final BlockItemId COMPUTER_ADVANCED = create("computer_advanced");
|
||||
public static final BlockItemId COMPUTER_COMMAND = create("computer_command");
|
||||
|
||||
public static final BlockItemId TURTLE_NORMAL = create("turtle_normal");
|
||||
public static final BlockItemId TURTLE_ADVANCED = create("turtle_advanced");
|
||||
|
||||
public static final BlockItemId DISK_DRIVE = create("disk_drive");
|
||||
public static final BlockItemId MONITOR_ADVANCED = create("monitor_advanced");
|
||||
public static final BlockItemId MONITOR_NORMAL = create("monitor_normal");
|
||||
public static final BlockItemId PRINTER = create("printer");
|
||||
public static final BlockItemId REDSTONE_RELAY = create("redstone_relay");
|
||||
public static final BlockItemId SPEAKER = create("speaker");
|
||||
public static final BlockItemId WIRED_MODEM_FULL = create("wired_modem_full");
|
||||
public static final BlockItemId WIRELESS_MODEM_ADVANCED = create("wireless_modem_advanced");
|
||||
public static final BlockItemId WIRELESS_MODEM_NORMAL = create("wireless_modem_normal");
|
||||
|
||||
private static BlockItemId create(String name) {
|
||||
var id = Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name);
|
||||
return BlockItemId.create(id, id);
|
||||
}
|
||||
|
||||
private ComputerCraftBlockItemIds() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.api;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
/**
|
||||
* The identifiers of items provided by ComputerCraft.
|
||||
*
|
||||
* @see net.minecraft.references.ItemIds
|
||||
* @see ComputerCraftBlockItemIds
|
||||
*/
|
||||
public final class ComputerCraftItemIds {
|
||||
public static final ResourceKey<Item> COMPUTER_NORMAL = ComputerCraftBlockItemIds.COMPUTER_NORMAL.item();
|
||||
public static final ResourceKey<Item> COMPUTER_ADVANCED = ComputerCraftBlockItemIds.COMPUTER_ADVANCED.item();
|
||||
public static final ResourceKey<Item> COMPUTER_COMMAND = ComputerCraftBlockItemIds.COMPUTER_COMMAND.item();
|
||||
|
||||
public static final ResourceKey<Item> TURTLE_NORMAL = ComputerCraftBlockItemIds.TURTLE_NORMAL.item();
|
||||
public static final ResourceKey<Item> TURTLE_ADVANCED = ComputerCraftBlockItemIds.TURTLE_ADVANCED.item();
|
||||
|
||||
public static final ResourceKey<Item> POCKET_COMPUTER_NORMAL = create("pocket_computer_normal");
|
||||
public static final ResourceKey<Item> POCKET_COMPUTER_ADVANCED = create("pocket_computer_advanced");
|
||||
|
||||
public static final ResourceKey<Item> DISK = create("disk");
|
||||
public static final ResourceKey<Item> TREASURE_DISK = create("treasure_disk");
|
||||
|
||||
public static final ResourceKey<Item> PRINTED_PAGE = create("printed_page");
|
||||
public static final ResourceKey<Item> PRINTED_PAGES = create("printed_pages");
|
||||
public static final ResourceKey<Item> PRINTED_BOOK = create("printed_book");
|
||||
|
||||
public static final ResourceKey<Item> CABLE = create("cable");
|
||||
public static final ResourceKey<Item> DISK_DRIVE = ComputerCraftBlockItemIds.DISK_DRIVE.item();
|
||||
public static final ResourceKey<Item> MONITOR_ADVANCED = ComputerCraftBlockItemIds.MONITOR_ADVANCED.item();
|
||||
public static final ResourceKey<Item> MONITOR_NORMAL = ComputerCraftBlockItemIds.MONITOR_NORMAL.item();
|
||||
public static final ResourceKey<Item> PRINTER = ComputerCraftBlockItemIds.PRINTER.item();
|
||||
public static final ResourceKey<Item> REDSTONE_RELAY = ComputerCraftBlockItemIds.REDSTONE_RELAY.item();
|
||||
public static final ResourceKey<Item> SPEAKER = ComputerCraftBlockItemIds.SPEAKER.item();
|
||||
public static final ResourceKey<Item> WIRED_MODEM = create("wired_modem");
|
||||
public static final ResourceKey<Item> WIRED_MODEM_FULL = ComputerCraftBlockItemIds.WIRED_MODEM_FULL.item();
|
||||
public static final ResourceKey<Item> WIRELESS_MODEM_ADVANCED = ComputerCraftBlockItemIds.WIRELESS_MODEM_ADVANCED.item();
|
||||
public static final ResourceKey<Item> WIRELESS_MODEM_NORMAL = ComputerCraftBlockItemIds.WIRELESS_MODEM_NORMAL.item();
|
||||
|
||||
private static ResourceKey<Item> create(String id) {
|
||||
return ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, id));
|
||||
}
|
||||
|
||||
private ComputerCraftItemIds() {
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ package dan200.computercraft.api;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.tags.BlockItemTagId;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -21,11 +22,11 @@ import net.minecraft.world.phys.BlockHitResult;
|
||||
* Tags provided by ComputerCraft.
|
||||
*/
|
||||
public class ComputerCraftTags {
|
||||
public static class Items {
|
||||
public static final TagKey<Item> COMPUTER = make("computer");
|
||||
public static final TagKey<Item> TURTLE = make("turtle");
|
||||
public static final TagKey<Item> WIRED_MODEM = make("wired_modem");
|
||||
public static final TagKey<Item> MONITOR = make("monitor");
|
||||
public static final class Items {
|
||||
public static final TagKey<Item> COMPUTER = BlockItems.COMPUTER.item();
|
||||
public static final TagKey<Item> TURTLE = BlockItems.TURTLE.item();
|
||||
public static final TagKey<Item> WIRED_MODEM = BlockItems.WIRED_MODEM.item();
|
||||
public static final TagKey<Item> MONITOR = BlockItems.MONITOR.item();
|
||||
|
||||
/**
|
||||
* Floppy disks. Both the read/write version, and treasure disks.
|
||||
@@ -60,13 +61,16 @@ public class ComputerCraftTags {
|
||||
private static TagKey<Item> make(String name) {
|
||||
return TagKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name));
|
||||
}
|
||||
|
||||
private Items() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class Blocks {
|
||||
public static final TagKey<Block> COMPUTER = make("computer");
|
||||
public static final TagKey<Block> TURTLE = make("turtle");
|
||||
public static final TagKey<Block> WIRED_MODEM = make("wired_modem");
|
||||
public static final TagKey<Block> MONITOR = make("monitor");
|
||||
public static final class Blocks {
|
||||
public static final TagKey<Block> COMPUTER = BlockItems.COMPUTER.block();
|
||||
public static final TagKey<Block> TURTLE = BlockItems.TURTLE.block();
|
||||
public static final TagKey<Block> WIRED_MODEM = BlockItems.WIRED_MODEM.block();
|
||||
public static final TagKey<Block> MONITOR = BlockItems.MONITOR.block();
|
||||
|
||||
/**
|
||||
* Blocks which should be ignored by a {@code peripheral_hub} peripheral.
|
||||
@@ -102,8 +106,26 @@ public class ComputerCraftTags {
|
||||
*/
|
||||
public static final TagKey<Block> TURTLE_CAN_USE = make("turtle_can_use");
|
||||
|
||||
private Blocks() {
|
||||
}
|
||||
|
||||
private static TagKey<Block> make(String name) {
|
||||
return TagKey.create(Registries.BLOCK, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class BlockItems {
|
||||
public static final BlockItemTagId COMPUTER = make("computer");
|
||||
public static final BlockItemTagId TURTLE = make("turtle");
|
||||
public static final BlockItemTagId WIRED_MODEM = make("wired_modem");
|
||||
public static final BlockItemTagId MONITOR = make("monitor");
|
||||
|
||||
private BlockItems() {
|
||||
}
|
||||
|
||||
private static BlockItemTagId make(String name) {
|
||||
var id = Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name);
|
||||
return BlockItemTagId.create(id, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,11 @@ import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.gui.screens.inventory.MenuAccess;
|
||||
import net.minecraft.client.model.geom.ModelLayerLocation;
|
||||
import net.minecraft.client.model.geom.builders.LayerDefinition;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
import net.minecraft.client.renderer.feature.FeatureRenderer;
|
||||
import net.minecraft.client.renderer.feature.FeatureRendererType;
|
||||
import net.minecraft.client.renderer.feature.submit.SubmitNode;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperty;
|
||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
|
||||
@@ -56,7 +58,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
@@ -208,7 +209,7 @@ public final class ClientRegistry {
|
||||
}
|
||||
|
||||
public interface RegisterPictureInPictureRenderer {
|
||||
<T extends PictureInPictureRenderState> void register(Class<T> state, Function<MultiBufferSource.BufferSource, PictureInPictureRenderer<T>> factory);
|
||||
<T extends PictureInPictureRenderState> void register(Class<T> state, Supplier<PictureInPictureRenderer<T>> factory);
|
||||
}
|
||||
|
||||
public static void registerPictureInPictureRenderers(RegisterPictureInPictureRenderer register) {
|
||||
@@ -218,4 +219,12 @@ public final class ClientRegistry {
|
||||
public static void registerDebugScreenEntries(BiConsumer<Identifier, DebugScreenEntry> register) {
|
||||
register.accept(LookingAtBlockEntityDebugEntry.ID, LookingAtBlockEntityDebugEntry.create());
|
||||
}
|
||||
|
||||
public interface RegisterFeatureRenderer {
|
||||
<T extends SubmitNode> void register(FeatureRendererType<T> type, Supplier<FeatureRenderer<T>> renderer);
|
||||
}
|
||||
|
||||
public static void registerFeatureRenderers(RegisterFeatureRenderer register) {
|
||||
register.register(MonitorBlockEntityRenderer.MonitorFeatureRenderer.TYPE, MonitorBlockEntityRenderer.MonitorFeatureRenderer::new);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -61,7 +61,7 @@ public class ClientTableFormatter implements TableFormatter {
|
||||
@Override
|
||||
public void writeLine(String label, Component component) {
|
||||
var mc = Minecraft.getInstance();
|
||||
var chat = mc.gui.getChat();
|
||||
var chat = mc.gui.hud.getChat();
|
||||
|
||||
// TODO: Trim the text if it goes over the allowed length
|
||||
// int maxWidth = MathHelper.floor( chat.getChatWidth() / chat.getScale() );
|
||||
@@ -72,7 +72,7 @@ public class ClientTableFormatter implements TableFormatter {
|
||||
|
||||
@Override
|
||||
public void display(TableBuilder table) {
|
||||
var chat = Minecraft.getInstance().gui.getChat();
|
||||
var chat = Minecraft.getInstance().gui.hud.getChat();
|
||||
|
||||
var tag = createTag(table.getId());
|
||||
if (chat.allMessages.removeIf(guiMessage -> guiMessage.tag() != null && Objects.equals(guiMessage.tag().logTag(), tag.logTag()))) {
|
||||
|
||||
+2
-2
@@ -101,7 +101,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
|
||||
if (uploadNagDeadline != Long.MAX_VALUE && Util.getNanos() >= uploadNagDeadline) {
|
||||
new ItemToast(minecraft, displayStack, NO_RESPONSE_TITLE, NO_RESPONSE_MSG, ItemToast.TRANSFER_NO_RESPONSE_TOKEN)
|
||||
.showOrReplace(minecraft.getToastManager());
|
||||
.showOrReplace(minecraft.gui.toastManager());
|
||||
uploadNagDeadline = Long.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
@@ -230,7 +230,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
|
||||
private void alert(Component title, Component message) {
|
||||
OptionScreen.show(minecraft, this, title, message,
|
||||
List.of(OptionScreen.newButton(OK, b -> minecraft.setScreen(this)))
|
||||
List.of(OptionScreen.newButton(OK, b -> minecraft.gui.setScreen(this)))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
|
||||
// First ensure we're still grabbing the mouse, so the user can look around. Then reset bits of state that
|
||||
// grabbing unsets.
|
||||
minecraft.mouseHandler.grabMouse();
|
||||
minecraft.screen = this;
|
||||
minecraft.gui.screen = this;
|
||||
KeyMapping.releaseAll();
|
||||
|
||||
super.init();
|
||||
|
||||
@@ -52,7 +52,7 @@ public final class OptionScreen extends Screen {
|
||||
}
|
||||
|
||||
public static void show(Minecraft minecraft, Screen originalScreen, Component title, Component message, List<AbstractWidget> buttons) {
|
||||
minecraft.setScreen(new OptionScreen(title, message, buttons, unwrap(originalScreen)));
|
||||
minecraft.gui.setScreen(new OptionScreen(title, message, buttons, unwrap(originalScreen)));
|
||||
}
|
||||
|
||||
@Contract("!null -> !null")
|
||||
@@ -106,7 +106,7 @@ public final class OptionScreen extends Screen {
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
minecraft.setScreen(originalScreen);
|
||||
minecraft.gui.setScreen(originalScreen);
|
||||
}
|
||||
|
||||
public static AbstractWidget newButton(Component component, Button.OnPress clicked) {
|
||||
|
||||
+10
-12
@@ -6,6 +6,7 @@ package dan200.computercraft.client.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.render.PrintoutRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.media.PrintoutMenu;
|
||||
@@ -15,7 +16,7 @@ import net.minecraft.client.gui.navigation.ScreenRectangle;
|
||||
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
|
||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||
import net.minecraft.client.input.KeyEvent;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.state.gui.GuiElementRenderState;
|
||||
import net.minecraft.client.renderer.state.gui.pip.PictureInPictureRenderState;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@@ -176,23 +177,20 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
|
||||
* multiple z-levels.
|
||||
*/
|
||||
public static final class PrintoutPictureRenderer extends PictureInPictureRenderer<PrintoutRenderState> {
|
||||
public PrintoutPictureRenderer(MultiBufferSource.BufferSource bufferSource) {
|
||||
super(bufferSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderToTexture(PrintoutRenderState state, PoseStack pose) {
|
||||
protected void renderToTexture(PrintoutRenderState state, PoseStack pose, SubmitNodeCollector collector) {
|
||||
pose.pushPose();
|
||||
pose.translate(-0.5f * X_SIZE, -(Y_SIZE + COVER_SIZE), 0);
|
||||
pose.scale(1.0f, 1.0f, -1.0f);
|
||||
|
||||
var buffer = bufferSource.getBuffer(PrintoutRenderer.BACKGROUND);
|
||||
drawBorder(pose.last().pose(), buffer, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightCoordsUtil.FULL_BRIGHT);
|
||||
|
||||
drawText(
|
||||
pose, bufferSource, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightCoordsUtil.FULL_BRIGHT,
|
||||
state.printout().text(), state.printout().colour()
|
||||
collector.submitCustomGeometry(pose, PrintoutRenderer.BACKGROUND, (p, buffer) -> drawBorder(
|
||||
p.pose(), buffer, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightCoordsUtil.FULL_BRIGHT)
|
||||
);
|
||||
collector.submitCustomGeometry(pose, FixedWidthFontRenderer.TERMINAL_TEXT, (p, buffer) -> drawText(
|
||||
p.pose(), buffer, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightCoordsUtil.FULL_BRIGHT,
|
||||
state.printout().text(), state.printout().colour()
|
||||
));
|
||||
|
||||
pose.popPose();
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ public final class ClientNetworkContextImpl implements ClientNetworkContext {
|
||||
public void handleUploadResult(int containerId, UploadResult result, @Nullable Component errorMessage) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
|
||||
var screen = OptionScreen.unwrap(minecraft.screen);
|
||||
var screen = OptionScreen.unwrap(minecraft.gui.screen());
|
||||
if (screen instanceof AbstractComputerScreen<?> && ((AbstractComputerScreen<?>) screen).getMenu().containerId == containerId) {
|
||||
((AbstractComputerScreen<?>) screen).uploadResult(result, errorMessage);
|
||||
}
|
||||
|
||||
+18
@@ -4,7 +4,11 @@
|
||||
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.minecraft.client.renderer.OrderedSubmitNodeCollector;
|
||||
import net.minecraft.client.resources.model.ModelDebugName;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
@@ -25,6 +29,20 @@ public interface ClientPlatformHelper {
|
||||
@Contract("_ -> new")
|
||||
<T> ModelKey<T> createModelKey(ModelDebugName name);
|
||||
|
||||
/**
|
||||
* Submit a monitor to be rendered.
|
||||
*
|
||||
* @param collector The submit node collector.
|
||||
* @param poseStack The current translation.
|
||||
* @param monitor The monitor to draw.
|
||||
* @param terminal The terminal contents of the monitor.
|
||||
* @param xMargin The X margin.
|
||||
* @param yMargin The Y margin.
|
||||
*/
|
||||
void submitMonitor(
|
||||
OrderedSubmitNodeCollector collector, PoseStack poseStack, ClientMonitor monitor, Terminal terminal, float xMargin, float yMargin
|
||||
);
|
||||
|
||||
final class Instance {
|
||||
static final @Nullable ClientPlatformHelper INSTANCE;
|
||||
static final @Nullable Throwable ERROR;
|
||||
|
||||
+18
-6
@@ -10,7 +10,7 @@ import dan200.computercraft.client.ClientHooks;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.rendertype.RenderTypes;
|
||||
import net.minecraft.client.renderer.state.level.LevelRenderState;
|
||||
import net.minecraft.util.ARGB;
|
||||
@@ -32,20 +32,32 @@ public final class BlockOutlineRenderer {
|
||||
* @param transform The current transformations.
|
||||
* @param bufferSource The buffer source.
|
||||
* @param renderer The function to render a highlight.
|
||||
* @see LevelRenderer#renderBlockOutline(MultiBufferSource.BufferSource, PoseStack, boolean, LevelRenderState)
|
||||
* @param camera The current camera.
|
||||
* @param hit The hit result of the block we're rendering.
|
||||
* @see LevelRenderer#submitBlockOutline(PoseStack, SubmitNodeCollector, LevelRenderState)
|
||||
*/
|
||||
public static void render(PoseStack transform, MultiBufferSource bufferSource, Renderer renderer) {
|
||||
public static void render(PoseStack transform, SubmitNodeCollector bufferSource, Renderer renderer, Camera camera, BlockHitResult hit) {
|
||||
var cameraPos = camera.position();
|
||||
var xOffset = hit.getBlockPos().getX() - cameraPos.x();
|
||||
var yOffset = hit.getBlockPos().getY() - cameraPos.y();
|
||||
var zOffset = hit.getBlockPos().getZ() - cameraPos.z();
|
||||
|
||||
transform.pushPose();
|
||||
transform.translate(xOffset, yOffset, zOffset);
|
||||
|
||||
var highContrast = Minecraft.getInstance().options.highContrastBlockOutline().get();
|
||||
if (highContrast) {
|
||||
renderer.render(transform, bufferSource.getBuffer(RenderTypes.secondaryBlockOutline()), 0xff000000, 7f);
|
||||
bufferSource.submitCustomGeometry(transform, RenderTypes.secondaryBlockOutline(), (p, b) -> renderer.render(p, b, 0xff000000, 7f));
|
||||
}
|
||||
|
||||
var colour = highContrast ? CommonColors.HIGH_CONTRAST_DIAMOND : ARGB.color(0x66, CommonColors.BLACK);
|
||||
renderer.render(transform, bufferSource.getBuffer(RenderTypes.lines()), colour, Minecraft.getInstance().getWindow().getAppropriateLineWidth());
|
||||
bufferSource.submitCustomGeometry(transform, RenderTypes.lines(), (p, b) -> renderer.render(p, b, colour, Minecraft.getInstance().getWindow().getAppropriateLineWidth()));
|
||||
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Renderer {
|
||||
void render(PoseStack transform, VertexConsumer buffer, int colour, float width);
|
||||
void render(PoseStack.Pose transform, VertexConsumer buffer, int colour, float width);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-9
@@ -9,8 +9,8 @@ import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableShapes;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.renderer.ShapeRenderer;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import org.joml.Vector3f;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public final class CableHighlightRenderer {
|
||||
@@ -25,11 +25,10 @@ public final class CableHighlightRenderer {
|
||||
* @return The custom renderer.
|
||||
*/
|
||||
public static BlockOutlineRenderer.@Nullable Renderer drawHighlight(Camera camera, BlockHitResult hit) {
|
||||
var pos = hit.getBlockPos();
|
||||
|
||||
var player = camera.entity();
|
||||
if (player == null) return null;
|
||||
|
||||
var pos = hit.getBlockPos();
|
||||
var state = player.level().getBlockState(pos);
|
||||
|
||||
// We only care about instances with both cable and modem.
|
||||
@@ -41,11 +40,13 @@ public final class CableHighlightRenderer {
|
||||
? CableShapes.getModemShape(state)
|
||||
: CableShapes.getCableShape(state);
|
||||
|
||||
var cameraPos = camera.position();
|
||||
var xOffset = pos.getX() - cameraPos.x();
|
||||
var yOffset = pos.getY() - cameraPos.y();
|
||||
var zOffset = pos.getZ() - cameraPos.z();
|
||||
|
||||
return (transform, buffer, colour, width) -> ShapeRenderer.renderShape(transform, buffer, shape, xOffset, yOffset, zOffset, colour, width);
|
||||
return (transform, buffer, colour, width) -> {
|
||||
var normal = new Vector3f();
|
||||
shape.forAllEdges((x1, y1, z1, x2, y2, z2) -> {
|
||||
normal.set((float) (x2 - x1), (float) (y2 - y1), (float) (z2 - z1)).normalize();
|
||||
buffer.addVertex(transform, (float) x1, (float) y1, (float) z1).setColor(colour).setNormal(transform, normal).setLineWidth(width);
|
||||
buffer.addVertex(transform, (float) x2, (float) y2, (float) z2).setColor(colour).setNormal(transform, normal).setLineWidth(width);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -4,13 +4,11 @@
|
||||
|
||||
package dan200.computercraft.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Palette;
|
||||
import dan200.computercraft.core.terminal.TextBuffer;
|
||||
import dan200.computercraft.shared.media.items.PrintoutData;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.rendertype.RenderType;
|
||||
import net.minecraft.client.renderer.rendertype.RenderTypes;
|
||||
import net.minecraft.resources.Identifier;
|
||||
@@ -73,11 +71,10 @@ public final class PrintoutRenderer {
|
||||
private PrintoutRenderer() {
|
||||
}
|
||||
|
||||
public static void drawText(PoseStack transform, MultiBufferSource bufferSource, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours) {
|
||||
var buffer = bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT);
|
||||
public static void drawText(Matrix4f matrix, VertexConsumer buffer, int x, int y, int start, int light, TextBuffer[] text, TextBuffer[] colours) {
|
||||
for (var line = 0; line < LINES_PER_PAGE && line < text.length; line++) {
|
||||
FixedWidthFontRenderer.drawString(
|
||||
transform.last().pose(), buffer,
|
||||
matrix, buffer,
|
||||
x, y + line * FONT_HEIGHT, text[start + line], colours[start + line],
|
||||
Palette.DEFAULT, light
|
||||
);
|
||||
|
||||
-1
@@ -122,7 +122,6 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer<TurtleBloc
|
||||
if (state.label != null) {
|
||||
collector.submitNameTag(
|
||||
transform, new Vec3(0.5, 1.2, 0.5), 0, Component.literal(state.label), false, state.lightCoords,
|
||||
camera.pos.distanceToSqr(Vec3.atCenterOf(state.blockPos)), // TODO: Should we read camera from the render state instead?
|
||||
camera
|
||||
);
|
||||
}
|
||||
|
||||
+84
-89
@@ -5,13 +5,13 @@
|
||||
package dan200.computercraft.client.render.monitor;
|
||||
|
||||
import com.mojang.blaze3d.buffers.GpuBuffer;
|
||||
import com.mojang.blaze3d.pipeline.RenderPipeline;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import dan200.computercraft.annotations.ForgeOverride;
|
||||
import dan200.computercraft.client.FrameInfo;
|
||||
import dan200.computercraft.client.integration.ShaderMod;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.render.text.DirectFixedWidthFontRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
@@ -21,27 +21,26 @@ import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.RenderPipelines;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.feature.FeatureFrameContext;
|
||||
import net.minecraft.client.renderer.feature.FeatureRenderer;
|
||||
import net.minecraft.client.renderer.feature.FeatureRendererType;
|
||||
import net.minecraft.client.renderer.feature.ModelFeatureRenderer;
|
||||
import net.minecraft.client.renderer.feature.submit.SubmitNode;
|
||||
import net.minecraft.client.renderer.fog.FogRenderer;
|
||||
import net.minecraft.client.renderer.rendertype.RenderType;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.lwjgl.system.MemoryUtil;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.List;
|
||||
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_HEIGHT;
|
||||
import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FONT_WIDTH;
|
||||
@@ -112,13 +111,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
var xMargin = (float) (MARGIN / xScale);
|
||||
var yMargin = (float) (MARGIN / yScale);
|
||||
|
||||
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> {
|
||||
FixedWidthFontRenderer.drawTerminalBackground(pose.pose(), buffer, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin);
|
||||
});
|
||||
collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, (pose, buffer) -> {
|
||||
FixedWidthFontRenderer.drawTerminalForeground(pose.pose(), buffer, 0, 0, terminal);
|
||||
FixedWidthFontRenderer.drawCursor(pose.pose(), buffer, 0, 0, terminal);
|
||||
});
|
||||
ClientPlatformHelper.get().submitMonitor(collector, transform, state.terminal, terminal, xMargin, yMargin);
|
||||
|
||||
transform.popPose();
|
||||
} else {
|
||||
@@ -128,8 +121,8 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
transform.popPose();
|
||||
}
|
||||
|
||||
private static void renderTerminal(
|
||||
Matrix4f matrix, ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
|
||||
private static void prepareTerminal(
|
||||
ClientMonitor monitor, MonitorRenderState renderState, Terminal terminal, float xMargin, float yMargin
|
||||
) {
|
||||
var redraw = monitor.pollTerminalChanged();
|
||||
if (renderState.vertexBuffer == null) redraw = true;
|
||||
@@ -186,79 +179,6 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
renderState.vertexCountAfterForeground = vertexCountAfterForeground;
|
||||
renderState.vertexCountAfterCursor = vertexCountAfterCursor;
|
||||
}
|
||||
|
||||
if (renderState.vertexCountAfterCursor == 0) return;
|
||||
|
||||
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
|
||||
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
|
||||
// normal render distance (~200), and the edges of the monitor fade out due to fog.
|
||||
// There's not really a good way around this, at least without using a custom render type (which the VBO
|
||||
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
|
||||
// absurdly high value.
|
||||
var oldFog = Nullability.assertNonNull(RenderSystem.getShaderFog());
|
||||
RenderSystem.setShaderFog(Minecraft.getInstance().gameRenderer.fogRenderer.getBuffer(FogRenderer.FogMode.NONE));
|
||||
|
||||
// Compose the existing model view matrix with our transformation matrix.
|
||||
RenderSystem.getModelViewStack().pushMatrix();
|
||||
RenderSystem.getModelViewStack().mul(matrix);
|
||||
|
||||
// Render background geometry
|
||||
drawWithShader(renderState, FixedWidthFontRenderer.TERMINAL_TEXT, RenderPipelines.TEXT, 0, renderState.vertexCountAfterBackground);
|
||||
drawWithShader(
|
||||
renderState, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, RenderPipelines.TEXT_POLYGON_OFFSET, renderState.vertexCountAfterBackground,
|
||||
(
|
||||
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
|
||||
? renderState.vertexCountAfterCursor : renderState.vertexCountAfterForeground
|
||||
) - renderState.vertexCountAfterBackground
|
||||
);
|
||||
|
||||
// Clear state
|
||||
RenderSystem.getModelViewStack().popMatrix();
|
||||
RenderSystem.setShaderFog(oldFog);
|
||||
}
|
||||
|
||||
private static void drawWithShader(MonitorRenderState renderState, RenderType renderType, RenderPipeline pipeline, int vertexOffset, int vertexCount) {
|
||||
if (renderState.vertexBuffer == null) {
|
||||
throw new IllegalStateException("MonitorRenderState has not been initialised");
|
||||
}
|
||||
if (vertexCount == 0) return;
|
||||
|
||||
var transforms = RenderSystem.getDynamicUniforms().writeTransform(
|
||||
RenderSystem.getModelViewMatrix(),
|
||||
new Vector4f(1.0F, 1.0F, 1.0F, 1.0F),
|
||||
new Vector3f(),
|
||||
new Matrix4f()
|
||||
);
|
||||
|
||||
var autoStorageBuffer = RenderSystem.getSequentialBuffer(renderType.mode());
|
||||
var indexCount = FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(vertexCount);
|
||||
var indexBuffer = autoStorageBuffer.getBuffer(indexCount);
|
||||
|
||||
var target = Minecraft.getInstance().getMainRenderTarget();
|
||||
var colourTarget = RenderSystem.outputColorTextureOverride != null ? RenderSystem.outputColorTextureOverride : target.getColorTextureView();
|
||||
var depthTarget = target.useDepth
|
||||
? (RenderSystem.outputDepthTextureOverride != null ? RenderSystem.outputDepthTextureOverride : target.getDepthTextureView())
|
||||
: null;
|
||||
|
||||
try (var renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
|
||||
() -> "Monitor", Nullability.assertNonNull(colourTarget), OptionalInt.empty(), depthTarget, OptionalDouble.empty()
|
||||
)) {
|
||||
renderPass.setPipeline(pipeline);
|
||||
|
||||
RenderSystem.bindDefaultUniforms(renderPass);
|
||||
renderPass.setUniform("DynamicTransforms", transforms);
|
||||
renderPass.setVertexBuffer(0, renderState.vertexBuffer);
|
||||
renderPass.setIndexBuffer(indexBuffer, autoStorageBuffer.type());
|
||||
|
||||
/*
|
||||
for (var j = 0; j < 12; j++) {
|
||||
var gpuTexture = RenderSystem.getShaderTexture(j);
|
||||
if (gpuTexture != null) renderPass.bindTexture("Sampler" + j, gpuTexture);
|
||||
}
|
||||
*/
|
||||
|
||||
renderPass.drawIndexed(vertexOffset, 0, indexCount, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -296,4 +216,79 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
|
||||
private State() {
|
||||
}
|
||||
}
|
||||
|
||||
public record MonitorSubmit(
|
||||
PoseStack.Pose pose, ClientMonitor monitor, Terminal terminal, MonitorRenderState state,
|
||||
float xMargin, float yMargin
|
||||
) implements SubmitNode {
|
||||
@Override
|
||||
public FeatureRendererType<? extends SubmitNode> featureType() {
|
||||
return MonitorFeatureRenderer.TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class MonitorFeatureRenderer implements FeatureRenderer<MonitorSubmit> {
|
||||
public static final FeatureRendererType<MonitorSubmit> TYPE = FeatureRendererType.create("Monitor");
|
||||
|
||||
@Override
|
||||
public void prepareGroup(FeatureFrameContext context, List<MonitorSubmit> submits, boolean strictlyOrdered) {
|
||||
for (var submit : submits) {
|
||||
prepareTerminal(submit.monitor(), submit.state(), submit.terminal(), submit.xMargin(), submit.yMargin());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeGroup(FeatureFrameContext context, int groupIndex, List<MonitorSubmit> submits, boolean strictlyOrdered) {
|
||||
if (submits.isEmpty()) return;
|
||||
|
||||
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
|
||||
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
|
||||
// normal render distance (~200), and the edges of the monitor fade out due to fog.
|
||||
// There's not really a good way around this, at least without using a custom render type (which the VBO
|
||||
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
|
||||
// absurdly high value.
|
||||
var oldFog = Nullability.assertNonNull(RenderSystem.getShaderFog());
|
||||
RenderSystem.setShaderFog(Minecraft.getInstance().gameRenderer.fogRenderer.getBuffer(FogRenderer.FogMode.NONE));
|
||||
|
||||
var autoStorageBuffer = RenderSystem.getSequentialBuffer(FixedWidthFontRenderer.TERMINAL_TEXT.primitiveTopology());
|
||||
|
||||
for (var submit : submits) {
|
||||
// Compose the existing model view matrix with our transformation matrix.
|
||||
RenderSystem.getModelViewStack().pushMatrix();
|
||||
RenderSystem.getModelViewStack().mul(submit.pose().pose());
|
||||
|
||||
// Render geometry
|
||||
var renderState = submit.state();
|
||||
if (renderState.vertexBuffer == null) {
|
||||
throw new IllegalStateException("MonitorRenderState has not been initialised");
|
||||
}
|
||||
drawWithShader(
|
||||
renderState.vertexBuffer, autoStorageBuffer, FixedWidthFontRenderer.TERMINAL_TEXT,
|
||||
0, renderState.vertexCountAfterBackground
|
||||
);
|
||||
drawWithShader(
|
||||
renderState.vertexBuffer, autoStorageBuffer, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET,
|
||||
renderState.vertexCountAfterBackground,
|
||||
(
|
||||
FixedWidthFontRenderer.isCursorVisible(submit.terminal()) && FrameInfo.getGlobalCursorBlink()
|
||||
? renderState.vertexCountAfterCursor : renderState.vertexCountAfterForeground
|
||||
) - renderState.vertexCountAfterBackground
|
||||
);
|
||||
|
||||
RenderSystem.getModelViewStack().popMatrix();
|
||||
}
|
||||
|
||||
// Clear state
|
||||
RenderSystem.setShaderFog(oldFog);
|
||||
}
|
||||
|
||||
private static void drawWithShader(GpuBuffer buffer, RenderSystem.AutoStorageIndexBuffer autoStorageBuffer, RenderType renderType, int vertexOffset, int vertexCount) {
|
||||
if (vertexCount == 0) return;
|
||||
|
||||
var indexCount = FixedWidthFontRenderer.TERMINAL_TEXT.primitiveTopology().indexCount(vertexCount);
|
||||
renderType.prepare().drawFromBuffer(
|
||||
buffer, autoStorageBuffer.getBuffer(indexCount), autoStorageBuffer.type(), vertexOffset, 0, indexCount
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-12
@@ -31,7 +31,6 @@ public final class MonitorHighlightRenderer {
|
||||
if (player == null || player.isCrouching()) return null;
|
||||
|
||||
var pos = hit.getBlockPos();
|
||||
|
||||
if (!(player.level().getBlockEntity(pos) instanceof MonitorBlockEntity monitor)) return null;
|
||||
|
||||
// Determine which sides are part of the external faces of the monitor, and so which need to be rendered.
|
||||
@@ -43,17 +42,7 @@ public final class MonitorHighlightRenderer {
|
||||
if (monitor.getYIndex() != 0) faces.remove(monitor.getDown().getOpposite());
|
||||
if (monitor.getYIndex() != monitor.getHeight() - 1) faces.remove(monitor.getDown());
|
||||
|
||||
var cameraPos = camera.position();
|
||||
var xOffset = pos.getX() - cameraPos.x();
|
||||
var yOffset = pos.getY() - cameraPos.y();
|
||||
var zOffset = pos.getZ() - cameraPos.z();
|
||||
|
||||
return (transform, buffer, colour, width) -> {
|
||||
transform.pushPose();
|
||||
transform.translate(xOffset, yOffset, zOffset);
|
||||
draw(buffer, transform.last(), faces, colour, width);
|
||||
transform.popPose();
|
||||
};
|
||||
return (transform, buffer, colour, width) -> draw(buffer, transform, faces, colour, width);
|
||||
}
|
||||
|
||||
private static void draw(VertexConsumer buffer, PoseStack.Pose transform, EnumSet<Direction> faces, int colour, float width) {
|
||||
|
||||
+21
-21
@@ -202,7 +202,7 @@ public final class DirectFixedWidthFontRenderer {
|
||||
// Emit a single quad to our buffer. This uses Unsafe (well, LWJGL's MemoryUtil) to directly blit bytes to the
|
||||
// underlying buffer. This allows us to have a single bounds check up-front, rather than one for every write.
|
||||
// This provides significant performance gains, at the cost of well, using Unsafe.
|
||||
// Each vertex is 28 bytes, giving 112 bytes in total. Vertices are of the form (xyz:FFF)(abgr:BBBB)(uv1:FF)(uv2:SS),
|
||||
// Each vertex is 28 bytes, giving 112 bytes in total. Vertices are of the form (xyz:FFF)(uv1:FF)(uv2:SS)(abgr:BBBB),
|
||||
// which matches the POSITION_COLOR_TEX_LIGHTMAP vertex format.
|
||||
var position = buffer.position();
|
||||
var addr = MemoryUtil.memAddress(buffer);
|
||||
@@ -221,38 +221,38 @@ public final class DirectFixedWidthFontRenderer {
|
||||
memPutFloat(addr + 0, x1);
|
||||
memPutFloat(addr + 4, y1);
|
||||
memPutFloat(addr + 8, z);
|
||||
memPutInt(addr + 12, nativeColour);
|
||||
memPutFloat(addr + 16, u1);
|
||||
memPutFloat(addr + 20, v1);
|
||||
memPutShort(addr + 24, (short) 0xF0);
|
||||
memPutShort(addr + 26, (short) 0xF0);
|
||||
memPutFloat(addr + 12, u1);
|
||||
memPutFloat(addr + 16, v1);
|
||||
memPutShort(addr + 20, (short) 0xF0);
|
||||
memPutShort(addr + 22, (short) 0xF0);
|
||||
memPutInt(addr + 24, nativeColour);
|
||||
|
||||
memPutFloat(addr + 28, x1);
|
||||
memPutFloat(addr + 32, y2);
|
||||
memPutFloat(addr + 36, z);
|
||||
memPutInt(addr + 40, nativeColour);
|
||||
memPutFloat(addr + 44, u1);
|
||||
memPutFloat(addr + 48, v2);
|
||||
memPutShort(addr + 52, (short) 0xF0);
|
||||
memPutShort(addr + 54, (short) 0xF0);
|
||||
memPutFloat(addr + 40, u1);
|
||||
memPutFloat(addr + 44, v2);
|
||||
memPutShort(addr + 48, (short) 0xF0);
|
||||
memPutShort(addr + 50, (short) 0xF0);
|
||||
memPutInt(addr + 52, nativeColour);
|
||||
|
||||
memPutFloat(addr + 56, x2);
|
||||
memPutFloat(addr + 60, y2);
|
||||
memPutFloat(addr + 64, z);
|
||||
memPutInt(addr + 68, nativeColour);
|
||||
memPutFloat(addr + 72, u2);
|
||||
memPutFloat(addr + 76, v2);
|
||||
memPutShort(addr + 80, (short) 0xF0);
|
||||
memPutShort(addr + 82, (short) 0xF0);
|
||||
memPutFloat(addr + 68, u2);
|
||||
memPutFloat(addr + 72, v2);
|
||||
memPutShort(addr + 76, (short) 0xF0);
|
||||
memPutShort(addr + 78, (short) 0xF0);
|
||||
memPutInt(addr + 80, nativeColour);
|
||||
|
||||
memPutFloat(addr + 84, x2);
|
||||
memPutFloat(addr + 88, y1);
|
||||
memPutFloat(addr + 92, z);
|
||||
memPutInt(addr + 96, nativeColour);
|
||||
memPutFloat(addr + 100, u2);
|
||||
memPutFloat(addr + 104, v1);
|
||||
memPutShort(addr + 108, (short) 0xF0);
|
||||
memPutShort(addr + 110, (short) 0xF0);
|
||||
memPutFloat(addr + 96, u2);
|
||||
memPutFloat(addr + 100, v1);
|
||||
memPutShort(addr + 104, (short) 0xF0);
|
||||
memPutShort(addr + 106, (short) 0xF0);
|
||||
memPutInt(addr + 108, nativeColour);
|
||||
|
||||
// Finally increment the position.
|
||||
buffer.position(position + 112);
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ public class LevelRendererMixin {
|
||||
@ModifyExpressionValue(
|
||||
method = "submitBlockDestroyAnimation", at = @At(value = "INVOKE", target = "Ljava/util/Iterator;next()Ljava/lang/Object;")
|
||||
)
|
||||
@SuppressWarnings("unused")
|
||||
private Object submitBlockDestroyAnimation(Object breaking) {
|
||||
return getBlockDamageState((BlockBreakingRenderState) breaking);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"required": true,
|
||||
"package": "dan200.computercraft.mixin.client",
|
||||
"minVersion": "0.8",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ import dan200.computercraft.shared.data.HasComputerIdLootCondition;
|
||||
import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlock;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant;
|
||||
import net.minecraft.advancements.criterion.StatePropertiesPredicate;
|
||||
import net.minecraft.advancements.predicates.StatePropertiesPredicate;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.data.loot.LootTableProvider.SubProviderEntry;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
|
||||
@@ -28,9 +28,9 @@ import dan200.computercraft.shared.turtle.items.TurtleItem;
|
||||
import dan200.computercraft.shared.turtle.recipes.TurtleUpgradeRecipe;
|
||||
import dan200.computercraft.shared.util.ColourUtils;
|
||||
import dan200.computercraft.shared.util.RegistryHelper;
|
||||
import net.minecraft.advancements.Criterion;
|
||||
import net.minecraft.advancements.criterion.InventoryChangeTrigger;
|
||||
import net.minecraft.advancements.criterion.ItemPredicate;
|
||||
import net.minecraft.advancements.predicates.ItemPredicate;
|
||||
import net.minecraft.advancements.triggers.Criterion;
|
||||
import net.minecraft.advancements.triggers.InventoryChangeTrigger;
|
||||
import net.minecraft.core.HolderGetter;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.component.DataComponentPatch;
|
||||
|
||||
@@ -4,18 +4,26 @@
|
||||
|
||||
package dan200.computercraft.data;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftBlockIds;
|
||||
import dan200.computercraft.api.ComputerCraftBlockItemIds;
|
||||
import dan200.computercraft.api.ComputerCraftItemIds;
|
||||
import dan200.computercraft.api.ComputerCraftTags;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.integration.ExternalModTags;
|
||||
import net.minecraft.data.tags.TagAppender;
|
||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.tags.BlockItemTagAppender;
|
||||
import net.minecraft.data.tags.TagsProvider;
|
||||
import net.minecraft.references.BlockIds;
|
||||
import net.minecraft.references.BlockItemIds;
|
||||
import net.minecraft.references.ItemIds;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.tags.BlockItemTagId;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
|
||||
/**
|
||||
* Generators for block and item tags.
|
||||
@@ -25,102 +33,105 @@ import net.minecraft.world.level.block.Blocks;
|
||||
*/
|
||||
class TagProvider {
|
||||
public static void blockTags(TagConsumer<Block> tags) {
|
||||
itemAndBlockTags((b, i) -> tags.tag(b));
|
||||
tags.tag(ComputerCraftTags.Blocks.WIRED_MODEM).add(ModRegistry.Blocks.CABLE.get(), ModRegistry.Blocks.WIRED_MODEM_FULL.get());
|
||||
itemAndBlockTags(i -> tags.tag(i.block()));
|
||||
tags.tag(ComputerCraftTags.Blocks.WIRED_MODEM).add(ComputerCraftBlockIds.CABLE, ComputerCraftBlockIds.WIRED_MODEM_FULL);
|
||||
|
||||
tags.tag(ComputerCraftTags.Blocks.PERIPHERAL_HUB_IGNORE).addTag(ComputerCraftTags.Blocks.WIRED_MODEM);
|
||||
|
||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_ALWAYS_BREAKABLE).addTag(BlockTags.LEAVES).add(
|
||||
Blocks.BAMBOO, Blocks.BAMBOO_SAPLING // Bamboo isn't instabreak for some odd reason.
|
||||
BlockItemIds.BAMBOO.block(), BlockIds.BAMBOO_SAPLING // Bamboo isn't instabreak for some odd reason.
|
||||
);
|
||||
|
||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_SHOVEL_BREAKABLE).addTag(BlockTags.MINEABLE_WITH_SHOVEL).add(
|
||||
Blocks.MELON,
|
||||
Blocks.PUMPKIN,
|
||||
Blocks.CARVED_PUMPKIN,
|
||||
Blocks.JACK_O_LANTERN
|
||||
BlockItemIds.MELON,
|
||||
BlockItemIds.PUMPKIN,
|
||||
BlockItemIds.CARVED_PUMPKIN,
|
||||
BlockItemIds.JACK_O_LANTERN
|
||||
);
|
||||
|
||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_HOE_BREAKABLE).addTag(BlockTags.CROPS).addTag(BlockTags.MINEABLE_WITH_HOE).add(
|
||||
Blocks.CACTUS,
|
||||
Blocks.MELON,
|
||||
Blocks.PUMPKIN,
|
||||
Blocks.CARVED_PUMPKIN,
|
||||
Blocks.JACK_O_LANTERN
|
||||
BlockItemIds.CACTUS,
|
||||
BlockItemIds.MELON,
|
||||
BlockItemIds.PUMPKIN,
|
||||
BlockItemIds.CARVED_PUMPKIN,
|
||||
BlockItemIds.JACK_O_LANTERN
|
||||
);
|
||||
|
||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_SWORD_BREAKABLE).addTag(BlockTags.WOOL).add(Blocks.COBWEB);
|
||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_SWORD_BREAKABLE)
|
||||
.addTag(BlockTags.WOOL)
|
||||
.addTag(BlockTags.SWORD_INSTANTLY_MINES)
|
||||
.add(BlockItemIds.COBWEB);
|
||||
|
||||
tags.tag(ComputerCraftTags.Blocks.TURTLE_CAN_USE);
|
||||
|
||||
// Make all blocks aside from command computer mineable.
|
||||
tags.tag(BlockTags.MINEABLE_WITH_PICKAXE).add(
|
||||
ModRegistry.Blocks.COMPUTER_NORMAL.get(),
|
||||
ModRegistry.Blocks.COMPUTER_ADVANCED.get(),
|
||||
ModRegistry.Blocks.TURTLE_NORMAL.get(),
|
||||
ModRegistry.Blocks.TURTLE_ADVANCED.get(),
|
||||
ModRegistry.Blocks.SPEAKER.get(),
|
||||
ModRegistry.Blocks.DISK_DRIVE.get(),
|
||||
ModRegistry.Blocks.PRINTER.get(),
|
||||
ModRegistry.Blocks.MONITOR_NORMAL.get(),
|
||||
ModRegistry.Blocks.MONITOR_ADVANCED.get(),
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get(),
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get(),
|
||||
ModRegistry.Blocks.WIRED_MODEM_FULL.get(),
|
||||
ModRegistry.Blocks.CABLE.get(),
|
||||
ModRegistry.Blocks.REDSTONE_RELAY.get()
|
||||
ComputerCraftBlockIds.COMPUTER_NORMAL,
|
||||
ComputerCraftBlockIds.COMPUTER_ADVANCED,
|
||||
ComputerCraftBlockIds.TURTLE_NORMAL,
|
||||
ComputerCraftBlockIds.TURTLE_ADVANCED,
|
||||
ComputerCraftBlockIds.SPEAKER,
|
||||
ComputerCraftBlockIds.DISK_DRIVE,
|
||||
ComputerCraftBlockIds.PRINTER,
|
||||
ComputerCraftBlockIds.MONITOR_NORMAL,
|
||||
ComputerCraftBlockIds.MONITOR_ADVANCED,
|
||||
ComputerCraftBlockIds.WIRELESS_MODEM_NORMAL,
|
||||
ComputerCraftBlockIds.WIRELESS_MODEM_ADVANCED,
|
||||
ComputerCraftBlockIds.WIRED_MODEM_FULL,
|
||||
ComputerCraftBlockIds.CABLE,
|
||||
ComputerCraftBlockIds.REDSTONE_RELAY
|
||||
);
|
||||
|
||||
tags.tag(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.Blocks.LECTERN.get());
|
||||
tags.tag(BlockTags.MINEABLE_WITH_AXE).add(ComputerCraftBlockIds.LECTERN);
|
||||
|
||||
tags.tag(BlockTags.WITHER_IMMUNE).add(ModRegistry.Blocks.COMPUTER_COMMAND.get());
|
||||
tags.tag(BlockTags.WITHER_IMMUNE).add(ComputerCraftBlockIds.COMPUTER_COMMAND);
|
||||
|
||||
tags.tag(ExternalModTags.Blocks.CREATE_BRITTLE).add(
|
||||
ModRegistry.Blocks.CABLE.get(),
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_NORMAL.get(),
|
||||
ModRegistry.Blocks.WIRELESS_MODEM_ADVANCED.get()
|
||||
ComputerCraftBlockIds.CABLE,
|
||||
ComputerCraftBlockIds.WIRELESS_MODEM_NORMAL,
|
||||
ComputerCraftBlockIds.WIRELESS_MODEM_ADVANCED
|
||||
);
|
||||
}
|
||||
|
||||
public static void itemTags(TagConsumer<Item> tags) {
|
||||
itemAndBlockTags((b, i) -> tags.tag(i).map(Block::asItem));
|
||||
tags.tag(ComputerCraftTags.Items.WIRED_MODEM).add(ModRegistry.Items.WIRED_MODEM.get(), ModRegistry.Items.WIRED_MODEM_FULL.get());
|
||||
tags.tag(ComputerCraftTags.Items.DISKS).add(ModRegistry.Items.DISK.get(), ModRegistry.Items.TREASURE_DISK.get());
|
||||
tags.tag(ComputerCraftTags.Items.POCKET_COMPUTERS).add(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
|
||||
itemAndBlockTags(i -> tags.tag(i.item()));
|
||||
tags.tag(ComputerCraftTags.Items.WIRED_MODEM).add(ComputerCraftItemIds.WIRED_MODEM, item(ModRegistry.Items.WIRED_MODEM_FULL));
|
||||
tags.tag(ComputerCraftTags.Items.DISKS).add(ComputerCraftItemIds.DISK, item(ModRegistry.Items.TREASURE_DISK));
|
||||
tags.tag(ComputerCraftTags.Items.POCKET_COMPUTERS).add(ComputerCraftItemIds.POCKET_COMPUTER_NORMAL, item(ModRegistry.Items.POCKET_COMPUTER_ADVANCED));
|
||||
|
||||
tags.tag(ComputerCraftTags.Items.DYEABLE)
|
||||
.addTag(ComputerCraftTags.Items.TURTLE)
|
||||
.add(ModRegistry.Items.DISK.get(), ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
|
||||
.add(ComputerCraftItemIds.DISK, ComputerCraftItemIds.POCKET_COMPUTER_NORMAL, item(ModRegistry.Items.POCKET_COMPUTER_ADVANCED));
|
||||
|
||||
tags.tag(ItemTags.PIGLIN_LOVED).add(
|
||||
ModRegistry.Items.COMPUTER_ADVANCED.get(), ModRegistry.Items.TURTLE_ADVANCED.get(),
|
||||
ModRegistry.Items.WIRELESS_MODEM_ADVANCED.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get(),
|
||||
ModRegistry.Items.MONITOR_ADVANCED.get()
|
||||
ComputerCraftItemIds.COMPUTER_ADVANCED, ComputerCraftItemIds.TURTLE_ADVANCED,
|
||||
ComputerCraftItemIds.WIRELESS_MODEM_ADVANCED, ComputerCraftItemIds.POCKET_COMPUTER_ADVANCED,
|
||||
ComputerCraftItemIds.MONITOR_ADVANCED
|
||||
);
|
||||
|
||||
tags.tag(ItemTags.CAULDRON_CAN_REMOVE_DYE).addTag(ComputerCraftTags.Items.TURTLE);
|
||||
|
||||
// Allow printed books to be placed in bookshelves.
|
||||
tags.tag(ItemTags.BOOKSHELF_BOOKS).add(ModRegistry.Items.PRINTED_BOOK.get());
|
||||
tags.tag(ItemTags.BOOKSHELF_BOOKS).add(item(ModRegistry.Items.PRINTED_BOOK));
|
||||
|
||||
tags.tag(ComputerCraftTags.Items.TURTLE_CAN_PLACE)
|
||||
.add(Items.GLASS_BOTTLE)
|
||||
.add(ItemIds.GLASS_BOTTLE)
|
||||
.addTag(ItemTags.BOATS);
|
||||
}
|
||||
|
||||
private static void itemAndBlockTags(BlockItemTagConsumer tags) {
|
||||
tags.tag(ComputerCraftTags.Blocks.COMPUTER, ComputerCraftTags.Items.COMPUTER).add(
|
||||
ModRegistry.Blocks.COMPUTER_NORMAL.get(),
|
||||
ModRegistry.Blocks.COMPUTER_ADVANCED.get(),
|
||||
ModRegistry.Blocks.COMPUTER_COMMAND.get()
|
||||
tags.tag(ComputerCraftTags.BlockItems.COMPUTER).add(
|
||||
ComputerCraftBlockItemIds.COMPUTER_NORMAL,
|
||||
ComputerCraftBlockItemIds.COMPUTER_ADVANCED,
|
||||
ComputerCraftBlockItemIds.COMPUTER_COMMAND
|
||||
);
|
||||
tags.tag(ComputerCraftTags.Blocks.TURTLE, ComputerCraftTags.Items.TURTLE).add(
|
||||
ModRegistry.Blocks.TURTLE_NORMAL.get(),
|
||||
ModRegistry.Blocks.TURTLE_ADVANCED.get()
|
||||
tags.tag(ComputerCraftTags.BlockItems.TURTLE).add(
|
||||
ComputerCraftBlockItemIds.TURTLE_NORMAL,
|
||||
ComputerCraftBlockItemIds.TURTLE_ADVANCED
|
||||
);
|
||||
tags.tag(ComputerCraftTags.Blocks.MONITOR, ComputerCraftTags.Items.MONITOR).add(
|
||||
ModRegistry.Blocks.MONITOR_NORMAL.get(),
|
||||
ModRegistry.Blocks.MONITOR_ADVANCED.get()
|
||||
tags.tag(ComputerCraftTags.BlockItems.MONITOR).add(
|
||||
ComputerCraftBlockItemIds.MONITOR_NORMAL,
|
||||
ComputerCraftBlockItemIds.MONITOR_ADVANCED
|
||||
);
|
||||
}
|
||||
|
||||
@@ -130,10 +141,14 @@ class TagProvider {
|
||||
* @param <T> The type of object we're providing tags for.
|
||||
*/
|
||||
public interface TagConsumer<T> {
|
||||
TagAppender<T, T> tag(TagKey<T> tag);
|
||||
BlockItemTagAppender<T> tag(TagKey<T> tag);
|
||||
}
|
||||
|
||||
private interface BlockItemTagConsumer {
|
||||
TagAppender<Block, ?> tag(TagKey<Block> blockTag, TagKey<Item> itemTag);
|
||||
BlockItemTagAppender<?> tag(BlockItemTagId tag);
|
||||
}
|
||||
|
||||
private static ResourceKey<Item> item(RegistryEntry<? extends Item> entry) {
|
||||
return ResourceKey.create(Registries.ITEM, entry.id());
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@ import com.mojang.serialization.DataResult;
|
||||
import dan200.computercraft.shared.recipe.RecipeProperties;
|
||||
import net.minecraft.advancements.AdvancementRequirements;
|
||||
import net.minecraft.advancements.AdvancementRewards;
|
||||
import net.minecraft.advancements.Criterion;
|
||||
import net.minecraft.advancements.criterion.RecipeUnlockedTrigger;
|
||||
import net.minecraft.advancements.triggers.Criterion;
|
||||
import net.minecraft.advancements.triggers.RecipeUnlockedTrigger;
|
||||
import net.minecraft.core.HolderGetter;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.recipes.RecipeBuilder;
|
||||
|
||||
@@ -8,6 +8,8 @@ import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.ComputerCraftBlockIds;
|
||||
import dan200.computercraft.api.ComputerCraftItemIds;
|
||||
import dan200.computercraft.api.component.ComputerComponents;
|
||||
import dan200.computercraft.api.detail.DetailProvider;
|
||||
import dan200.computercraft.api.detail.VanillaDetailRegistries;
|
||||
@@ -44,7 +46,6 @@ import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
|
||||
import dan200.computercraft.shared.details.BlockDetails;
|
||||
import dan200.computercraft.shared.details.EntityDetails;
|
||||
import dan200.computercraft.shared.details.ItemDetails;
|
||||
import dan200.computercraft.shared.integration.PermissionRegistry;
|
||||
import dan200.computercraft.shared.lectern.CustomLecternBlock;
|
||||
import dan200.computercraft.shared.lectern.CustomLecternBlockEntity;
|
||||
import dan200.computercraft.shared.lectern.PocketComputerLecternMenu;
|
||||
@@ -71,6 +72,7 @@ import dan200.computercraft.shared.peripheral.redstone.RedstoneRelayBlock;
|
||||
import dan200.computercraft.shared.peripheral.redstone.RedstoneRelayBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlock;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity;
|
||||
import dan200.computercraft.shared.platform.PermissionRegistry;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.platform.RegistrationHelper;
|
||||
import dan200.computercraft.shared.platform.RegistryEntry;
|
||||
@@ -126,6 +128,7 @@ import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.GameMasterBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTypes;
|
||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||
import net.minecraft.world.level.material.MapColor;
|
||||
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
||||
@@ -148,11 +151,8 @@ public final class ModRegistry {
|
||||
public static final class Blocks {
|
||||
static final RegistrationHelper<Block> REGISTRY = PlatformHelper.get().createRegistrationHelper(Registries.BLOCK);
|
||||
|
||||
private static <T extends Block> RegistryEntry<T> register(String name, Function<BlockBehaviour.Properties, T> build, BlockBehaviour.Properties properties) {
|
||||
return REGISTRY.register(name, () -> {
|
||||
properties.setId(ResourceKey.create(Registries.BLOCK, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name)));
|
||||
return build.apply(properties);
|
||||
});
|
||||
private static <T extends Block> RegistryEntry<T> register(ResourceKey<Block> name, Function<BlockBehaviour.Properties, T> build, BlockBehaviour.Properties properties) {
|
||||
return REGISTRY.register(name, () -> build.apply(properties.setId(name)));
|
||||
}
|
||||
|
||||
private static BlockBehaviour.Properties properties() {
|
||||
@@ -173,42 +173,42 @@ public final class ModRegistry {
|
||||
return BlockBehaviour.Properties.of().strength(1.5f);
|
||||
}
|
||||
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_NORMAL = register("computer_normal",
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_NORMAL = register(ComputerCraftBlockIds.COMPUTER_NORMAL,
|
||||
p -> new ComputerBlock<>(p, BlockEntities.COMPUTER_NORMAL), redstoneConductor().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = register("computer_advanced",
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_ADVANCED = register(ComputerCraftBlockIds.COMPUTER_ADVANCED,
|
||||
p -> new ComputerBlock<>(p, BlockEntities.COMPUTER_ADVANCED), redstoneConductor().mapColor(MapColor.GOLD));
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_COMMAND = register("computer_command",
|
||||
public static final RegistryEntry<ComputerBlock<ComputerBlockEntity>> COMPUTER_COMMAND = register(ComputerCraftBlockIds.COMPUTER_COMMAND,
|
||||
p -> new CommandComputerBlock<>(p, BlockEntities.COMPUTER_COMMAND), redstoneConductor().strength(-1, 6000000.0F));
|
||||
|
||||
public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = register("turtle_normal",
|
||||
public static final RegistryEntry<TurtleBlock> TURTLE_NORMAL = register(ComputerCraftBlockIds.TURTLE_NORMAL,
|
||||
p -> new TurtleBlock(p, BlockEntities.TURTLE_NORMAL), turtleProperties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<TurtleBlock> TURTLE_ADVANCED = register("turtle_advanced",
|
||||
public static final RegistryEntry<TurtleBlock> TURTLE_ADVANCED = register(ComputerCraftBlockIds.TURTLE_ADVANCED,
|
||||
p -> new TurtleBlock(p, BlockEntities.TURTLE_ADVANCED), turtleProperties().mapColor(MapColor.GOLD).explosionResistance(TurtleBlock.IMMUNE_EXPLOSION_RESISTANCE));
|
||||
|
||||
public static final RegistryEntry<SpeakerBlock> SPEAKER = register("speaker", SpeakerBlock::new, properties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<DiskDriveBlock> DISK_DRIVE = register("disk_drive", DiskDriveBlock::new, properties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<PrinterBlock> PRINTER = register("printer", PrinterBlock::new, properties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<SpeakerBlock> SPEAKER = register(ComputerCraftBlockIds.SPEAKER, SpeakerBlock::new, properties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<DiskDriveBlock> DISK_DRIVE = register(ComputerCraftBlockIds.DISK_DRIVE, DiskDriveBlock::new, properties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<PrinterBlock> PRINTER = register(ComputerCraftBlockIds.PRINTER, PrinterBlock::new, properties().mapColor(MapColor.STONE));
|
||||
|
||||
public static final RegistryEntry<MonitorBlock> MONITOR_NORMAL = register("monitor_normal",
|
||||
public static final RegistryEntry<MonitorBlock> MONITOR_NORMAL = register(ComputerCraftBlockIds.MONITOR_NORMAL,
|
||||
p -> new MonitorBlock(p, BlockEntities.MONITOR_NORMAL), properties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<MonitorBlock> MONITOR_ADVANCED = register("monitor_advanced",
|
||||
public static final RegistryEntry<MonitorBlock> MONITOR_ADVANCED = register(ComputerCraftBlockIds.MONITOR_ADVANCED,
|
||||
p -> new MonitorBlock(p, BlockEntities.MONITOR_ADVANCED), properties().mapColor(MapColor.GOLD));
|
||||
|
||||
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_NORMAL = register("wireless_modem_normal",
|
||||
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_NORMAL = register(ComputerCraftBlockIds.WIRELESS_MODEM_NORMAL,
|
||||
p -> new WirelessModemBlock(p, BlockEntities.WIRELESS_MODEM_NORMAL), properties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_ADVANCED = register("wireless_modem_advanced",
|
||||
public static final RegistryEntry<WirelessModemBlock> WIRELESS_MODEM_ADVANCED = register(ComputerCraftBlockIds.WIRELESS_MODEM_ADVANCED,
|
||||
p -> new WirelessModemBlock(p, BlockEntities.WIRELESS_MODEM_ADVANCED), properties().mapColor(MapColor.GOLD));
|
||||
|
||||
public static final RegistryEntry<WiredModemFullBlock> WIRED_MODEM_FULL = register("wired_modem_full",
|
||||
public static final RegistryEntry<WiredModemFullBlock> WIRED_MODEM_FULL = register(ComputerCraftBlockIds.WIRED_MODEM_FULL,
|
||||
WiredModemFullBlock::new, modemProperties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<CableBlock> CABLE = register("cable", CableBlock::new, modemProperties().mapColor(MapColor.STONE));
|
||||
public static final RegistryEntry<CableBlock> CABLE = register(ComputerCraftBlockIds.CABLE, CableBlock::new, modemProperties().mapColor(MapColor.STONE));
|
||||
|
||||
public static final RegistryEntry<CustomLecternBlock> LECTERN = register("lectern", CustomLecternBlock::new,
|
||||
public static final RegistryEntry<CustomLecternBlock> LECTERN = register(ComputerCraftBlockIds.LECTERN, CustomLecternBlock::new,
|
||||
BlockBehaviour.Properties.ofFullCopy(net.minecraft.world.level.block.Blocks.LECTERN)
|
||||
.overrideDescription(net.minecraft.world.level.block.Blocks.LECTERN.getDescriptionId())
|
||||
);
|
||||
|
||||
public static final RegistryEntry<RedstoneRelayBlock> REDSTONE_RELAY = register("redstone_relay", RedstoneRelayBlock::new,
|
||||
public static final RegistryEntry<RedstoneRelayBlock> REDSTONE_RELAY = register(ComputerCraftBlockIds.REDSTONE_RELAY, RedstoneRelayBlock::new,
|
||||
redstoneConductor().mapColor(MapColor.STONE));
|
||||
}
|
||||
|
||||
@@ -285,44 +285,44 @@ public final class ModRegistry {
|
||||
);
|
||||
}
|
||||
|
||||
private static <T extends Item> RegistryEntry<T> register(String name, Function<Item.Properties, T> build, Supplier<Item.Properties> properties) {
|
||||
return REGISTRY.register(name, () -> build.apply(properties.get().setId(ResourceKey.create(Registries.ITEM, Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name)))));
|
||||
private static <T extends Item> RegistryEntry<T> register(ResourceKey<Item> name, Function<Item.Properties, T> build, Supplier<Item.Properties> properties) {
|
||||
return REGISTRY.register(name, () -> build.apply(properties.get().setId(name)));
|
||||
}
|
||||
|
||||
private static <T extends Item> RegistryEntry<T> register(String name, Function<Item.Properties, T> build, Item.Properties properties) {
|
||||
private static <T extends Item> RegistryEntry<T> register(ResourceKey<Item> name, Function<Item.Properties, T> build, Item.Properties properties) {
|
||||
return register(name, build, () -> properties);
|
||||
}
|
||||
|
||||
private static <B extends Block, I extends Item> RegistryEntry<I> ofBlock(RegistryEntry<B> parent, BiFunction<B, Item.Properties, I> supplier, Item.Properties properties) {
|
||||
return register(parent.id().getPath(), p -> supplier.apply(parent.get(), p), properties.useBlockDescriptionPrefix());
|
||||
return register(ResourceKey.create(Registries.ITEM, parent.id()), p -> supplier.apply(parent.get(), p), properties.useBlockDescriptionPrefix());
|
||||
}
|
||||
|
||||
public static final RegistryEntry<BlockItem> COMPUTER_NORMAL = ofBlock(Blocks.COMPUTER_NORMAL, BlockItem::new, properties());
|
||||
public static final RegistryEntry<BlockItem> COMPUTER_ADVANCED = ofBlock(Blocks.COMPUTER_ADVANCED, BlockItem::new, properties());
|
||||
public static final RegistryEntry<GameMasterBlockItem> COMPUTER_COMMAND = ofBlock(Blocks.COMPUTER_COMMAND, GameMasterBlockItem::new, properties());
|
||||
|
||||
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_NORMAL = register("pocket_computer_normal",
|
||||
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_NORMAL = register(ComputerCraftItemIds.POCKET_COMPUTER_NORMAL,
|
||||
p -> new PocketComputerItem(p, ComputerFamily.NORMAL), dyeableProperties().stacksTo(1));
|
||||
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_ADVANCED = register("pocket_computer_advanced",
|
||||
public static final RegistryEntry<PocketComputerItem> POCKET_COMPUTER_ADVANCED = register(ComputerCraftItemIds.POCKET_COMPUTER_ADVANCED,
|
||||
p -> new PocketComputerItem(p, ComputerFamily.ADVANCED), dyeableProperties().stacksTo(1));
|
||||
|
||||
public static final RegistryEntry<TurtleItem> TURTLE_NORMAL = ofBlock(Blocks.TURTLE_NORMAL, TurtleItem::new, dyeableProperties());
|
||||
public static final RegistryEntry<TurtleItem> TURTLE_ADVANCED = ofBlock(Blocks.TURTLE_ADVANCED, TurtleItem::new, dyeableProperties());
|
||||
|
||||
public static final RegistryEntry<DiskItem> DISK =
|
||||
register("disk", DiskItem::new, dyeableProperties().stacksTo(1));
|
||||
register(ComputerCraftItemIds.DISK, DiskItem::new, dyeableProperties().stacksTo(1));
|
||||
public static final RegistryEntry<DiskItem> TREASURE_DISK =
|
||||
register("treasure_disk", DiskItem::new, dyeableProperties().stacksTo(1));
|
||||
register(ComputerCraftItemIds.TREASURE_DISK, DiskItem::new, dyeableProperties().stacksTo(1));
|
||||
|
||||
private static Item.Properties printoutProperties() {
|
||||
return properties().stacksTo(1).component(DataComponents.PRINTOUT.get(), PrintoutData.EMPTY);
|
||||
}
|
||||
|
||||
public static final RegistryEntry<PrintoutItem> PRINTED_PAGE = register("printed_page",
|
||||
public static final RegistryEntry<PrintoutItem> PRINTED_PAGE = register(ComputerCraftItemIds.PRINTED_PAGE,
|
||||
PrintoutItem::new, Items::printoutProperties);
|
||||
public static final RegistryEntry<PrintoutItem> PRINTED_PAGES = register("printed_pages",
|
||||
public static final RegistryEntry<PrintoutItem> PRINTED_PAGES = register(ComputerCraftItemIds.PRINTED_PAGES,
|
||||
PrintoutItem::new, Items::printoutProperties);
|
||||
public static final RegistryEntry<PrintoutItem> PRINTED_BOOK = register("printed_book",
|
||||
public static final RegistryEntry<PrintoutItem> PRINTED_BOOK = register(ComputerCraftItemIds.PRINTED_BOOK,
|
||||
PrintoutItem::new, Items::printoutProperties);
|
||||
|
||||
public static final RegistryEntry<BlockItem> SPEAKER = ofBlock(Blocks.SPEAKER, BlockItem::new, properties());
|
||||
@@ -335,9 +335,9 @@ public final class ModRegistry {
|
||||
public static final RegistryEntry<BlockItem> WIRED_MODEM_FULL = ofBlock(Blocks.WIRED_MODEM_FULL, BlockItem::new, properties());
|
||||
public static final RegistryEntry<BlockItem> REDSTONE_RELAY = ofBlock(Blocks.REDSTONE_RELAY, BlockItem::new, properties());
|
||||
|
||||
public static final RegistryEntry<CableBlockItem.Cable> CABLE = register("cable",
|
||||
public static final RegistryEntry<CableBlockItem.Cable> CABLE = register(ComputerCraftItemIds.CABLE,
|
||||
p -> new CableBlockItem.Cable(Blocks.CABLE.get(), p), properties().useBlockDescriptionPrefix());
|
||||
public static final RegistryEntry<CableBlockItem.WiredModem> WIRED_MODEM = register("wired_modem",
|
||||
public static final RegistryEntry<CableBlockItem.WiredModem> WIRED_MODEM = register(ComputerCraftItemIds.WIRED_MODEM,
|
||||
p -> new CableBlockItem.WiredModem(Blocks.CABLE.get(), p), properties().useBlockDescriptionPrefix());
|
||||
}
|
||||
|
||||
@@ -576,7 +576,7 @@ public final class ModRegistry {
|
||||
}
|
||||
|
||||
public static class Permissions {
|
||||
static final PermissionRegistry REGISTRY = PermissionRegistry.create();
|
||||
static final PermissionRegistry REGISTRY = PlatformHelper.get().createPermissionRegistry();
|
||||
|
||||
public static final Predicate<CommandSourceStack> PERMISSION_DUMP = REGISTRY.registerCommand("dump", UserLevel.OWNER_OP);
|
||||
public static final Predicate<CommandSourceStack> PERMISSION_SHUTDOWN = REGISTRY.registerCommand("shutdown", UserLevel.OWNER_OP);
|
||||
@@ -692,7 +692,7 @@ public final class ModRegistry {
|
||||
peripherals.registerForBlockEntity(ModRegistry.BlockEntities.CABLE.get(), CableBlockEntity::getPeripheral);
|
||||
peripherals.registerForBlockEntity(ModRegistry.BlockEntities.REDSTONE_RELAY.get(), (b, d) -> b.peripheral());
|
||||
|
||||
peripherals.registerForBlockEntity(BlockEntityType.COMMAND_BLOCK, (b, d) -> Config.enableCommandBlock ? new CommandBlockPeripheral(b) : null);
|
||||
peripherals.registerForBlockEntity(BlockEntityTypes.COMMAND_BLOCK, (b, d) -> Config.enableCommandBlock ? new CommandBlockPeripheral(b) : null);
|
||||
}
|
||||
|
||||
public static void registerWiredElements(BlockComponent<WiredElement, Direction> wiredElements) {
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import net.minecraft.advancements.criterion.MinMaxBounds;
|
||||
import net.minecraft.advancements.predicates.MinMaxBounds;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.arguments.UuidArgument;
|
||||
|
||||
+6
-29
@@ -2,28 +2,25 @@
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.integration;
|
||||
package dan200.computercraft.shared.platform;
|
||||
|
||||
import com.google.errorprone.annotations.OverridingMethodsMustInvokeSuper;
|
||||
import com.mojang.brigadier.builder.ArgumentBuilder;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.command.UserLevel;
|
||||
import dan200.computercraft.shared.platform.RegistrationHelper;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A registry of nodes in a permission system.
|
||||
* <p>
|
||||
* This acts as an abstraction layer over permission systems such Forge's built-in permissions API, or Fabric's
|
||||
* unofficial <a href="https://github.com/lucko/fabric-permissions-api">fabric-permissions-api-v0</a>.
|
||||
* This acts as an abstraction layer over permission systems such Forge or Fabric's built-in permissions API.
|
||||
* <p>
|
||||
* This behaves similarly to {@link RegistrationHelper} (aka Forge's deferred registry), in that you {@linkplain #create()
|
||||
* create a registry}, {@linkplain #registerCommand(String, UserLevel) add nodes to it} and then finally {@linkplain
|
||||
* #register()} all created nodes.
|
||||
* This behaves similarly to {@link RegistrationHelper} (aka Forge's deferred registry), in that you
|
||||
* {@linkplain PlatformHelper#createPermissionRegistry()} create a registry},
|
||||
* {@linkplain #registerCommand(String, UserLevel) add nodes to it} and then finally {@linkplain #register()} all
|
||||
* created nodes.
|
||||
*
|
||||
* @see dan200.computercraft.shared.ModRegistry.Permissions
|
||||
*/
|
||||
@@ -56,24 +53,4 @@ public abstract class PermissionRegistry {
|
||||
public void register() {
|
||||
frozen = true;
|
||||
}
|
||||
|
||||
public interface Provider {
|
||||
Optional<PermissionRegistry> get();
|
||||
}
|
||||
|
||||
public static PermissionRegistry create() {
|
||||
return ServiceLoader.load(Provider.class)
|
||||
.stream()
|
||||
.flatMap(x -> x.get().get().stream())
|
||||
.findFirst()
|
||||
.orElseGet(DefaultPermissionRegistry::new);
|
||||
}
|
||||
|
||||
private static final class DefaultPermissionRegistry extends PermissionRegistry {
|
||||
@Override
|
||||
public Predicate<CommandSourceStack> registerCommand(String command, UserLevel fallback) {
|
||||
checkNotFrozen();
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,6 +89,13 @@ public interface PlatformHelper {
|
||||
*/
|
||||
<T> RegistrationHelper<T> createRegistrationHelper(ResourceKey<Registry<T>> registry);
|
||||
|
||||
/**
|
||||
* Create a new {@linkplain PermissionRegistry registry for permissions}.
|
||||
*
|
||||
* @return The newly created permission registry.
|
||||
*/
|
||||
PermissionRegistry createPermissionRegistry();
|
||||
|
||||
/**
|
||||
* Register a new argument type.
|
||||
*
|
||||
|
||||
+11
@@ -32,6 +32,17 @@ public interface RegistrationHelper<T> {
|
||||
*/
|
||||
<U extends T> RegistryEntry<U> register(String name, Supplier<U> create);
|
||||
|
||||
/**
|
||||
* Register an entry in this helper. This does <em>NOT</em> immediately register the object in the underlying
|
||||
* {@link Registry}.
|
||||
*
|
||||
* @param id The id of this entry.
|
||||
* @param create A factory method to create the entry.
|
||||
* @param <U> The type of this item in the registry.
|
||||
* @return The {@link RegistryEntry} for the registered entry.
|
||||
*/
|
||||
<U extends T> RegistryEntry<U> register(ResourceKey<T> id, Supplier<U> create);
|
||||
|
||||
/**
|
||||
* Register this helper.
|
||||
*/
|
||||
|
||||
+1
-1
@@ -240,7 +240,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
|
||||
var knockBack = EnchantmentHelper.modifyKnockback(player.level(), tool, entity, source, (float) player.getAttributeValue(Attributes.ATTACK_KNOCKBACK));
|
||||
if (knockBack > 0) {
|
||||
if (entity instanceof LivingEntity target) {
|
||||
target.knockback(knockBack * 0.5, -direction.getStepX(), -direction.getStepZ());
|
||||
target.knockback(knockBack * 0.5, -direction.getStepX(), -direction.getStepZ(), source, damage);
|
||||
} else {
|
||||
entity.push(direction.getStepX() * knockBack * 0.5, 0.1, direction.getStepZ() * knockBack * 0.5);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.EntityTypes;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.ProjectileUtil;
|
||||
@@ -174,7 +174,7 @@ public final class WorldUtil {
|
||||
private final Block block;
|
||||
|
||||
ContextlessClipContext(Level level, Vec3 from, Vec3 to, Block block, Fluid fluid) {
|
||||
super(from, to, block, fluid, new ItemEntity(EntityType.ITEM, level));
|
||||
super(from, to, block, fluid, new ItemEntity(EntityTypes.ITEM, level));
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ accessible field net/minecraft/client/data/models/ItemModelGenerators itemModelO
|
||||
accessible field net/minecraft/client/data/models/ItemModelGenerators modelOutput Ljava/util/function/BiConsumer;
|
||||
accessible method net/minecraft/client/data/models/ItemModelGenerators generateFlatItem (Lnet/minecraft/world/item/Item;Lnet/minecraft/client/data/models/model/ModelTemplate;)V
|
||||
accessible method net/minecraft/client/data/models/model/TextureSlot create (Ljava/lang/String;)Lnet/minecraft/client/data/models/model/TextureSlot;
|
||||
accessible method net/minecraft/data/recipes/RecipeProvider inventoryTrigger ([Lnet/minecraft/advancements/criterion/ItemPredicate;)Lnet/minecraft/advancements/Criterion;
|
||||
accessible method net/minecraft/data/recipes/RecipeProvider inventoryTrigger ([Lnet/minecraft/advancements/predicates/ItemPredicate;)Lnet/minecraft/advancements/triggers/Criterion;
|
||||
|
||||
# GUI elements
|
||||
accessible class net/minecraft/client/gui/GuiGraphicsExtractor$ScissorStack
|
||||
|
||||
@@ -7,13 +7,13 @@ accessWidener v1 official
|
||||
# Shared vanilla and Fabric access wideners. This should not include things already exposed by Fabric's transitive
|
||||
# wideners.
|
||||
|
||||
accessible class net/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier
|
||||
accessible method net/minecraft/world/level/block/entity/BlockEntityType <init> (Lnet/minecraft/world/level/block/entity/BlockEntityType$BlockEntitySupplier;Ljava/util/Set;)V
|
||||
|
||||
# ClientTableFormatter
|
||||
accessible field net/minecraft/client/gui/components/ChatComponent allMessages Ljava/util/List;
|
||||
accessible method net/minecraft/client/gui/components/ChatComponent addMessage (Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/MessageSignature;Lnet/minecraft/client/multiplayer/chat/GuiMessageSource;Lnet/minecraft/client/multiplayer/chat/GuiMessageTag;)V
|
||||
|
||||
# NoTermComputerScreen
|
||||
accessible field net/minecraft/client/gui/Gui screen Lnet/minecraft/client/gui/screens/Screen;
|
||||
|
||||
# ItemPocketRenderer/ItemPrintoutRenderer
|
||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer calculateMapTilt (F)F
|
||||
accessible method net/minecraft/client/renderer/ItemInHandRenderer renderMapHand (Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/world/entity/HumanoidArm;)V
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"required": true,
|
||||
"package": "dan200.computercraft.mixin",
|
||||
"minVersion": "0.8",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
|
||||
@@ -64,7 +64,12 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat
|
||||
|
||||
@Override
|
||||
public <T> RegistrationHelper<T> createRegistrationHelper(ResourceKey<Registry<T>> registry) {
|
||||
throw new UnsupportedOperationException("Cannot query registry inside tests");
|
||||
throw new UnsupportedOperationException("Cannot create RegistrationHelper inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionRegistry createPermissionRegistry() {
|
||||
throw new UnsupportedOperationException("Cannot create PermissionRegistry inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -52,7 +52,7 @@ public class Exporter {
|
||||
private static void run(String path) {
|
||||
var output = new File(path).getAbsoluteFile().toPath();
|
||||
if (!Files.isDirectory(output)) {
|
||||
Minecraft.getInstance().gui.getChat().addClientSystemMessage(Component.literal("Output path does not exist"));
|
||||
Minecraft.getInstance().gui.hud.getChat().addClientSystemMessage(Component.literal("Output path does not exist"));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class Exporter {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
|
||||
Minecraft.getInstance().gui.getChat().addClientSystemMessage(Component.literal("Export finished!"));
|
||||
Minecraft.getInstance().gui.hud.getChat().addClientSystemMessage(Component.literal("Export finished!"));
|
||||
}
|
||||
|
||||
private static void export(Path root) throws IOException {
|
||||
|
||||
+6
-6
@@ -19,9 +19,9 @@ import net.minecraft.gametest.framework.StructureUtils;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.EntityTypes;
|
||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTypes;
|
||||
import net.minecraft.world.level.block.entity.TestInstanceBlockEntity;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
|
||||
@@ -46,20 +46,20 @@ class CCTestCommand {
|
||||
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.level()).orElse(null);
|
||||
if (pos == null) return error(context.getSource(), "No nearby test");
|
||||
|
||||
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)
|
||||
var test = player.level().getBlockEntity(pos, BlockEntityTypes.TEST_INSTANCE_BLOCK)
|
||||
.flatMap(TestInstanceBlockEntity::test).orElse(null);
|
||||
if (test == null) return error(context.getSource(), "No nearby structure block");
|
||||
|
||||
// Kill the existing armor stand
|
||||
var level = player.level();
|
||||
level.getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(test.identifier().getPath()))
|
||||
level.getEntities(EntityTypes.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(test.identifier().getPath()))
|
||||
.forEach(e -> e.kill(level));
|
||||
|
||||
// And create a new one
|
||||
var nbt = new CompoundTag();
|
||||
nbt.putBoolean("Marker", true);
|
||||
nbt.putBoolean("Invisible", true);
|
||||
var armorStand = new ArmorStand(EntityType.ARMOR_STAND, level);
|
||||
var armorStand = new ArmorStand(EntityTypes.ARMOR_STAND, level);
|
||||
armorStand.setInvisible(true);
|
||||
((ArmorStandAccessor) armorStand).computercraft$setMarker(true);
|
||||
armorStand.copyPosition(player);
|
||||
@@ -75,7 +75,7 @@ class CCTestCommand {
|
||||
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.level()).orElse(null);
|
||||
if (pos == null) return error(context.getSource(), "No nearby test");
|
||||
|
||||
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)
|
||||
var test = player.level().getBlockEntity(pos, BlockEntityTypes.TEST_INSTANCE_BLOCK)
|
||||
.flatMap(TestInstanceBlockEntity::test).orElse(null);
|
||||
if (test == null) return error(context.getSource(), "No nearby structure block");
|
||||
|
||||
|
||||
+3
-2
@@ -11,6 +11,7 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.Services;
|
||||
import net.minecraft.server.WorldStem;
|
||||
import net.minecraft.server.level.progress.LevelLoadListener;
|
||||
import net.minecraft.server.notifications.NotificationManager;
|
||||
import net.minecraft.server.packs.repository.PackRepository;
|
||||
import net.minecraft.world.level.gamerules.GameRules;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
@@ -27,9 +28,9 @@ abstract class GameTestServerMixin extends MinecraftServer {
|
||||
GameTestServerMixin(
|
||||
Thread serverThread, LevelStorageSource.LevelStorageAccess storageSource, PackRepository packRepository,
|
||||
WorldStem worldStem, Optional<GameRules> gameRules, Proxy proxy, DataFixer fixerUpper, Services services,
|
||||
LevelLoadListener progressListenerFactory, boolean propagatesCrashes
|
||||
LevelLoadListener progressListenerFactory, boolean propagatesCrashes, NotificationManager notificationManager
|
||||
) {
|
||||
super(serverThread, storageSource, packRepository, worldStem, gameRules, proxy, fixerUpper, services, progressListenerFactory, propagatesCrashes);
|
||||
super(serverThread, storageSource, packRepository, worldStem, gameRules, proxy, fixerUpper, services, progressListenerFactory, propagatesCrashes, notificationManager);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ class MinecraftMixin implements MinecraftExtensions {
|
||||
private void updateStable(boolean render, CallbackInfo ci) {
|
||||
isStable.set(
|
||||
level != null && player != null &&
|
||||
levelRenderer.isSectionCompiledAndVisible(player.blockPosition()) && levelRenderer.countRenderedSections() > 10 &&
|
||||
levelRenderer.isSectionCompiledAndVisible(player.blockPosition()) && levelRenderer.visibleSections().size() > 10 &&
|
||||
levelRenderer.hasRenderedAllSections()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ class Computer_Test {
|
||||
}
|
||||
// Press a key on the client
|
||||
thenOnClient {
|
||||
val screen = minecraft.screen as AbstractComputerScreen<*>
|
||||
val screen = minecraft.gui.screen() as AbstractComputerScreen<*>
|
||||
screen.keyPressed(KeyEvent(GLFW.GLFW_KEY_A, 0, 0))
|
||||
screen.keyReleased(KeyEvent(GLFW.GLFW_KEY_A, 0, 0))
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ class Disk_Test {
|
||||
|
||||
assertThat(
|
||||
"Disk with dye",
|
||||
helper.craftItem(ItemStack(Items.REDSTONE), ItemStack(Items.PAPER), ItemStack(Items.GREEN_DYE)),
|
||||
helper.craftItem(ItemStack(Items.REDSTONE), ItemStack(Items.PAPER), ItemStack(Items.DYE.green)),
|
||||
isStack(DataComponentUtil.createDyedStack(ModRegistry.Items.DISK.get(), Colour.GREEN.hex)),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ package dan200.computercraft.gametest
|
||||
import dan200.computercraft.api.lua.Coerced
|
||||
import dan200.computercraft.api.lua.LuaException
|
||||
import dan200.computercraft.gametest.api.*
|
||||
import dan200.computercraft.gametest.api.GameTest
|
||||
import dan200.computercraft.shared.ModRegistry
|
||||
import dan200.computercraft.shared.media.items.PrintoutData
|
||||
import dan200.computercraft.shared.peripheral.printer.PrinterBlock
|
||||
@@ -36,7 +35,7 @@ class Printer_Test {
|
||||
// Adding items should provide power
|
||||
thenExecute {
|
||||
val printer = helper.getBlockEntity(printerPos, PrinterBlockEntity::class.java)
|
||||
printer.setItem(0, ItemStack(Items.BLACK_DYE))
|
||||
printer.setItem(0, ItemStack(Items.DYE.black))
|
||||
printer.setItem(1, ItemStack(Items.PAPER))
|
||||
printer.setChanged()
|
||||
}
|
||||
@@ -100,7 +99,7 @@ class Printer_Test {
|
||||
assertFalse(peripheral.newPage(), "newPage fails with no items")
|
||||
|
||||
// Try to print with just ink
|
||||
printer.setItem(0, ItemStack(Items.BLUE_DYE))
|
||||
printer.setItem(0, ItemStack(Items.DYE.blue))
|
||||
printer.setChanged()
|
||||
assertFalse(peripheral.newPage(), "newPage fails with no paper")
|
||||
|
||||
@@ -114,7 +113,7 @@ class Printer_Test {
|
||||
printer.clearContent()
|
||||
|
||||
// Try to print with both items
|
||||
printer.setItem(0, ItemStack(Items.BLUE_DYE))
|
||||
printer.setItem(0, ItemStack(Items.DYE.blue))
|
||||
printer.setItem(1, ItemStack(Items.PAPER))
|
||||
printer.setChanged()
|
||||
assertTrue(peripheral.newPage(), "newPage succeeds")
|
||||
@@ -187,7 +186,7 @@ class Printer_Test {
|
||||
helper.assertExactlyItems(
|
||||
DataComponentUtil.createStack(ModRegistry.Items.PRINTER.get(), DataComponents.CUSTOM_NAME, Component.literal("My Printer")),
|
||||
ItemStack(Items.PAPER),
|
||||
ItemStack(Items.BLACK_DYE),
|
||||
ItemStack(Items.DYE.black),
|
||||
message = "Breaking a printer should drop the contents",
|
||||
)
|
||||
}
|
||||
@@ -200,7 +199,7 @@ class Printer_Test {
|
||||
fun Can_insert_items(helper: GameTestHelper) = helper.sequence {
|
||||
thenWaitUntil {
|
||||
helper.assertContainerExactly(BlockPos(1, 1, 2), listOf(ItemStack.EMPTY, ItemStack(Items.PAPER)))
|
||||
helper.assertContainerExactly(BlockPos(3, 1, 2), listOf(ItemStack(Items.BLACK_DYE)))
|
||||
helper.assertContainerExactly(BlockPos(3, 1, 2), listOf(ItemStack(Items.DYE.black)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ import net.minecraft.core.registries.Registries
|
||||
import net.minecraft.gametest.framework.GameTestHelper
|
||||
import net.minecraft.resources.Identifier
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.EntityTypes
|
||||
import net.minecraft.world.entity.item.PrimedTnt
|
||||
import net.minecraft.world.item.BlockItem
|
||||
import net.minecraft.world.item.ItemStack
|
||||
@@ -129,7 +130,7 @@ class Turtle_Test {
|
||||
thenOnComputer {
|
||||
turtle.placeDown(ObjectArguments()).await().assertArrayEquals(true, message = "Placed boat")
|
||||
}
|
||||
thenExecute { helper.assertEntityPresent(EntityType.OAK_BOAT) }
|
||||
thenExecute { helper.assertEntityPresent(EntityTypes.OAK_BOAT) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -485,7 +486,7 @@ class Turtle_Test {
|
||||
tnt.fuse = 1
|
||||
helper.level.addFreshEntity(tnt)
|
||||
}
|
||||
thenWaitUntil { helper.assertEntityNotPresent(EntityType.TNT) }
|
||||
thenWaitUntil { helper.assertEntityNotPresent(EntityTypes.TNT) }
|
||||
thenExecute {
|
||||
helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_ADVANCED.get(), BlockPos(2, 1, 2))
|
||||
helper.assertBlockPresent(Blocks.AIR, BlockPos(2, 1, 1))
|
||||
@@ -497,8 +498,8 @@ class Turtle_Test {
|
||||
*/
|
||||
@GameTest
|
||||
fun Resists_entity_explosions(helper: GameTestHelper) = helper.sequence {
|
||||
thenExecute { helper.getEntity(EntityType.CREEPER).ignite() }
|
||||
thenWaitUntil { helper.assertEntityNotPresent(EntityType.CREEPER) }
|
||||
thenExecute { helper.getEntity(EntityTypes.CREEPER).ignite() }
|
||||
thenWaitUntil { helper.assertEntityNotPresent(EntityTypes.CREEPER) }
|
||||
thenExecute {
|
||||
helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_ADVANCED.get(), BlockPos(2, 1, 2))
|
||||
helper.assertBlockPresent(ModRegistry.Blocks.TURTLE_NORMAL.get(), BlockPos(2, 1, 1))
|
||||
@@ -529,7 +530,7 @@ class Turtle_Test {
|
||||
@GameTest
|
||||
fun Drop_into_entity(helper: GameTestHelper) = helper.sequence {
|
||||
// When running /test runthis, the previous items pop from the chest. Remove them first!
|
||||
thenExecute { for (it in helper.getEntities(EntityType.ITEM)) it.discard() }
|
||||
thenExecute { for (it in helper.getEntities(EntityTypes.ITEM)) it.discard() }
|
||||
|
||||
thenOnComputer {
|
||||
turtle.drop(Optional.of(32)).await()
|
||||
@@ -537,8 +538,8 @@ class Turtle_Test {
|
||||
}
|
||||
thenExecute {
|
||||
helper.assertContainerExactly(BlockPos(2, 1, 2), listOf(ItemStack(Blocks.DIRT, 32)))
|
||||
helper.assertContainerExactly(helper.getEntity(EntityType.CHEST_MINECART), listOf(ItemStack(Blocks.DIRT, 48)))
|
||||
helper.assertEntityNotPresent(EntityType.ITEM)
|
||||
helper.assertContainerExactly(helper.getEntity(EntityTypes.CHEST_MINECART), listOf(ItemStack(Blocks.DIRT, 48)))
|
||||
helper.assertEntityNotPresent(EntityTypes.ITEM)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -621,7 +622,7 @@ class Turtle_Test {
|
||||
assertEquals("turtle_test.move_preserves_state", turtle.label)
|
||||
assertEquals(79, turtle.access.fuelLevel)
|
||||
|
||||
helper.assertEntityNotPresent(EntityType.ITEM)
|
||||
helper.assertEntityNotPresent(EntityTypes.ITEM)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,9 +678,9 @@ class Turtle_Test {
|
||||
|
||||
// As has the villager
|
||||
val pos = BlockPos(2, 3, 2)
|
||||
helper.assertEntityPresent(EntityType.VILLAGER, pos)
|
||||
helper.assertEntityPresent(EntityTypes.VILLAGER, pos)
|
||||
|
||||
val villager = helper.getEntity(EntityType.VILLAGER)
|
||||
val villager = helper.getEntity(EntityTypes.VILLAGER)
|
||||
val expectedY = helper.absolutePos(pos).y - 0.125
|
||||
if (villager.y < expectedY) helper.abort("Expected villager at y>=$expectedY, but at ${villager.y}", pos)
|
||||
}
|
||||
@@ -695,9 +696,9 @@ class Turtle_Test {
|
||||
turtle.attack(Optional.empty()).await().assertArrayEquals(true, message = "Attacked entity")
|
||||
}
|
||||
thenExecute {
|
||||
helper.assertEntityNotPresent(EntityType.SHEEP)
|
||||
helper.assertEntityNotPresent(EntityTypes.SHEEP)
|
||||
val count = helper.getBlockEntity(turtlePos, TurtleBlockEntity::class.java)
|
||||
.countItem(Items.WHITE_WOOL)
|
||||
.countItem(Items.WOOL.white)
|
||||
if (count == 0) helper.abort("Expected turtle to have white wool", turtlePos)
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -17,7 +17,7 @@ import net.minecraft.gametest.framework.GameTestHelper
|
||||
import net.minecraft.gametest.framework.GameTestSequence
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.EntityTypes
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.inventory.MenuType
|
||||
import java.util.concurrent.CompletableFuture
|
||||
@@ -68,14 +68,14 @@ fun GameTestSequence.thenScreenshot(name: String? = null, showGui: Boolean = fal
|
||||
|
||||
// Now disable the GUI, take a screenshot and reenable it. Sleep a little afterwards to ensure the render thread
|
||||
// has caught up.
|
||||
thenOnClient { minecraft.options.hideGui = !showGui }
|
||||
thenOnClient { if (minecraft.gui.hud.isHidden == showGui) minecraft.gui.hud.toggle() }
|
||||
thenIdle(2)
|
||||
|
||||
// Take a screenshot and wait for it to have finished.
|
||||
val hasScreenshot = AtomicBoolean()
|
||||
thenOnClient { screenshot("$fullName.png") { hasScreenshot.set(true) } }
|
||||
thenWaitUntil { if (!hasScreenshot.get()) abort("Screenshot does not exist") }
|
||||
thenOnClient { minecraft.options.hideGui = false }
|
||||
thenOnClient { if (minecraft.gui.hud.isHidden) minecraft.gui.hud.toggle() }
|
||||
|
||||
return this
|
||||
}
|
||||
@@ -91,7 +91,7 @@ fun ServerPlayer.setupForTest() {
|
||||
* Position the player at an armor stand.
|
||||
*/
|
||||
fun GameTestHelper.positionAtArmorStand() {
|
||||
val stand = getEntity(EntityType.ARMOR_STAND)
|
||||
val stand = getEntity(EntityTypes.ARMOR_STAND)
|
||||
val player = level.randomPlayer ?: abort("Player does not exist")
|
||||
|
||||
player.setupForTest()
|
||||
@@ -116,7 +116,7 @@ class ClientTestHelper {
|
||||
val minecraft: Minecraft = Minecraft.getInstance()
|
||||
|
||||
fun screenshot(name: String, callback: () -> Unit = {}) {
|
||||
Screenshot.grab(minecraft.gameDirectory, name, minecraft.mainRenderTarget, 1) { callback() }
|
||||
Screenshot.grab(minecraft.gameDirectory, name, minecraft.gameRenderer.mainRenderTarget(), 1) { callback() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +125,7 @@ class ClientTestHelper {
|
||||
fun <T : AbstractContainerMenu> getOpenMenu(type: MenuType<T>): T {
|
||||
fun getName(type: MenuType<*>) = RegistryHelper.getKeyOrThrow(BuiltInRegistries.MENU, type)
|
||||
|
||||
val screen = minecraft.screen
|
||||
val screen = minecraft.gui.screen()
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
when {
|
||||
screen == null -> throw GameTestAssertException(Component.literal("Expected a ${getName(type)} menu, but no screen is open"), 0)
|
||||
|
||||
+3
-2
@@ -30,6 +30,7 @@ import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.clock.WorldClock
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.entity.EntityType
|
||||
import net.minecraft.world.entity.EntityTypes
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.ItemStackTemplate
|
||||
@@ -294,7 +295,7 @@ fun GameTestHelper.assertNoPeripheral(pos: BlockPos, direction: Direction = Dire
|
||||
}
|
||||
|
||||
fun GameTestHelper.assertExactlyItems(vararg expected: ItemStack, message: String? = null) {
|
||||
val actual = getEntities(EntityType.ITEM).map { it.item }
|
||||
val actual = getEntities(EntityTypes.ITEM).map { it.item }
|
||||
val matcher = Matchers.containsInAnyOrder(expected.map { isStack(it) })
|
||||
if (!matcher.matches(actual)) {
|
||||
val description = StringDescription()
|
||||
@@ -307,7 +308,7 @@ fun GameTestHelper.assertExactlyItems(vararg expected: ItemStack, message: Strin
|
||||
* Similar to [GameTestHelper.assertItemEntityCountIs], but searching anywhere in the structure bounds.
|
||||
*/
|
||||
fun GameTestHelper.assertItemEntityCountIs(expected: Item, count: Int) {
|
||||
val actualCount = getEntities(EntityType.ITEM).sumOf { if (it.item.`is`(expected)) it.item.count else 0 }
|
||||
val actualCount = getEntities(EntityTypes.ITEM).sumOf { if (it.item.`is`(expected)) it.item.count else 0 }
|
||||
if (actualCount != count) {
|
||||
abort("Expected $count ${ItemStack(expected).itemName.string} items to exist (found $actualCount)")
|
||||
}
|
||||
|
||||
+1
-1
@@ -83,7 +83,7 @@ object ClientTestHooks {
|
||||
|
||||
if (minecraft.levelSource.levelExists(LEVEL_NAME)) {
|
||||
LOG.info("World already exists, opening.")
|
||||
minecraft.createWorldOpenFlows().openWorld(LEVEL_NAME) { minecraft.setScreen(screen) }
|
||||
minecraft.createWorldOpenFlows().openWorld(LEVEL_NAME) { minecraft.gui.setScreen(screen) }
|
||||
} else {
|
||||
LOG.info("World does not exist, creating it.")
|
||||
val rules = GameRules(FeatureFlags.DEFAULT_FLAGS)
|
||||
|
||||
@@ -22,6 +22,7 @@ import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.LevelAccessor
|
||||
import net.minecraft.world.level.block.Blocks
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTypes
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.minecraft.world.level.gamerules.GameRules
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager
|
||||
@@ -91,7 +92,7 @@ object TestHooks {
|
||||
|
||||
val level = server.overworld()
|
||||
StructureUtils.findTestBlocks(getTestOrigin(server), 200, level).toList().forEach { pos ->
|
||||
val test = level.getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK).getOrNull() ?: return@forEach
|
||||
val test = level.getBlockEntity(pos, BlockEntityTypes.TEST_INSTANCE_BLOCK).getOrNull() ?: return@forEach
|
||||
StructureUtils.clearSpaceForStructure(test.structureBoundingBox, level)
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"required": true,
|
||||
"package": "dan200.computercraft.mixin.gametest",
|
||||
"minVersion": "0.8",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* An abstract mount based on some archive of files, such as a Zip or Minecraft's resources.
|
||||
@@ -33,7 +33,7 @@ public abstract class ArchiveMount<T extends ArchiveMount.FileEntry<T>> extends
|
||||
*/
|
||||
private static final Cache<FileEntry<?>, byte[]> CONTENTS_CACHE = CacheBuilder.newBuilder()
|
||||
.concurrencyLevel(4)
|
||||
.expireAfterAccess(60, TimeUnit.SECONDS)
|
||||
.expireAfterAccess(Duration.ofSeconds(60))
|
||||
.maximumWeight(MAX_CACHE_SIZE)
|
||||
.weakKeys()
|
||||
.<FileEntry<?>, byte[]>weigher((k, v) -> v.length)
|
||||
|
||||
+9
-6
@@ -13,6 +13,7 @@ import dan200.computercraft.client.platform.ClientNetworkContextImpl;
|
||||
import dan200.computercraft.client.platform.FabricModelKey;
|
||||
import dan200.computercraft.client.platform.ModelKey;
|
||||
import dan200.computercraft.client.render.BlockOutlineRenderer;
|
||||
import dan200.computercraft.client.render.ExtendedItemFrameRenderState;
|
||||
import dan200.computercraft.shared.ComputerCraft;
|
||||
import dan200.computercraft.shared.config.ConfigSpec;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
@@ -25,6 +26,7 @@ import net.fabricmc.fabric.api.client.model.loading.v1.UnbakedExtraModel;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.ModelLayerRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.PictureInPictureRendererRegistry;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.RenderStateDataKey;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -32,7 +34,6 @@ import net.minecraft.client.color.item.ItemTintSources;
|
||||
import net.minecraft.client.gui.components.debug.DebugScreenEntries;
|
||||
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.item.ItemModels;
|
||||
import net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperties;
|
||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperties;
|
||||
@@ -46,9 +47,11 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ComputerCraftClient {
|
||||
public static final RenderStateDataKey<ExtendedItemFrameRenderState> ITEM_FRAME_STATE = RenderStateDataKey.create(() -> "Extended item frame");
|
||||
|
||||
public static void init() {
|
||||
var clientNetwork = new ClientNetworkContextImpl();
|
||||
for (var type : NetworkMessages.getClientbound()) {
|
||||
@@ -78,8 +81,8 @@ public class ComputerCraftClient {
|
||||
|
||||
ClientRegistry.registerPictureInPictureRenderers(new ClientRegistry.RegisterPictureInPictureRenderer() {
|
||||
@Override
|
||||
public <T extends PictureInPictureRenderState> void register(Class<T> ty, Function<MultiBufferSource.BufferSource, PictureInPictureRenderer<T>> f) {
|
||||
PictureInPictureRendererRegistry.register(c -> f.apply(c.bufferSource()));
|
||||
public <T extends PictureInPictureRenderState> void register(Class<T> ty, Supplier<PictureInPictureRenderer<T>> f) {
|
||||
PictureInPictureRendererRegistry.register(c -> f.get());
|
||||
}
|
||||
});
|
||||
|
||||
@@ -92,11 +95,11 @@ public class ComputerCraftClient {
|
||||
return true;
|
||||
}
|
||||
|
||||
var camera = context.gameRenderer().getMainCamera();
|
||||
var camera = context.gameRenderer().mainCamera();
|
||||
var renderer = ClientHooks.drawHighlight(camera, blockHit);
|
||||
if (renderer == null) return true;
|
||||
|
||||
BlockOutlineRenderer.render(context.poseStack(), context.bufferSource(), renderer);
|
||||
BlockOutlineRenderer.render(context.poseStack(), context.submitNodeCollector(), renderer, camera, blockHit);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.render.ExtendedItemFrameRenderState;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||
|
||||
/**
|
||||
* An interface implemented on {@link ItemFrameRenderState} to provide a {@link ExtendedItemFrameRenderState}.
|
||||
*
|
||||
* @see ClientHooks#onRenderItemFrame(PoseStack, SubmitNodeCollector, ItemFrameRenderState, ExtendedItemFrameRenderState)
|
||||
*/
|
||||
public interface ExtendedItemFrameRenderStateHolder {
|
||||
/**
|
||||
* Get or create the CC-specific render state.
|
||||
*
|
||||
* @return The CC-specific render state.
|
||||
*/
|
||||
ExtendedItemFrameRenderState computercraft$state();
|
||||
}
|
||||
+10
@@ -5,7 +5,12 @@
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.impl.client.ExtendedOrderedSubmitNodeCollector;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.fabricmc.fabric.api.client.model.loading.v1.ExtraModelKey;
|
||||
import net.minecraft.client.renderer.OrderedSubmitNodeCollector;
|
||||
import net.minecraft.client.resources.model.ModelDebugName;
|
||||
|
||||
@AutoService(ClientPlatformHelper.class)
|
||||
@@ -14,4 +19,9 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
public <T> ModelKey<T> createModelKey(ModelDebugName name) {
|
||||
return new FabricModelKey<>(ExtraModelKey.create(name::debugName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitMonitor(OrderedSubmitNodeCollector collector, PoseStack poseStack, ClientMonitor monitor, Terminal terminal, float xMargin, float yMargin) {
|
||||
((ExtendedOrderedSubmitNodeCollector) collector).computercraft$submitMonitor(poseStack, monitor, terminal, xMargin, yMargin);
|
||||
}
|
||||
}
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.impl.client;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.minecraft.client.renderer.OrderedSubmitNodeCollector;
|
||||
|
||||
/**
|
||||
* Extension interface to {@link OrderedSubmitNodeCollector} that allows submitting monitor contents.
|
||||
*
|
||||
* @see MonitorBlockEntityRenderer
|
||||
*/
|
||||
public interface ExtendedOrderedSubmitNodeCollector {
|
||||
default void computercraft$submitMonitor(
|
||||
PoseStack poseStack, ClientMonitor monitor, Terminal terminal, float xMargin, float yMargin
|
||||
) {
|
||||
var collector = (OrderedSubmitNodeCollector) this;
|
||||
collector.submitCustomGeometry(poseStack, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> {
|
||||
FixedWidthFontRenderer.drawTerminalBackground(pose.pose(), buffer, 0, 0, terminal, yMargin, yMargin, xMargin, xMargin);
|
||||
});
|
||||
collector.submitCustomGeometry(poseStack, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, (pose, buffer) -> {
|
||||
FixedWidthFontRenderer.drawTerminalForeground(pose.pose(), buffer, 0, 0, terminal);
|
||||
FixedWidthFontRenderer.drawCursor(pose.pose(), buffer, 0, 0, terminal);
|
||||
});
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import dan200.computercraft.client.ClientRegistry;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollection;
|
||||
import net.minecraft.client.renderer.feature.FeatureRenderDispatcher;
|
||||
import net.minecraft.client.renderer.feature.FeatureRenderer;
|
||||
import net.minecraft.client.renderer.feature.FeatureRendererMap;
|
||||
import net.minecraft.client.renderer.feature.FeatureRendererType;
|
||||
import net.minecraft.client.renderer.feature.submit.SubmitNode;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Monitor support for {@link SubmitNodeCollection}.
|
||||
*/
|
||||
@Mixin(FeatureRenderDispatcher.class)
|
||||
abstract class FeatureRenderDispatcherMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private FeatureRendererMap featureRenderers;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
@SuppressWarnings("unused")
|
||||
private void registerExtendedFeatureRenderers(CallbackInfo ci) {
|
||||
ClientRegistry.registerFeatureRenderers(new ClientRegistry.RegisterFeatureRenderer() {
|
||||
@Override
|
||||
public <T extends SubmitNode> void register(FeatureRendererType<T> type, Supplier<FeatureRenderer<T>> renderer) {
|
||||
featureRenderers.put(type, renderer.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
-22
@@ -1,22 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import dan200.computercraft.client.ExtendedItemFrameRenderStateHolder;
|
||||
import dan200.computercraft.client.render.ExtendedItemFrameRenderState;
|
||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
@Mixin(ItemFrameRenderState.class)
|
||||
class ItemFrameRenderStateMixin implements ExtendedItemFrameRenderStateHolder {
|
||||
private @Nullable ExtendedItemFrameRenderState computercraft$state;
|
||||
|
||||
@Override
|
||||
public ExtendedItemFrameRenderState computercraft$state() {
|
||||
if (computercraft$state == null) computercraft$state = new ExtendedItemFrameRenderState();
|
||||
return computercraft$state;
|
||||
}
|
||||
}
|
||||
+15
-5
@@ -6,7 +6,8 @@ package dan200.computercraft.mixin.client;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.ClientHooks;
|
||||
import dan200.computercraft.client.ExtendedItemFrameRenderStateHolder;
|
||||
import dan200.computercraft.client.ComputerCraftClient;
|
||||
import dan200.computercraft.client.render.ExtendedItemFrameRenderState;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.entity.ItemFrameRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||
@@ -14,6 +15,7 @@ import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@@ -27,9 +29,8 @@ class ItemFrameRendererMixin {
|
||||
cancellable = true
|
||||
)
|
||||
@SuppressWarnings("unused")
|
||||
private void submit(ItemFrameRenderState frame, PoseStack pose, SubmitNodeCollector buffers, CameraRenderState camera, CallbackInfo ci) {
|
||||
var state = ((ExtendedItemFrameRenderStateHolder) frame).computercraft$state();
|
||||
if (ClientHooks.onRenderItemFrame(pose, buffers, frame, state)) {
|
||||
private void submit(ItemFrameRenderState state, PoseStack pose, SubmitNodeCollector buffers, CameraRenderState camera, CallbackInfo ci) {
|
||||
if (ClientHooks.onRenderItemFrame(pose, buffers, state, getState(state))) {
|
||||
ci.cancel();
|
||||
pose.popPose();
|
||||
}
|
||||
@@ -41,6 +42,15 @@ class ItemFrameRendererMixin {
|
||||
)
|
||||
@SuppressWarnings("unused")
|
||||
private void extractRenderState(ItemFrame entity, ItemFrameRenderState state, float f, CallbackInfo ci) {
|
||||
((ExtendedItemFrameRenderStateHolder) state).computercraft$state().setup(entity.getItem());
|
||||
getState(state).setup(entity.getItem());
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static ExtendedItemFrameRenderState getState(ItemFrameRenderState state) {
|
||||
var extendedState = state.getData(ComputerCraftClient.ITEM_FRAME_STATE);
|
||||
if (extendedState == null) {
|
||||
state.setData(ComputerCraftClient.ITEM_FRAME_STATE, extendedState = new ExtendedItemFrameRenderState());
|
||||
}
|
||||
return extendedState;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,9 +18,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ItemInHandRenderer.class)
|
||||
class ItemInHandRendererMixin {
|
||||
@Inject(method = "renderArmWithItem", at = @At("HEAD"), cancellable = true)
|
||||
@Inject(method = "submitArmWithItem", at = @At("HEAD"), cancellable = true)
|
||||
@SuppressWarnings("unused")
|
||||
private void onRenderItem(
|
||||
private void onSubmitArmWithItem(
|
||||
AbstractClientPlayer player, float partialTicks, float pitch, InteractionHand hand, float swingProgress, ItemStack stack,
|
||||
float equippedProgress, PoseStack transform, SubmitNodeCollector collector, int combinedLight, CallbackInfo ci
|
||||
) {
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import dan200.computercraft.impl.client.ExtendedOrderedSubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.OrderedSubmitNodeCollector;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
/**
|
||||
* Monitor support for {@link OrderedSubmitNodeCollector}.
|
||||
*/
|
||||
@Mixin(OrderedSubmitNodeCollector.class)
|
||||
interface OrderedSubmitNodeCollectorMixin extends ExtendedOrderedSubmitNodeCollector {
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||
import dan200.computercraft.client.render.monitor.MonitorRenderState;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.impl.client.ExtendedOrderedSubmitNodeCollector;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollection;
|
||||
import net.minecraft.client.renderer.feature.phase.SimpleFeatureRenderPhase;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
/**
|
||||
* Monitor support for {@link SubmitNodeCollection}.
|
||||
*/
|
||||
@Mixin(SubmitNodeCollection.class)
|
||||
abstract class SubmitNodeCollectionMixin implements ExtendedOrderedSubmitNodeCollector {
|
||||
@Shadow
|
||||
@Final
|
||||
public SimpleFeatureRenderPhase solid;
|
||||
|
||||
@Override
|
||||
public void computercraft$submitMonitor(PoseStack poseStack, ClientMonitor monitor, Terminal terminal, float xMargin, float yMargin) {
|
||||
var renderState = monitor.getRenderState(MonitorRenderState::new);
|
||||
solid.submit(new MonitorBlockEntityRenderer.MonitorSubmit(poseStack.last().copy(), monitor, terminal, renderState, xMargin, yMargin));
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// SPDX-FileCopyrightText: 2026 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.impl.client.ExtendedOrderedSubmitNodeCollector;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
|
||||
/**
|
||||
* Monitor support for {@link SubmitNodeCollector}.
|
||||
*/
|
||||
@Mixin(SubmitNodeCollector.class)
|
||||
interface SubmitNodeCollectorMixin extends ExtendedOrderedSubmitNodeCollector {
|
||||
@Override
|
||||
default void computercraft$submitMonitor(PoseStack poseStack, ClientMonitor monitor, Terminal terminal, float xMargin, float yMargin) {
|
||||
((ExtendedOrderedSubmitNodeCollector) ((SubmitNodeCollector) this).order(0)).computercraft$submitMonitor(poseStack, monitor, terminal, xMargin, yMargin);
|
||||
}
|
||||
}
|
||||
@@ -2,16 +2,19 @@
|
||||
"required": true,
|
||||
"package": "dan200.computercraft.mixin.client",
|
||||
"minVersion": "0.8",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"client": [
|
||||
"FeatureRenderDispatcherMixin",
|
||||
"ItemFrameRendererMixin",
|
||||
"ItemFrameRenderStateMixin",
|
||||
"ItemInHandRendererMixin",
|
||||
"MinecraftMixin",
|
||||
"MultiPlayerGameModeMixin",
|
||||
"SoundEngineMixin"
|
||||
"OrderedSubmitNodeCollectorMixin",
|
||||
"SoundEngineMixin",
|
||||
"SubmitNodeCollectionMixin",
|
||||
"SubmitNodeCollectorMixin"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class FabricDataProviders implements DataGeneratorEntrypoint {
|
||||
return addWithRegistries((out, registries) -> new FabricTagsProvider.BlockTagsProvider(out, registries) {
|
||||
@Override
|
||||
protected void addTags(HolderLookup.Provider registries) {
|
||||
tags.accept(this::valueLookupBuilder);
|
||||
tags.accept(this::builder);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public class FabricDataProviders implements DataGeneratorEntrypoint {
|
||||
return addWithRegistries((out, registries) -> new FabricTagsProvider.ItemTagsProvider(out, registries) {
|
||||
@Override
|
||||
protected void addTags(HolderLookup.Provider registries) {
|
||||
tags.accept(this::valueLookupBuilder);
|
||||
tags.accept(this::builder);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class FabricDataProviders implements DataGeneratorEntrypoint {
|
||||
|
||||
@Override
|
||||
protected void configure(HolderLookup.Provider registries, Entries entries) {
|
||||
for (var reg : DynamicRegistries.getDynamicRegistries()) {
|
||||
for (var reg : DynamicRegistries.getBootstrappingRegistries()) {
|
||||
registries.lookupOrThrow(reg.key()).listElements().forEach(x -> register(entries, x));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import net.fabricmc.api.ModInitializer;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTypes;
|
||||
|
||||
/**
|
||||
* The main entry point for our example mod.
|
||||
@@ -25,7 +25,7 @@ public class FabricExampleMod implements ModInitializer {
|
||||
ExampleMod.registerComputerCraft();
|
||||
|
||||
// @start region=peripherals
|
||||
PeripheralLookup.get().registerForBlockEntity((f, s) -> new BrewingStandPeripheral(f), BlockEntityType.BREWING_STAND);
|
||||
PeripheralLookup.get().registerForBlockEntity((f, s) -> new BrewingStandPeripheral(f), BlockEntityTypes.BREWING_STAND);
|
||||
// @end region=peripherals
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ public class FabricExampleModDataGenerator implements DataGeneratorEntrypoint {
|
||||
|
||||
@Override
|
||||
protected void configure(HolderLookup.Provider registries, Entries entries) {
|
||||
for (var r : DynamicRegistries.getDynamicRegistries()) entries.addAll(registries.lookupOrThrow(r.key()));
|
||||
for (var r : DynamicRegistries.getWorldRegistries()) entries.addAll(registries.lookupOrThrow(r.key()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.integration;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.shared.command.UserLevel;
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* An implementation of {@link PermissionRegistry} using Fabric's unofficial {@linkplain Permissions permissions api}.
|
||||
*/
|
||||
public final class FabricPermissionRegistry extends PermissionRegistry {
|
||||
private FabricPermissionRegistry() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<CommandSourceStack> registerCommand(String command, UserLevel fallback) {
|
||||
checkNotFrozen();
|
||||
// var name = ComputerCraftAPI.MOD_ID + ".command." + command;
|
||||
// Permissions.getPermissionValue(source, name).orElseGet(() -> ...)
|
||||
return fallback;
|
||||
}
|
||||
|
||||
@AutoService(PermissionRegistry.Provider.class)
|
||||
public static final class Provider implements PermissionRegistry.Provider {
|
||||
@Override
|
||||
public Optional<PermissionRegistry> get() {
|
||||
return FabricLoader.getInstance().isModLoaded("fabric-permissions-api-v0")
|
||||
? Optional.of(new FabricPermissionRegistry())
|
||||
: Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
-1
@@ -18,6 +18,7 @@ import dan200.computercraft.api.peripheral.PeripheralLookup;
|
||||
import dan200.computercraft.impl.Peripherals;
|
||||
import dan200.computercraft.mixin.ArgumentTypeInfosAccessor;
|
||||
import dan200.computercraft.shared.ComputerCraft;
|
||||
import dan200.computercraft.shared.command.UserLevel;
|
||||
import dan200.computercraft.shared.config.ConfigFile;
|
||||
import dan200.computercraft.shared.network.container.ContainerData;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
@@ -29,10 +30,12 @@ import net.fabricmc.fabric.api.lookup.v1.block.BlockApiCache;
|
||||
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiLookup;
|
||||
import net.fabricmc.fabric.api.menu.v1.ExtendedMenuProvider;
|
||||
import net.fabricmc.fabric.api.menu.v1.ExtendedMenuType;
|
||||
import net.fabricmc.fabric.api.permission.v1.PermissionNode;
|
||||
import net.fabricmc.fabric.api.tag.convention.v2.ConventionalItemTags;
|
||||
import net.fabricmc.fabric.api.transfer.v1.item.ContainerStorage;
|
||||
import net.fabricmc.fabric.api.transfer.v1.item.ItemStorage;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@@ -71,6 +74,7 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@AutoService(PlatformHelper.class)
|
||||
@@ -97,6 +101,11 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return new RegistrationHelperImpl<>(getRegistry(registry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionRegistry createPermissionRegistry() {
|
||||
return new PermissionRegistryImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>, I extends ArgumentTypeInfo<A, T>> I registerArgumentTypeInfo(Class<A> klass, I info) {
|
||||
ArgumentTypeInfosAccessor.classMap().put(klass, info);
|
||||
@@ -255,7 +264,16 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
|
||||
@Override
|
||||
public <U extends T> RegistryEntry<U> register(String name, Supplier<U> create) {
|
||||
var entry = new RegistryEntryImpl<>(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name), create);
|
||||
return register(ResourceKey.create(registry.key(), Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, name)), create);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U extends T> RegistryEntry<U> register(ResourceKey<T> id, Supplier<U> create) {
|
||||
if (!id.identifier().getNamespace().equals(ComputerCraftAPI.MOD_ID)) {
|
||||
throw new IllegalArgumentException("Can only register items for ComputerCraft");
|
||||
}
|
||||
|
||||
var entry = new RegistryEntryImpl<>(id.identifier(), create);
|
||||
entries.add(entry);
|
||||
return entry;
|
||||
}
|
||||
@@ -292,6 +310,19 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class PermissionRegistryImpl extends PermissionRegistry {
|
||||
@Override
|
||||
public Predicate<CommandSourceStack> registerCommand(String command, UserLevel fallback) {
|
||||
checkNotFrozen();
|
||||
var node = PermissionNode.of(Identifier.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "command." + command));
|
||||
return source -> {
|
||||
var result = source.checkPermission(node);
|
||||
return result == null ? fallback.test(source) : result;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private record WrappedMenuProvider<T extends ContainerData>(
|
||||
Component title, MenuConstructor menu, T data
|
||||
) implements ExtendedMenuProvider<T> {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"required": true,
|
||||
"package": "dan200.computercraft.mixin",
|
||||
"minVersion": "0.8",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
|
||||
@@ -47,8 +47,8 @@
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.19.3",
|
||||
"fabric-api": ">=0.146.1",
|
||||
"minecraft": "~26.1.2"
|
||||
"fabric-api": ">=0.152.0",
|
||||
"minecraft": ">=26.2 <26.3"
|
||||
},
|
||||
"accessWidener": "computercraft.accesswidener"
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"required": true,
|
||||
"package": "dan200.computercraft.mixin.gametest",
|
||||
"minVersion": "0.8",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
},
|
||||
|
||||
@@ -49,8 +49,8 @@ public final class ForgeClientHooks {
|
||||
var renderer = ClientHooks.drawHighlight(event.getCamera(), event.getHitResult());
|
||||
if (renderer == null) return;
|
||||
|
||||
event.addCustomRenderer((state, buffers, transform, translucentPass, renderState) -> {
|
||||
BlockOutlineRenderer.render(transform, buffers, renderer);
|
||||
event.addCustomRenderer((state, buffers, transform, renderState) -> {
|
||||
BlockOutlineRenderer.render(transform, buffers, renderer, event.getCamera(), event.getHitResult());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,9 @@ import dan200.computercraft.client.render.ExtendedItemFrameRenderState;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.entity.ItemFrameRenderer;
|
||||
import net.minecraft.client.renderer.feature.FeatureRenderer;
|
||||
import net.minecraft.client.renderer.feature.FeatureRendererType;
|
||||
import net.minecraft.client.renderer.feature.submit.SubmitNode;
|
||||
import net.minecraft.client.resources.model.ModelBaker;
|
||||
import net.minecraft.client.resources.model.ModelDebugName;
|
||||
import net.minecraft.client.resources.model.ResolvableModel;
|
||||
@@ -32,6 +35,7 @@ import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
||||
/**
|
||||
@@ -123,6 +127,16 @@ public final class ForgeClientRegistry {
|
||||
ClientRegistry.registerDebugScreenEntries(event::register);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerFeatureRenderers(RegisterFeatureRenderersEvent event) {
|
||||
ClientRegistry.registerFeatureRenderers(new ClientRegistry.RegisterFeatureRenderer() {
|
||||
@Override
|
||||
public <T extends SubmitNode> void register(FeatureRendererType<T> type, Supplier<FeatureRenderer<T>> renderer) {
|
||||
event.register(type, renderer.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void setupClient(FMLClientSetupEvent event) {
|
||||
ClientRegistry.register();
|
||||
|
||||
+15
@@ -5,8 +5,15 @@
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||
import dan200.computercraft.client.render.monitor.MonitorRenderState;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
|
||||
import net.minecraft.client.renderer.OrderedSubmitNodeCollector;
|
||||
import net.minecraft.client.resources.model.ModelDebugName;
|
||||
import net.neoforged.neoforge.client.model.standalone.StandaloneModelKey;
|
||||
import net.neoforged.neoforge.client.submit.RenderPhaseKeys;
|
||||
|
||||
@AutoService(ClientPlatformHelper.class)
|
||||
public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
@@ -14,4 +21,12 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
public <T> ModelKey<T> createModelKey(ModelDebugName name) {
|
||||
return new ForgeModelKey<>(new StandaloneModelKey<T>(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submitMonitor(OrderedSubmitNodeCollector collector, PoseStack poseStack, ClientMonitor monitor, Terminal terminal, float xMargin, float yMargin) {
|
||||
var renderState = monitor.getRenderState(MonitorRenderState::new);
|
||||
collector.submitSpecial(
|
||||
RenderPhaseKeys.SOLID, new MonitorBlockEntityRenderer.MonitorSubmit(poseStack.last().copy(), monitor, terminal, renderState, xMargin, yMargin)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,11 @@ import net.minecraft.core.RegistrySetBuilder;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.tags.BlockItemTagAppender;
|
||||
import net.minecraft.data.tags.TagsProvider;
|
||||
import net.minecraft.references.BlockItemId;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
@@ -63,7 +66,12 @@ public class ForgeDataProviders {
|
||||
return add(out -> new BlockTagsProvider(out, registries, ComputerCraftAPI.MOD_ID) {
|
||||
@Override
|
||||
protected void addTags(HolderLookup.Provider registries) {
|
||||
tags.accept(this::tag);
|
||||
tags.accept(tag -> new BlockItemTagAppender<>(tag(tag)) {
|
||||
@Override
|
||||
protected ResourceKey<Block> convertElement(BlockItemId blockItemId) {
|
||||
return blockItemId.block();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -73,7 +81,12 @@ public class ForgeDataProviders {
|
||||
return add(out -> new ItemTagsProvider(out, registries, ComputerCraftAPI.MOD_ID) {
|
||||
@Override
|
||||
protected void addTags(HolderLookup.Provider registries) {
|
||||
tags.accept(this::tag);
|
||||
tags.accept(tag -> new BlockItemTagAppender<Item>(tag(tag)) {
|
||||
@Override
|
||||
protected ResourceKey<Item> convertElement(BlockItemId blockItemId) {
|
||||
return blockItemId.item();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.example.examplemod.peripheral.BrewingStandPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralCapability;
|
||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTypes;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
@@ -34,7 +34,7 @@ public class ForgeExampleMod {
|
||||
|
||||
// @start region=peripherals
|
||||
modBus.addListener((RegisterCapabilitiesEvent event) -> {
|
||||
event.registerBlockEntity(PeripheralCapability.get(), BlockEntityType.BREWING_STAND, (b, d) -> new BrewingStandPeripheral(b));
|
||||
event.registerBlockEntity(PeripheralCapability.get(), BlockEntityTypes.BREWING_STAND, (b, d) -> new BrewingStandPeripheral(b));
|
||||
});
|
||||
// @end region=peripherals
|
||||
}
|
||||
|
||||
-65
@@ -1,65 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.integration;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.shared.command.UserLevel;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.server.permission.PermissionAPI;
|
||||
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionType;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* An implementation of {@link PermissionRegistry} using Forge's {@link PermissionAPI}.
|
||||
*/
|
||||
public final class ForgePermissionRegistry extends PermissionRegistry {
|
||||
private final List<PermissionNode<?>> nodes = new ArrayList<>();
|
||||
|
||||
private ForgePermissionRegistry() {
|
||||
}
|
||||
|
||||
private <T> PermissionNode<T> registerNode(String nodeName, PermissionType<T> type, PermissionNode.PermissionResolver<T> defaultResolver) {
|
||||
checkNotFrozen();
|
||||
var node = new PermissionNode<>(ComputerCraftAPI.MOD_ID, nodeName, type, defaultResolver);
|
||||
nodes.add(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<CommandSourceStack> registerCommand(String command, UserLevel fallback) {
|
||||
var node = registerNode(
|
||||
"command." + command, PermissionTypes.BOOLEAN,
|
||||
(player, uuid, context) -> player != null && fallback.test(player)
|
||||
);
|
||||
|
||||
return source -> {
|
||||
var player = source.getPlayer();
|
||||
return player == null ? fallback.test(source) : PermissionAPI.getPermission(player, node);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
super.register();
|
||||
NeoForge.EVENT_BUS.addListener((PermissionGatherEvent.Nodes event) -> event.addNodes(nodes));
|
||||
}
|
||||
|
||||
@AutoService(PermissionRegistry.Provider.class)
|
||||
public static final class Provider implements PermissionRegistry.Provider {
|
||||
@Override
|
||||
public Optional<PermissionRegistry> get() {
|
||||
return Optional.of(new ForgePermissionRegistry());
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -16,9 +16,11 @@ import dan200.computercraft.api.network.wired.WiredElementCapability;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.api.peripheral.PeripheralCapability;
|
||||
import dan200.computercraft.impl.Peripherals;
|
||||
import dan200.computercraft.shared.command.UserLevel;
|
||||
import dan200.computercraft.shared.config.ConfigFile;
|
||||
import dan200.computercraft.shared.network.container.ContainerData;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -59,19 +61,27 @@ import net.neoforged.neoforge.capabilities.BlockCapabilityCache;
|
||||
import net.neoforged.neoforge.capabilities.Capabilities;
|
||||
import net.neoforged.neoforge.common.CommonHooks;
|
||||
import net.neoforged.neoforge.common.ItemAbilities;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.neoforged.neoforge.common.Tags;
|
||||
import net.neoforged.neoforge.common.extensions.IMenuTypeExtension;
|
||||
import net.neoforged.neoforge.event.EventHooks;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
import net.neoforged.neoforge.server.permission.PermissionAPI;
|
||||
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionType;
|
||||
import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
|
||||
import net.neoforged.neoforge.transfer.item.VanillaContainerWrapper;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@AutoService(PlatformHelper.class)
|
||||
@@ -91,6 +101,11 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return new RegistrationHelperImpl<>(DeferredRegister.create(registry, ComputerCraftAPI.MOD_ID));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionRegistry createPermissionRegistry() {
|
||||
return new PermissionRegistryImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <A extends ArgumentType<?>, T extends ArgumentTypeInfo.Template<A>, I extends ArgumentTypeInfo<A, T>> I registerArgumentTypeInfo(Class<A> klass, I info) {
|
||||
return ArgumentTypeInfos.registerByClass(klass, info);
|
||||
@@ -255,6 +270,15 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return new RegistryEntryImpl<>(registry().register(name, create));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <U extends R> RegistryEntry<U> register(ResourceKey<R> id, Supplier<U> create) {
|
||||
if (!id.identifier().getNamespace().equals(ComputerCraftAPI.MOD_ID)) {
|
||||
throw new IllegalArgumentException("Can only register items for ComputerCraft");
|
||||
}
|
||||
|
||||
return register(id.identifier().getPath(), create);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
registry().register(ComputerCraft.getEventBus());
|
||||
@@ -321,4 +345,37 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return Peripherals.getGenericPeripheral(cache.level(), cache.pos(), cache.context(), cache.level().getBlockEntity(cache.pos()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of {@link PermissionRegistry} using Forge's {@link PermissionAPI}.
|
||||
*/
|
||||
private static final class PermissionRegistryImpl extends PermissionRegistry {
|
||||
private final List<PermissionNode<?>> nodes = new ArrayList<>();
|
||||
|
||||
private <T> PermissionNode<T> registerNode(String nodeName, PermissionType<T> type, PermissionNode.PermissionResolver<T> defaultResolver) {
|
||||
checkNotFrozen();
|
||||
var node = new PermissionNode<>(ComputerCraftAPI.MOD_ID, nodeName, type, defaultResolver);
|
||||
nodes.add(node);
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate<CommandSourceStack> registerCommand(String command, UserLevel fallback) {
|
||||
var node = registerNode(
|
||||
"command." + command, PermissionTypes.BOOLEAN,
|
||||
(player, uuid, context) -> player != null && fallback.test(player)
|
||||
);
|
||||
|
||||
return source -> {
|
||||
var player = source.getPlayer();
|
||||
return player == null ? fallback.test(source) : PermissionAPI.getPermission(player, node);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register() {
|
||||
super.register();
|
||||
NeoForge.EVENT_BUS.addListener((PermissionGatherEvent.Nodes event) -> event.addNodes(nodes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
public net.minecraft.client.gui.components.ChatComponent allMessages
|
||||
public net.minecraft.client.gui.components.ChatComponent addMessage(Lnet/minecraft/network/chat/Component;Lnet/minecraft/network/chat/MessageSignature;Lnet/minecraft/client/multiplayer/chat/GuiMessageSource;Lnet/minecraft/client/multiplayer/chat/GuiMessageTag;)V
|
||||
|
||||
# NoTermComputerScreen
|
||||
public net.minecraft.client.gui.Gui screen
|
||||
|
||||
# ItemPocketRenderer/ItemPrintoutRenderer
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer calculateMapTilt(F)F
|
||||
public net.minecraft.client.renderer.ItemInHandRenderer renderMapHand(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/SubmitNodeCollector;ILnet/minecraft/world/entity/HumanoidArm;)V
|
||||
|
||||
@@ -26,7 +26,7 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
|
||||
[[dependencies.computercraft]]
|
||||
modId="neoforge"
|
||||
type="required"
|
||||
versionRange="[${neoVersion},26.2)"
|
||||
versionRange="[${neoVersion},26.3)"
|
||||
ordering="NONE"
|
||||
side="BOTH"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user