mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-05-23 01:34:11 +00:00
Store command computers in a separate folder
- Remove the /computercraft-computer-folder client command, and replace it with OPEN_FILE on NeoForge, or a /computercraft-open-folder command on Fabric (which now accepts a path, rather than an id). - Store command computer files in "computercraft/command_computer/<id>". Fixes #1581.
This commit is contained in:
parent
9277aa33e9
commit
05163a4911
@ -4,10 +4,6 @@
|
||||
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.turtle.RegisterTurtleUpgradeModeller;
|
||||
@ -24,11 +20,8 @@ import dan200.computercraft.client.render.monitor.MonitorBlockEntityRenderer;
|
||||
import dan200.computercraft.client.turtle.TurtleModemModeller;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.core.ServerContext;
|
||||
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
|
||||
import dan200.computercraft.shared.turtle.TurtleOverlay;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.item.ItemTintSource;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
@ -39,13 +32,11 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
|
||||
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;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.packs.resources.PreparableReloadListener;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
@ -133,45 +124,4 @@ public final class ClientRegistry {
|
||||
public static void registerConditionalItemProperties(BiConsumer<ResourceLocation, MapCodec<? extends ConditionalItemModelProperty>> register) {
|
||||
register.accept(TurtleShowElfOverlay.ID, TurtleShowElfOverlay.CODEC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register client-side commands.
|
||||
*
|
||||
* @param dispatcher The dispatcher to register the commands to.
|
||||
* @param sendError A function to send an error message.
|
||||
* @param <T> The type of the client-side command context.
|
||||
*/
|
||||
public static <T> void registerClientCommands(CommandDispatcher<T> dispatcher, BiConsumer<T, Component> sendError) {
|
||||
dispatcher.register(LiteralArgumentBuilder.<T>literal(CommandComputerCraft.CLIENT_OPEN_FOLDER)
|
||||
.requires(x -> Minecraft.getInstance().getSingleplayerServer() != null)
|
||||
.then(RequiredArgumentBuilder.<T, Integer>argument("computer_id", IntegerArgumentType.integer(0))
|
||||
.executes(c -> handleOpenComputerCommand(c.getSource(), sendError, c.getArgument("computer_id", Integer.class)))
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the {@link CommandComputerCraft#CLIENT_OPEN_FOLDER} command.
|
||||
*
|
||||
* @param context The command context.
|
||||
* @param sendError A function to send an error message.
|
||||
* @param id The computer's id.
|
||||
* @param <T> The type of the client-side command context.
|
||||
* @return {@code 1} if a folder was opened, {@code 0} otherwise.
|
||||
*/
|
||||
private static <T> int handleOpenComputerCommand(T context, BiConsumer<T, Component> sendError, int id) {
|
||||
var server = Minecraft.getInstance().getSingleplayerServer();
|
||||
if (server == null) {
|
||||
sendError.accept(context, Component.literal("Not on a single-player server"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
var file = new File(ServerContext.get(server).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) {
|
||||
sendError.accept(context, Component.literal("Computer's folder does not exist"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Util.getPlatform().openFile(file);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.*;
|
||||
|
||||
import static dan200.computercraft.shared.command.CommandUtils.isPlayer;
|
||||
@ -52,12 +52,6 @@ import static net.minecraft.commands.Commands.literal;
|
||||
public final class CommandComputerCraft {
|
||||
public static final UUID SYSTEM_UUID = new UUID(0, 0);
|
||||
|
||||
/**
|
||||
* The client-side command to open the folder. Ideally this would live under the main {@code computercraft}
|
||||
* namespace, but unfortunately that overrides commands, rather than merging them.
|
||||
*/
|
||||
public static final String CLIENT_OPEN_FOLDER = "computercraft-computer-folder";
|
||||
|
||||
private CommandComputerCraft() {
|
||||
}
|
||||
|
||||
@ -351,8 +345,8 @@ public final class CommandComputerCraft {
|
||||
}
|
||||
}
|
||||
|
||||
if (isPlayer(source) && UserLevel.isOwner(source)) {
|
||||
var linkPath = linkStorage(source, computerId);
|
||||
if (computer != null && isPlayer(source) && UserLevel.isOwner(source)) {
|
||||
var linkPath = linkStorage(source, computer);
|
||||
if (linkPath != null) out.append(" ").append(linkPath);
|
||||
}
|
||||
|
||||
@ -371,13 +365,13 @@ public final class CommandComputerCraft {
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Component linkStorage(CommandSourceStack source, int id) {
|
||||
var file = new File(ServerContext.get(source.getServer()).storageDir().toFile(), "computer/" + id);
|
||||
if (!file.isDirectory()) return null;
|
||||
private static @Nullable Component linkStorage(CommandSourceStack source, ServerComputer computer) {
|
||||
var file = ServerContext.get(source.getServer()).storageDir().resolve(computer.getFamily().getSaveFolder()).resolve(Integer.toString(computer.getID()));
|
||||
if (!Files.isDirectory(file)) return null;
|
||||
|
||||
return clientLink(
|
||||
return link(
|
||||
text("\u270E"),
|
||||
"/" + CLIENT_OPEN_FOLDER + " " + id,
|
||||
PlatformHelper.get().createOpenFolderAction(file),
|
||||
Component.translatable("commands.computercraft.dump.open_path")
|
||||
);
|
||||
}
|
||||
|
@ -52,10 +52,6 @@ public final class ChatHelpers {
|
||||
return link(component, new ClickEvent(ClickEvent.Action.RUN_COMMAND, command), toolTip);
|
||||
}
|
||||
|
||||
public static Component clientLink(MutableComponent component, String command, Component toolTip) {
|
||||
return link(component, new ClickEvent(ClickEvent.Action.RUN_COMMAND, command), toolTip);
|
||||
}
|
||||
|
||||
public static Component link(Component component, ClickEvent click, Component toolTip) {
|
||||
var style = component.getStyle();
|
||||
|
||||
|
@ -29,6 +29,21 @@ public enum ComputerFamily {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the save folder for this computer type.
|
||||
* <p>
|
||||
* Command computers are saved under a different namespace, to prevent people who have obtained a normal computer
|
||||
* with the same ID as a command computer (e.g. via creative mode, or a bug), having access to its files.
|
||||
*
|
||||
* @return The save folder for a
|
||||
*/
|
||||
public String getSaveFolder() {
|
||||
return switch (this) {
|
||||
case NORMAL, ADVANCED -> "computer";
|
||||
case COMMAND -> "command_computer";
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean checkCommandUsable(Player player) {
|
||||
var server = player.getServer();
|
||||
if (server == null || !server.isCommandBlockEnabled()) {
|
||||
|
@ -268,7 +268,7 @@ public class ServerComputer implements ComputerEnvironment, ComputerEvents.Recei
|
||||
@Override
|
||||
public final WritableMount createRootMount() {
|
||||
var capacity = storageCapacity <= 0 ? ConfigSpec.computerSpaceLimit.get() : storageCapacity;
|
||||
return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + computer.getID(), capacity);
|
||||
return ComputerCraftAPI.createSaveDirMount(level.getServer(), family.getSaveFolder() + "/" + computer.getID(), capacity);
|
||||
}
|
||||
|
||||
public static Properties properties(int computerID, ComputerFamily family) {
|
||||
|
@ -18,6 +18,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
@ -48,6 +49,7 @@ import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -353,4 +355,12 @@ public interface PlatformHelper {
|
||||
*/
|
||||
@Nullable
|
||||
IMedia getMedia(ItemStack stack);
|
||||
|
||||
/**
|
||||
* Construct a {@link ClickEvent} that opens a folder.
|
||||
*
|
||||
* @param path The folder to open.
|
||||
* @return The click event.
|
||||
*/
|
||||
ClickEvent createOpenFolderAction(Path path);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
@ -44,6 +45,7 @@ import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -154,6 +156,11 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClickEvent createOpenFolderAction(Path path) {
|
||||
throw new UnsupportedOperationException("Cannot create open folder ClickEvent");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainerTransfer.Slotted wrapContainer(Container container) {
|
||||
throw new UnsupportedOperationException("Cannot wrap container");
|
||||
|
@ -4,11 +4,15 @@
|
||||
|
||||
package dan200.computercraft.client;
|
||||
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.client.FabricComputerCraftAPIClient;
|
||||
import dan200.computercraft.client.model.ExtraModels;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import dan200.computercraft.shared.ComputerCraft;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.config.ConfigSpec;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
@ -22,6 +26,7 @@ import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlu
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.color.item.ItemTintSources;
|
||||
import net.minecraft.client.gui.screens.MenuScreens;
|
||||
@ -31,6 +36,8 @@ import net.minecraft.client.renderer.item.properties.conditional.ConditionalItem
|
||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperties;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
@ -75,9 +82,17 @@ public class ComputerCraftClient {
|
||||
}
|
||||
});
|
||||
|
||||
ClientCommandRegistrationCallback.EVENT.register(
|
||||
(dispatcher, registryAccess) -> ClientRegistry.registerClientCommands(dispatcher, FabricClientCommandSource::sendError)
|
||||
);
|
||||
// Register our open folder command
|
||||
ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) ->
|
||||
dispatcher.register(LiteralArgumentBuilder.<FabricClientCommandSource>literal(ComputerCraft.CLIENT_OPEN_FOLDER)
|
||||
.requires(x -> Minecraft.getInstance().getSingleplayerServer() != null)
|
||||
.then(RequiredArgumentBuilder.<FabricClientCommandSource, String>argument("path", StringArgumentType.string())
|
||||
.executes(c -> {
|
||||
var file = Path.of(c.getArgument("path", String.class));
|
||||
if (Files.isDirectory(file)) Util.getPlatform().openFile(file.toFile());
|
||||
return 0;
|
||||
})
|
||||
)));
|
||||
|
||||
((FabricConfigFile) ConfigSpec.clientSpec).load(FabricLoader.getInstance().getConfigDir().resolve(ComputerCraftAPI.MOD_ID + "-client.toml"));
|
||||
}
|
||||
|
@ -64,6 +64,12 @@ import java.util.function.BiFunction;
|
||||
public class ComputerCraft {
|
||||
private static final LevelResource SERVERCONFIG = new LevelResource("serverconfig");
|
||||
|
||||
/**
|
||||
* The client-side command to open a folder. Ideally this would live under the main {@code computercraft}
|
||||
* namespace, but unfortunately that overrides commands, rather than merging them.
|
||||
*/
|
||||
public static final String CLIENT_OPEN_FOLDER = "computercraft-open-folder";
|
||||
|
||||
public static void init() {
|
||||
for (var type : NetworkMessages.getServerbound()) registerPayloadType(PayloadTypeRegistry.playC2S(), type);
|
||||
for (var type : NetworkMessages.getClientbound()) registerPayloadType(PayloadTypeRegistry.playS2C(), type);
|
||||
|
@ -7,6 +7,7 @@ package dan200.computercraft.shared.platform;
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.api.media.IMedia;
|
||||
import dan200.computercraft.api.media.MediaLookup;
|
||||
@ -16,6 +17,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
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.config.ConfigFile;
|
||||
import dan200.computercraft.shared.network.container.ContainerData;
|
||||
import dan200.computercraft.shared.util.InventoryUtil;
|
||||
@ -37,6 +39,7 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
@ -64,6 +67,7 @@ import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -235,6 +239,14 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return MediaLookup.get().find(stack, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClickEvent createOpenFolderAction(Path path) {
|
||||
return new ClickEvent(
|
||||
ClickEvent.Action.RUN_COMMAND,
|
||||
"/" + ComputerCraft.CLIENT_OPEN_FOLDER + " " + StringArgumentType.escapeIfRequired(path.toAbsolutePath().toString())
|
||||
);
|
||||
}
|
||||
|
||||
private static final class RegistrationHelperImpl<T> implements RegistrationHelper<T> {
|
||||
private final Registry<T> registry;
|
||||
private final List<RegistryEntryImpl<? extends T>> entries = new ArrayList<>();
|
||||
|
@ -6,7 +6,6 @@ package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.sound.SpeakerSound;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
@ -67,7 +66,6 @@ public final class ForgeClientHooks {
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderInFrame(RenderItemInFrameEvent event) {
|
||||
var state = event.getItemFrameRenderState().getRenderData(ITEM_FRAME_STATE);
|
||||
@ -83,9 +81,4 @@ public final class ForgeClientHooks {
|
||||
if (!(event.getSound() instanceof SpeakerSound sound) || sound.getStream() == null) return;
|
||||
ClientHooks.onPlayStreaming(event.getEngine(), event.getChannel(), sound.getStream());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerClientCommands(RegisterClientCommandsEvent event) {
|
||||
ClientRegistry.registerClientCommands(event.getDispatcher(), CommandSourceStack::sendFailure);
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,9 @@ import dan200.computercraft.client.model.ExtraModels;
|
||||
import dan200.computercraft.client.render.ExtendedItemFrameRenderState;
|
||||
import dan200.computercraft.client.turtle.TurtleUpgradeModellers;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.entity.state.ItemFrameRenderState;
|
||||
import net.minecraft.client.renderer.entity.ItemFrameRenderer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.context.ContextKey;
|
||||
import net.minecraft.world.entity.decoration.ItemFrame;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.ModLoader;
|
||||
@ -98,7 +97,7 @@ public final class ForgeClientRegistry {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerRenderStateModifiers(RegisterRenderStateModifiersEvent event) {
|
||||
event.<ItemFrame, ItemFrameRenderState>registerEntityModifier(new TypeToken<>() {
|
||||
event.registerEntityModifier(new TypeToken<ItemFrameRenderer<?>>() {
|
||||
}, (e, s) -> {
|
||||
var data = s.getRenderData(ITEM_FRAME_STATE);
|
||||
if (data == null) s.setRenderData(ITEM_FRAME_STATE, data = new ExtendedItemFrameRenderState());
|
||||
|
@ -1,26 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.mixin.client;
|
||||
|
||||
import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.neoforged.neoforge.client.ClientCommandHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
/**
|
||||
* Allows triggering ComputerCraft's client commands from chat components events.
|
||||
*/
|
||||
@Mixin(ClientPacketListener.class)
|
||||
class ClientPacketListenerMixin {
|
||||
@Inject(method = "sendUnsignedCommand", at = @At("HEAD"), cancellable = true)
|
||||
void commandUnsigned(String command, CallbackInfoReturnable<Boolean> ci) {
|
||||
if (command.startsWith(CommandComputerCraft.CLIENT_OPEN_FOLDER) && ClientCommandHandler.runCommand(command)) {
|
||||
ci.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,6 @@
|
||||
"defaultRequire": 1
|
||||
},
|
||||
"client": [
|
||||
"BlockRenderDispatcherMixin",
|
||||
"ClientPacketListenerMixin"
|
||||
"BlockRenderDispatcherMixin"
|
||||
]
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
@ -65,6 +66,7 @@ import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@ -244,6 +246,11 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return stack.getCapability(MediaCapability.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClickEvent createOpenFolderAction(Path path) {
|
||||
return new ClickEvent(ClickEvent.Action.OPEN_FILE, path.toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
private record RegistrationHelperImpl<R>(DeferredRegister<R> registry) implements RegistrationHelper<R> {
|
||||
@Override
|
||||
public <T extends R> RegistryEntry<T> register(String name, Supplier<T> create) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user