diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e384f902..82119cd5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- Security Card + +### Changed + +- The permissions for a Security Card must be configured through the card itself, instead of via the Security Manager. +- The Security Card can be bound to other (currently online) players via its GUI. +- The binding of a Security Card can now be cleared. +- The Security Card tooltip and GUI now show whether the permission has been touched/changed in any way. + ### Fixed - Wireless Grid name not being correct in the GUI. diff --git a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/security/PlatformPermission.java b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/security/PlatformPermission.java index 67ca7333c..d93d77ef0 100644 --- a/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/security/PlatformPermission.java +++ b/refinedstorage2-platform-api/src/main/java/com/refinedmods/refinedstorage2/platform/api/security/PlatformPermission.java @@ -12,4 +12,6 @@ public interface PlatformPermission extends Permission { Component getDescription(); Component getOwnerName(); + + boolean isAllowedByDefault(); } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/grid/screen/AbstractGridScreen.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/grid/screen/AbstractGridScreen.java index 454afcd89..dd20dde26 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/grid/screen/AbstractGridScreen.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/grid/screen/AbstractGridScreen.java @@ -71,11 +71,9 @@ protected AbstractGridScreen(final T menu, } @Override - protected void init() { + protected void init(final int rows) { LOGGER.info("Initializing grid screen"); - super.init(); - if (searchField == null) { searchField = new GridSearchBoxWidget( font, diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/BuiltinPermission.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/BuiltinPermission.java index ba2f4ba90..bd2d820a6 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/BuiltinPermission.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/BuiltinPermission.java @@ -73,4 +73,9 @@ public Component getDescription() { public Component getOwnerName() { return ContentNames.MOD; } + + @Override + public boolean isAllowedByDefault() { + return true; + } } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardContainerMenu.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardContainerMenu.java index 4bbc6bdbd..40e71de9f 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardContainerMenu.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardContainerMenu.java @@ -1,57 +1,182 @@ package com.refinedmods.refinedstorage2.platform.common.security; import com.refinedmods.refinedstorage2.platform.api.PlatformApi; +import com.refinedmods.refinedstorage2.platform.api.security.PlatformPermission; +import com.refinedmods.refinedstorage2.platform.api.support.network.bounditem.SlotReference; +import com.refinedmods.refinedstorage2.platform.common.Platform; import com.refinedmods.refinedstorage2.platform.common.content.Menus; import com.refinedmods.refinedstorage2.platform.common.support.AbstractBaseContainerMenu; import com.refinedmods.refinedstorage2.platform.common.support.stretching.ScreenSizeListener; import java.util.ArrayList; import java.util.List; +import java.util.UUID; +import javax.annotation.Nullable; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.item.ItemStack; public class SecurityCardContainerMenu extends AbstractBaseContainerMenu implements ScreenSizeListener { private final Inventory playerInventory; - private final List permissions; + private final List permissions = new ArrayList<>(); + private final List players = new ArrayList<>(); + + @Nullable + private Player boundTo; public SecurityCardContainerMenu(final int syncId, final Inventory playerInventory, final FriendlyByteBuf buf) { super(Menus.INSTANCE.getSecurityCard(), syncId); this.playerInventory = playerInventory; - this.permissions = new ArrayList<>(); + this.disabledSlot = PlatformApi.INSTANCE.getSlotReference(buf).orElse(null); + final int amountOfPermissions = buf.readInt(); for (int i = 0; i < amountOfPermissions; ++i) { final ResourceLocation id = buf.readResourceLocation(); + final boolean allowed = buf.readBoolean(); + final boolean dirty = buf.readBoolean(); PlatformApi.INSTANCE.getPermissionRegistry().get(id).ifPresent(permission -> permissions.add(new Permission( id, permission.getName(), permission.getDescription(), - permission.getOwnerName() + permission.getOwnerName(), + allowed, + dirty ))); } + + if (buf.readBoolean()) { + this.boundTo = new Player(buf.readUUID(), buf.readUtf()); + } + + final int amountOfPlayers = buf.readInt(); + for (int i = 0; i < amountOfPlayers; ++i) { + final UUID id = buf.readUUID(); + final String name = buf.readUtf(); + players.add(new Player(id, name)); + } } - SecurityCardContainerMenu(final int syncId, final Inventory playerInventory) { + SecurityCardContainerMenu(final int syncId, final Inventory playerInventory, final SlotReference disabledSlot) { super(Menus.INSTANCE.getSecurityCard(), syncId); this.playerInventory = playerInventory; - this.permissions = new ArrayList<>(); + this.disabledSlot = disabledSlot; } List getPermissions() { return permissions; } + List getPlayers() { + return players; + } + + @Nullable + Player getBoundTo() { + return boundTo; + } + @Override public void initSlots(final int playerInventoryY) { resetSlots(); addPlayerInventory(playerInventory, 8, playerInventoryY); } - record Permission(ResourceLocation id, Component name, Component description, Component ownerName) { + public void setPermission(final ResourceLocation permissionId, final boolean allowed) { + if (disabledSlot == null) { + return; + } + disabledSlot.resolve(playerInventory.player).ifPresent(stack -> setPermission(permissionId, allowed, stack)); + } + + private void setPermission(final ResourceLocation permissionId, final boolean allowed, final ItemStack stack) { + if (stack.getItem() instanceof SecurityCardItem securityCardItem) { + securityCardItem.getModel(stack).setPermission(permissionId, allowed); + } + } + + public void resetPermissionServer(final ResourceLocation permissionId) { + if (disabledSlot == null) { + return; + } + disabledSlot.resolve(playerInventory.player).ifPresent(stack -> resetPermissionServer(permissionId, stack)); + } + + private void resetPermissionServer(final ResourceLocation permissionId, final ItemStack stack) { + if (stack.getItem() instanceof SecurityCardItem securityCardItem) { + securityCardItem.getModel(stack).resetPermission(permissionId); + } + } + + public void setBoundPlayer(final MinecraftServer server, @Nullable final UUID playerId) { + if (disabledSlot == null) { + return; + } + disabledSlot.resolve(playerInventory.player).ifPresent(stack -> setBoundPlayer(server, playerId, stack)); + } + + private void setBoundPlayer(final MinecraftServer server, @Nullable final UUID playerId, final ItemStack stack) { + if (stack.getItem() instanceof SecurityCardItem securityCardItem) { + final ServerPlayer player = playerId == null ? null : server.getPlayerList().getPlayer(playerId); + securityCardItem.getModel(stack).setBoundPlayer(player); + } + } + + Permission changePermission(final ResourceLocation permissionId, final boolean selected) { + Platform.INSTANCE.getClientToServerCommunications().sendSecurityCardPermission(permissionId, selected); + return updatePermissionLocally(permissionId, selected, true); + } + + Permission resetPermission(final ResourceLocation permissionId) { + final PlatformPermission permission = PlatformApi.INSTANCE.getPermissionRegistry() + .get(permissionId) + .orElseThrow(); + final boolean allowed = permission.isAllowedByDefault(); + Platform.INSTANCE.getClientToServerCommunications().sendSecurityCardResetPermission(permissionId); + return updatePermissionLocally(permissionId, allowed, false); + } + + private Permission updatePermissionLocally(final ResourceLocation permissionId, + final boolean allowed, + final boolean dirty) { + final Permission localPermission = permissions.stream().filter(p -> p.id().equals(permissionId)) + .findFirst() + .orElseThrow(); + final int index = permissions.indexOf(localPermission); + final Permission updatedLocalPermission = new Permission( + localPermission.id(), + localPermission.name(), + localPermission.description(), + localPermission.ownerName(), + allowed, + dirty + ); + permissions.set(index, updatedLocalPermission); + return updatedLocalPermission; + } + + void changeBoundPlayer(@Nullable final Player player) { + Platform.INSTANCE.getClientToServerCommunications().sendSecurityCardBoundPlayer( + player == null ? null : player.id() + ); + this.boundTo = player; + } + + record Permission(ResourceLocation id, + Component name, + Component description, + Component ownerName, + boolean allowed, + boolean dirty) { + } + + record Player(UUID id, String name) { } } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardExtendedMenuProvider.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardExtendedMenuProvider.java index b5a4a2cbb..393cfd486 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardExtendedMenuProvider.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardExtendedMenuProvider.java @@ -6,6 +6,7 @@ import com.refinedmods.refinedstorage2.platform.common.content.ContentNames; import com.refinedmods.refinedstorage2.platform.common.support.containermenu.ExtendedMenuProvider; +import java.util.Collections; import java.util.List; import javax.annotation.Nullable; @@ -19,19 +20,40 @@ class SecurityCardExtendedMenuProvider implements ExtendedMenuProvider { private final SlotReference slotReference; + private final SecurityCardModel model; - SecurityCardExtendedMenuProvider(final SlotReference slotReference) { + SecurityCardExtendedMenuProvider(final SlotReference slotReference, final SecurityCardModel model) { this.slotReference = slotReference; + this.model = model; } @Override public void writeScreenOpeningData(final ServerPlayer player, final FriendlyByteBuf buf) { PlatformApi.INSTANCE.writeSlotReference(slotReference, buf); + final List permissions = PlatformApi.INSTANCE.getPermissionRegistry().getAll(); buf.writeInt(permissions.size()); for (final PlatformPermission permission : permissions) { final ResourceLocation id = PlatformApi.INSTANCE.getPermissionRegistry().getId(permission).orElseThrow(); buf.writeResourceLocation(id); + buf.writeBoolean(model.isAllowed(permission)); + buf.writeBoolean(model.isDirty(permission)); + } + + final boolean bound = model.getBoundPlayerId() != null && model.getBoundPlayerName() != null; + buf.writeBoolean(bound); + if (bound) { + buf.writeUUID(model.getBoundPlayerId()); + buf.writeUtf(model.getBoundPlayerName()); + } + + final List players = player.getServer() == null + ? Collections.emptyList() + : player.getServer().getPlayerList().getPlayers(); + buf.writeInt(players.size()); + for (final ServerPlayer otherPlayer : players) { + buf.writeUUID(otherPlayer.getUUID()); + buf.writeUtf(otherPlayer.getGameProfile().getName()); } } @@ -43,6 +65,6 @@ public Component getDisplayName() { @Nullable @Override public AbstractContainerMenu createMenu(final int syncId, final Inventory inventory, final Player player) { - return new SecurityCardContainerMenu(syncId, inventory); + return new SecurityCardContainerMenu(syncId, inventory, slotReference); } } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardItem.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardItem.java index 5dd31e8a2..bc819ad2b 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardItem.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardItem.java @@ -10,6 +10,7 @@ import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; @@ -26,47 +27,54 @@ public class SecurityCardItem extends Item { private static final Component UNBOUND_HELP = createTranslation("item", "security_card.unbound.help"); private static final Component BOUND_HELP = createTranslation("item", "security_card.bound.help"); - private static final String TAG_BOUND_TO = "boundto"; - private static final String TAG_BOUND_TO_NAME = "boundtoname"; - public SecurityCardItem() { super(new Item.Properties().stacksTo(1)); } + SecurityCardModel getModel(final ItemStack stack) { + return new SecurityCardModel(stack); + } + + boolean isActive(final ItemStack stack) { + return SecurityCardModel.isActive(stack); + } + @Override public InteractionResultHolder use(final Level level, final Player player, final InteractionHand hand) { final ItemStack stack = player.getItemInHand(hand); if (player instanceof ServerPlayer serverPlayer) { - if (serverPlayer.isCrouching()) { - bindOrUnbind(serverPlayer, stack); - } else { - Platform.INSTANCE.getMenuOpener().openMenu(serverPlayer, new SecurityCardExtendedMenuProvider( - PlatformApi.INSTANCE.createInventorySlotReference(player, hand) - )); - } + use(hand, serverPlayer, stack); } return InteractionResultHolder.consume(stack); } - private void bindOrUnbind(final ServerPlayer player, final ItemStack stack) { + private void use(final InteractionHand hand, final ServerPlayer player, final ItemStack stack) { + if (player.isCrouching()) { + bindOrClear(player, stack); + return; + } + Platform.INSTANCE.getMenuOpener().openMenu(player, new SecurityCardExtendedMenuProvider( + PlatformApi.INSTANCE.createInventorySlotReference(player, hand), + getModel(stack) + )); + } + + private void bindOrClear(final ServerPlayer player, final ItemStack stack) { if (stack.hasTag()) { - unbind(player, stack); + clear(player, stack); } else { bind(player, stack); } } - private void unbind(final ServerPlayer player, final ItemStack stack) { + private void clear(final ServerPlayer player, final ItemStack stack) { stack.setTag(null); - player.sendSystemMessage(createTranslation( - "item", - "security_card.unbound" - )); + player.sendSystemMessage(createTranslation("item", "security_card.cleared")); } private void bind(final ServerPlayer player, final ItemStack stack) { - stack.getOrCreateTag().putUUID(TAG_BOUND_TO, player.getGameProfile().getId()); - stack.getOrCreateTag().putString(TAG_BOUND_TO_NAME, player.getGameProfile().getName()); + final SecurityCardModel model = getModel(stack); + model.setBoundPlayer(player); player.sendSystemMessage(createTranslation( "item", "security_card.bound", @@ -80,25 +88,36 @@ public void appendHoverText(final ItemStack stack, final List lines, final TooltipFlag flag) { super.appendHoverText(stack, level, lines, flag); - if (stack.getTag() == null) { + final SecurityCardModel model = getModel(stack); + + final String boundPlayerName = model.getBoundPlayerName(); + if (boundPlayerName == null) { lines.add(createTranslation("item", "security_card.unbound").withStyle(ChatFormatting.GRAY)); return; } - final Component boundToName = Component.literal(stack.getTag().getString(TAG_BOUND_TO_NAME)) - .withStyle(ChatFormatting.YELLOW); + lines.add(createTranslation( "item", "security_card.bound", - boundToName + Component.literal(boundPlayerName).withStyle(ChatFormatting.YELLOW) ).withStyle(ChatFormatting.GRAY)); + + PlatformApi.INSTANCE.getPermissionRegistry().getAll().forEach(permission -> { + final boolean allowed = model.isAllowed(permission); + final boolean dirty = model.isDirty(permission); + final Style style = Style.EMPTY + .withColor(allowed ? ChatFormatting.GREEN : ChatFormatting.RED) + .withItalic(dirty); + final Component permissionTooltip = Component.literal(allowed ? "✓ " : "❌ ") + .append(permission.getName()) + .append(dirty ? " (*)" : "") + .withStyle(style); + lines.add(permissionTooltip); + }); } @Override public Optional getTooltipImage(final ItemStack stack) { return Optional.of(new HelpTooltipComponent(isActive(stack) ? BOUND_HELP : UNBOUND_HELP)); } - - boolean isActive(final ItemStack stack) { - return stack.getTag() != null && stack.getTag().contains(TAG_BOUND_TO); - } } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardModel.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardModel.java new file mode 100644 index 000000000..5ef43ae9d --- /dev/null +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardModel.java @@ -0,0 +1,89 @@ +package com.refinedmods.refinedstorage2.platform.common.security; + +import com.refinedmods.refinedstorage2.platform.api.PlatformApi; +import com.refinedmods.refinedstorage2.platform.api.security.PlatformPermission; + +import java.util.UUID; +import javax.annotation.Nullable; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; + +class SecurityCardModel { + private static final String TAG_BOUND_PLAYER_ID = "bid"; + private static final String TAG_BOUND_PLAYER_NAME = "bname"; + private static final String TAG_PERMISSIONS = "permissions"; + + private final ItemStack stack; + + SecurityCardModel(final ItemStack stack) { + this.stack = stack; + } + + boolean isAllowed(final PlatformPermission permission) { + if (stack.getTag() != null && stack.getTag().contains(TAG_PERMISSIONS)) { + final ResourceLocation permissionId = PlatformApi.INSTANCE.getPermissionRegistry() + .getId(permission) + .orElseThrow(); + final CompoundTag permissionsTag = stack.getTag().getCompound(TAG_PERMISSIONS); + final boolean dirty = permissionsTag.contains(permissionId.toString()); + if (dirty) { + return permissionsTag.getBoolean(permissionId.toString()); + } + } + return permission.isAllowedByDefault(); + } + + boolean isDirty(final PlatformPermission permission) { + final ResourceLocation permissionId = PlatformApi.INSTANCE.getPermissionRegistry() + .getId(permission) + .orElseThrow(); + return stack.getTag() != null + && stack.getTag().contains(TAG_PERMISSIONS) + && stack.getTag().getCompound(TAG_PERMISSIONS).contains(permissionId.toString()); + } + + void setPermission(final ResourceLocation permissionId, final boolean allowed) { + final CompoundTag permissionsTag = stack.getOrCreateTagElement(TAG_PERMISSIONS); + permissionsTag.putBoolean(permissionId.toString(), allowed); + } + + void resetPermission(final ResourceLocation permissionId) { + final CompoundTag permissionsTag = stack.getOrCreateTagElement(TAG_PERMISSIONS); + permissionsTag.remove(permissionId.toString()); + } + + @Nullable + UUID getBoundPlayerId() { + return (stack.getTag() == null || !stack.getTag().contains(TAG_BOUND_PLAYER_ID)) + ? null + : stack.getTag().getUUID(TAG_BOUND_PLAYER_ID); + } + + @Nullable + String getBoundPlayerName() { + return (stack.getTag() == null || !stack.getTag().contains(TAG_BOUND_PLAYER_NAME)) + ? null + : stack.getTag().getString(TAG_BOUND_PLAYER_NAME); + } + + void setBoundPlayer(@Nullable final ServerPlayer player) { + final CompoundTag tag = stack.getOrCreateTag(); + if (player == null) { + tag.remove(TAG_BOUND_PLAYER_ID); + tag.remove(TAG_BOUND_PLAYER_NAME); + return; + } + tag.putUUID(TAG_BOUND_PLAYER_ID, player.getGameProfile().getId()); + tag.putString(TAG_BOUND_PLAYER_NAME, player.getGameProfile().getName()); + } + + static boolean isActive(final ItemStack stack) { + return stack.getTag() != null + && stack.getTag().contains(TAG_BOUND_PLAYER_ID) + && stack.getTag().contains(TAG_BOUND_PLAYER_NAME) + && stack.getTag().contains(TAG_PERMISSIONS); + } +} diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardScreen.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardScreen.java index db6ab736d..7669855ca 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardScreen.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/security/SecurityCardScreen.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import javax.annotation.Nullable; import net.minecraft.ChatFormatting; import net.minecraft.client.gui.GuiGraphics; @@ -22,13 +23,19 @@ public class SecurityCardScreen extends AbstractStretchingScreen { private static final ResourceLocation TEXTURE = createIdentifier("textures/gui/security_card.png"); - private static final int BINDING_RIGHT_PADDING = 6; - private static final int BINDING_WIDTH = 80; + private static final int BOUND_PLAYER_BUTTON_RIGHT_PADDING = 6; + private static final int BOUND_PLAYER_BUTTON_WIDTH = 80; private static final MutableComponent UNBOUND_TITLE = Component.literal("<") .append(createTranslation("gui", "security_card.unbound")) .append(">"); - private final List checkboxes = new ArrayList<>(); + private static final int RESET_BUTTON_WIDTH = 40; + private static final int RESET_BUTTON_RIGHT_PADDING = 16; + private static final Component RESET_TITLE = createTranslation("gui", "security_card.permission.reset"); + private static final Component MODIFIED_TITLE = createTranslation("gui", "security_card.permission.modified") + .withStyle(Style.EMPTY.withItalic(true).withColor(ChatFormatting.YELLOW)); + + private final List permissions = new ArrayList<>(); public SecurityCardScreen(final SecurityCardContainerMenu menu, final Inventory playerInventory, @@ -40,68 +47,148 @@ public SecurityCardScreen(final SecurityCardContainerMenu menu, } @Override - protected void init() { - super.init(); - - checkboxes.clear(); - final List permissions = getMenu().getPermissions(); - for (int i = 0; i < permissions.size(); ++i) { - final CustomCheckboxWidget checkbox = createPermissionCheckbox(permissions.get(i), i); - addWidget(checkbox); - checkboxes.add(checkbox); + protected void init(final int rows) { + permissions.clear(); + final List menuPermissions = getMenu().getPermissions(); + for (int i = 0; i < menuPermissions.size(); ++i) { + final Permission permission = createPermission(menuPermissions.get(i), i, rows); + addWidget(permission.checkbox); + addWidget(permission.resetButton); + permissions.add(permission); } - updateScrollbar(checkboxes.size()); - - final Button playerButton = Button.builder(UNBOUND_TITLE, btn -> toggleBoundPlayer()) - .pos(leftPos + imageWidth - BINDING_RIGHT_PADDING - BINDING_WIDTH, topPos + 4) - .size(BINDING_WIDTH, 14) + updateScrollbar(permissions.size()); + + final Component boundToText = menu.getBoundTo() == null + ? UNBOUND_TITLE + : Component.literal(menu.getBoundTo().name()); + final Button boundPlayerButton = Button.builder(boundToText, this::toggleBoundPlayer) + .pos(leftPos + imageWidth - BOUND_PLAYER_BUTTON_RIGHT_PADDING - BOUND_PLAYER_BUTTON_WIDTH, topPos + 4) + .size(BOUND_PLAYER_BUTTON_WIDTH, 14) .build(); - addRenderableWidget(playerButton); + addRenderableWidget(boundPlayerButton); } - private CustomCheckboxWidget createPermissionCheckbox( - final SecurityCardContainerMenu.Permission permission, - final int index + private Permission createPermission( + final SecurityCardContainerMenu.Permission menuPermission, + final int index, + final int rows ) { + final int y = getPermissionY(index); + final boolean visible = isPermissionVisible(rows, y); + final CustomCheckboxWidget checkbox = createPermissionCheckbox(menuPermission, y, visible); + final Button resetButton = createPermissionResetButton(menuPermission, checkbox, y, visible); + checkbox.setOnPressed((c, selected) -> updatePermission(menuPermission, resetButton, c, selected)); + return new Permission(checkbox, resetButton); + } + + private CustomCheckboxWidget createPermissionCheckbox(final SecurityCardContainerMenu.Permission menuPermission, + final int y, + final boolean visible) { final CustomCheckboxWidget checkbox = new CustomCheckboxWidget( leftPos + 10, - getPermissionCheckboxY(index), - permission.name(), + y, + getPermissionName(menuPermission), font, - false + menuPermission.allowed() ); - checkbox.setTooltip(getPermissionTooltip(permission)); + checkbox.visible = visible; + checkbox.setTooltip(getPermissionTooltip(menuPermission)); return checkbox; } - private Tooltip getPermissionTooltip(final SecurityCardContainerMenu.Permission permission) { - final MutableComponent ownerName = permission.ownerName().copy().withStyle( + private void updatePermission(final SecurityCardContainerMenu.Permission menuPermission, + final Button resetButton, + final CustomCheckboxWidget checkbox, + final boolean allowed) { + updateCheckboxAndResetButton(checkbox, resetButton, menu.changePermission(menuPermission.id(), allowed)); + } + + private Tooltip getPermissionTooltip(final SecurityCardContainerMenu.Permission menuPermission) { + final MutableComponent ownerName = menuPermission.ownerName().copy().withStyle( Style.EMPTY.withItalic(true).withColor(ChatFormatting.GRAY) ); - return Tooltip.create(permission.description().copy().append("\n").append(ownerName)); + final MutableComponent tooltip = menuPermission.description().copy().append("\n").append(ownerName); + return Tooltip.create(menuPermission.dirty() ? tooltip.append("\n").append(MODIFIED_TITLE) : tooltip); } - private int getPermissionCheckboxY(final int index) { + private Button createPermissionResetButton(final SecurityCardContainerMenu.Permission menuPermission, + final CustomCheckboxWidget checkbox, + final int y, + final boolean visible) { + final Button resetButton = Button.builder(RESET_TITLE, btn -> resetPermission(menuPermission, checkbox, btn)) + .pos(leftPos + imageWidth - RESET_BUTTON_RIGHT_PADDING - RESET_BUTTON_WIDTH - 11, y) + .size(RESET_BUTTON_WIDTH, 16) + .build(); + resetButton.visible = visible; + resetButton.active = menuPermission.dirty(); + return resetButton; + } + + private void resetPermission(final SecurityCardContainerMenu.Permission menuPermission, + final CustomCheckboxWidget checkbox, + final Button resetButton) { + updateCheckboxAndResetButton(checkbox, resetButton, menu.resetPermission(menuPermission.id())); + } + + private void updateCheckboxAndResetButton(final CustomCheckboxWidget checkbox, + final Button resetButton, + final SecurityCardContainerMenu.Permission menuPermission) { + checkbox.setMessage(getPermissionName(menuPermission)); + checkbox.setTooltip(getPermissionTooltip(menuPermission)); + checkbox.setSelected(menuPermission.allowed()); + resetButton.active = menuPermission.dirty(); + } + + private Component getPermissionName(final SecurityCardContainerMenu.Permission menuPermission) { + if (!menuPermission.dirty()) { + return menuPermission.name(); + } + return menuPermission.name().copy().append(" (*)").setStyle(Style.EMPTY.withItalic(true)); + } + + private int getPermissionY(final int index) { return topPos + 19 + (index * ROW_SIZE) + 3; } + private boolean isPermissionVisible(final int rows, final int y) { + return y >= (topPos + 19 - ROW_SIZE) && y < (topPos + 19 + (rows * ROW_SIZE)); + } + @Override protected int getScrollPanePadding() { return 4; } - private void toggleBoundPlayer() { - // todo! + private void toggleBoundPlayer(final Button button) { + if (menu.getPlayers().isEmpty()) { + return; + } + if (menu.getBoundTo() == null) { + setBoundPlayer(button, menu.getPlayers().get(0)); + return; + } + final int nextIndex = menu.getPlayers().indexOf(menu.getBoundTo()) + 1; + if (nextIndex >= menu.getPlayers().size()) { + setBoundPlayer(button, null); + } else { + setBoundPlayer(button, menu.getPlayers().get(nextIndex)); + } + } + + private void setBoundPlayer(final Button button, @Nullable final SecurityCardContainerMenu.Player player) { + menu.changeBoundPlayer(player); + button.setMessage(player == null ? UNBOUND_TITLE : Component.literal(player.name())); } @Override protected void scrollbarChanged(final int rows) { final int offset = getScrollbarOffset(); - for (int i = 0; i < checkboxes.size(); ++i) { - final CustomCheckboxWidget checkbox = checkboxes.get(i); - final int y = getPermissionCheckboxY(i) - offset; - checkbox.visible = y >= (topPos + 19 - ROW_SIZE) && y < (topPos + 19 + (rows * ROW_SIZE)); - checkbox.setY(y); + for (int i = 0; i < permissions.size(); ++i) { + final Permission permission = permissions.get(i); + final int y = getPermissionY(i) - offset; + final boolean visible = isPermissionVisible(rows, y); + permission.setY(y); + permission.setVisible(visible); } } @@ -113,8 +200,8 @@ protected void renderRows(final GuiGraphics graphics, final int rows, final int mouseX, final int mouseY) { - for (final CustomCheckboxWidget checkbox : checkboxes) { - checkbox.render(graphics, mouseX, mouseY, 0); + for (final Permission permission : permissions) { + permission.render(graphics, mouseX, mouseY); } } @@ -145,4 +232,21 @@ protected int getBottomV() { protected ResourceLocation getTexture() { return TEXTURE; } + + private record Permission(CustomCheckboxWidget checkbox, Button resetButton) { + private void setY(final int y) { + checkbox.setY(y); + resetButton.setY(y); + } + + private void setVisible(final boolean visible) { + checkbox.visible = visible; + resetButton.visible = visible; + } + + private void render(final GuiGraphics graphics, final int mouseX, final int mouseY) { + checkbox.render(graphics, mouseX, mouseY, 0); + resetButton.render(graphics, mouseX, mouseY, 0); + } + } } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/ClientToServerCommunications.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/ClientToServerCommunications.java index 5aeca9c19..c1d47204b 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/ClientToServerCommunications.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/ClientToServerCommunications.java @@ -10,6 +10,9 @@ import java.util.List; import java.util.UUID; +import javax.annotation.Nullable; + +import net.minecraft.resources.ResourceLocation; public interface ClientToServerCommunications { void sendGridExtract(PlatformResourceKey resource, GridExtractMode mode, boolean cursor); @@ -35,4 +38,10 @@ public interface ClientToServerCommunications { void sendSingleAmountChange(double amount); void sendUseNetworkBoundItem(SlotReference slotReference); + + void sendSecurityCardPermission(ResourceLocation permissionId, boolean allowed); + + void sendSecurityCardResetPermission(ResourceLocation permissionId); + + void sendSecurityCardBoundPlayer(@Nullable UUID playerId); } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/packet/PacketIds.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/packet/PacketIds.java index bf476c452..1d3eea67a 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/packet/PacketIds.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/packet/PacketIds.java @@ -26,6 +26,11 @@ public final class PacketIds { public static final ResourceLocation SINGLE_AMOUNT_CHANGE = createIdentifier("detector_amount_change"); public static final ResourceLocation USE_NETWORK_BOUND_ITEM = createIdentifier("use_network_bound_item"); public static final ResourceLocation NETWORK_TRANSMITTER_STATUS = createIdentifier("network_transmitter_status"); + public static final ResourceLocation SECURITY_CARD_PERMISSION = createIdentifier("security_card_permission"); + public static final ResourceLocation SECURITY_CARD_RESET_PERMISSION = createIdentifier( + "security_card_reset_permission" + ); + public static final ResourceLocation SECURITY_CARD_BOUND_PLAYER = createIdentifier("security_card_bound_player"); private PacketIds() { } diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/stretching/AbstractStretchingScreen.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/stretching/AbstractStretchingScreen.java index eac896eea..8c73972d9 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/stretching/AbstractStretchingScreen.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/stretching/AbstractStretchingScreen.java @@ -41,11 +41,17 @@ protected void init() { super.init(); - addSideButton(new ScreenSizeSideButtonWidget(this)); - this.scrollbar = new ScrollbarWidget(leftPos + 174, topPos + 20, 12, (visibleRows * ROW_SIZE) - 2); this.scrollbar.setListener(offset -> scrollbarChanged(visibleRows)); addWidget(scrollbar); + + init(visibleRows); + + addSideButton(new ScreenSizeSideButtonWidget(this)); + } + + protected void init(final int rows) { + // no op } protected final int getScrollbarOffset() { diff --git a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/widget/CustomCheckboxWidget.java b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/widget/CustomCheckboxWidget.java index 3912a253f..ed1032afb 100644 --- a/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/widget/CustomCheckboxWidget.java +++ b/refinedstorage2-platform-common/src/main/java/com/refinedmods/refinedstorage2/platform/common/support/widget/CustomCheckboxWidget.java @@ -1,5 +1,7 @@ package com.refinedmods.refinedstorage2.platform.common.support.widget; +import javax.annotation.Nullable; + import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -25,6 +27,8 @@ public class CustomCheckboxWidget extends AbstractButton { private static final int BOX_SIZE = 9 + 8; + @Nullable + private OnPressed onPressed; private boolean selected; public CustomCheckboxWidget(final int x, @@ -36,18 +40,25 @@ public CustomCheckboxWidget(final int x, this.selected = selected; } + public void setOnPressed(@Nullable final OnPressed onPressed) { + this.onPressed = onPressed; + } + public void onPress() { this.selected = !this.selected; + if (onPressed != null) { + onPressed.onPressed(this, selected); + } } - public boolean selected() { - return this.selected; + public void setSelected(final boolean selected) { + this.selected = selected; } public void updateWidgetNarration(final NarrationElementOutput output) { - output.add(NarratedElementType.TITLE, this.createNarrationMessage()); - if (this.active) { - if (this.isFocused()) { + output.add(NarratedElementType.TITLE, createNarrationMessage()); + if (active) { + if (isFocused()) { output.add(NarratedElementType.USAGE, Component.translatable("narration.checkbox.usage.focused")); } else { output.add(NarratedElementType.USAGE, Component.translatable("narration.checkbox.usage.hovered")); @@ -73,4 +84,9 @@ public void renderWidget(final GuiGraphics graphics, final int mouseX, final int graphics.setColor(1.0F, 1.0F, 1.0F, 1.0F); graphics.drawString(font, getMessage(), x, y, 4210752, false); } + + @FunctionalInterface + public interface OnPressed { + void onPressed(CustomCheckboxWidget checkbox, boolean selected); + } } diff --git a/refinedstorage2-platform-common/src/main/resources/assets/refinedstorage2/lang/en_us.json b/refinedstorage2-platform-common/src/main/resources/assets/refinedstorage2/lang/en_us.json index 943ade269..a1a39448a 100644 --- a/refinedstorage2-platform-common/src/main/resources/assets/refinedstorage2/lang/en_us.json +++ b/refinedstorage2-platform-common/src/main/resources/assets/refinedstorage2/lang/en_us.json @@ -143,6 +143,8 @@ "gui.refinedstorage2.network_transmitter.status.transmitting": "%d block(s)", "gui.refinedstorage2.network_transmitter.status.receiver_unreachable": "Unreachable", "gui.refinedstorage2.security_card.unbound": "Unbound", + "gui.refinedstorage2.security_card.permission.reset": "Reset", + "gui.refinedstorage2.security_card.permission.modified": "Modified", "item.refinedstorage2.controller.help": "Provides the storage network with energy. Multiple are allowed in a single storage network.", "item.refinedstorage2.creative_controller.help": "Provides the storage network with an infinite source of energy.", "item.refinedstorage2.disk_drive.help": "Accepts storage disks to provide the storage network with storage space.", @@ -221,6 +223,7 @@ "item.refinedstorage2.network_card.bound_help": "Insert into a Network Transmitter. Use while crouching to clear binding.", "item.refinedstorage2.network_card.bound": "Bound to %d, %d, %d in %s.", "item.refinedstorage2.security_card": "Security Card", + "item.refinedstorage2.security_card.cleared": "Cleared binding.", "item.refinedstorage2.security_card.unbound": "Unbound.", "item.refinedstorage2.security_card.unbound.help": "Use while crouching to bind to the current player. Right click to configure.", "item.refinedstorage2.security_card.bound": "Bound to %s.", diff --git a/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/ModInitializerImpl.java b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/ModInitializerImpl.java index 31b8aec40..0676e4244 100644 --- a/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/ModInitializerImpl.java +++ b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/ModInitializerImpl.java @@ -39,6 +39,9 @@ import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.ResourceFilterSlotChangePacket; import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.ResourceSlotAmountChangePacket; import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.ResourceSlotChangePacket; +import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.SecurityCardBoundPlayerPacket; +import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.SecurityCardPermissionPacket; +import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.SecurityCardResetPermissionPacket; import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.SingleAmountChangePacket; import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.StorageInfoRequestPacket; import com.refinedmods.refinedstorage2.platform.fabric.packet.c2s.UseNetworkBoundItemPacket; @@ -314,6 +317,18 @@ private void registerPackets() { ); ServerPlayNetworking.registerGlobalReceiver(PacketIds.SINGLE_AMOUNT_CHANGE, new SingleAmountChangePacket()); ServerPlayNetworking.registerGlobalReceiver(PacketIds.USE_NETWORK_BOUND_ITEM, new UseNetworkBoundItemPacket()); + ServerPlayNetworking.registerGlobalReceiver( + PacketIds.SECURITY_CARD_PERMISSION, + new SecurityCardPermissionPacket() + ); + ServerPlayNetworking.registerGlobalReceiver( + PacketIds.SECURITY_CARD_RESET_PERMISSION, + new SecurityCardResetPermissionPacket() + ); + ServerPlayNetworking.registerGlobalReceiver( + PacketIds.SECURITY_CARD_BOUND_PLAYER, + new SecurityCardBoundPlayerPacket() + ); } private void registerSidedHandlers() { diff --git a/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/ClientToServerCommunicationsImpl.java b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/ClientToServerCommunicationsImpl.java index 064d16ddb..d61df1fc2 100644 --- a/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/ClientToServerCommunicationsImpl.java +++ b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/ClientToServerCommunicationsImpl.java @@ -15,6 +15,7 @@ import java.util.List; import java.util.UUID; import java.util.function.Consumer; +import javax.annotation.Nullable; import io.netty.buffer.Unpooled; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; @@ -129,6 +130,32 @@ public void sendUseNetworkBoundItem(final SlotReference slotReference) { ); } + @Override + public void sendSecurityCardPermission(final ResourceLocation permissionId, final boolean allowed) { + sendToServer( + PacketIds.SECURITY_CARD_PERMISSION, + buf -> { + buf.writeResourceLocation(permissionId); + buf.writeBoolean(allowed); + } + ); + } + + @Override + public void sendSecurityCardResetPermission(final ResourceLocation permissionId) { + sendToServer(PacketIds.SECURITY_CARD_RESET_PERMISSION, buf -> buf.writeResourceLocation(permissionId)); + } + + @Override + public void sendSecurityCardBoundPlayer(@Nullable final UUID playerId) { + sendToServer(PacketIds.SECURITY_CARD_BOUND_PLAYER, buf -> { + buf.writeBoolean(playerId != null); + if (playerId != null) { + buf.writeUUID(playerId); + } + }); + } + private static void sendToServer(final ResourceLocation id, final Consumer bufConsumer) { final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); bufConsumer.accept(buf); diff --git a/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardBoundPlayerPacket.java b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardBoundPlayerPacket.java new file mode 100644 index 000000000..ccca1783c --- /dev/null +++ b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardBoundPlayerPacket.java @@ -0,0 +1,27 @@ +package com.refinedmods.refinedstorage2.platform.fabric.packet.c2s; + +import com.refinedmods.refinedstorage2.platform.common.security.SecurityCardContainerMenu; + +import java.util.UUID; + +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +public class SecurityCardBoundPlayerPacket implements ServerPlayNetworking.PlayChannelHandler { + @Override + public void receive(final MinecraftServer server, + final ServerPlayer player, + final ServerGamePacketListenerImpl handler, + final FriendlyByteBuf buf, + final PacketSender responseSender) { + final boolean hasPlayer = buf.readBoolean(); + final UUID playerId = hasPlayer ? buf.readUUID() : null; + if (player.containerMenu instanceof SecurityCardContainerMenu securityCardContainerMenu) { + server.execute(() -> securityCardContainerMenu.setBoundPlayer(server, playerId)); + } + } +} diff --git a/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardPermissionPacket.java b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardPermissionPacket.java new file mode 100644 index 000000000..9c392195b --- /dev/null +++ b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardPermissionPacket.java @@ -0,0 +1,26 @@ +package com.refinedmods.refinedstorage2.platform.fabric.packet.c2s; + +import com.refinedmods.refinedstorage2.platform.common.security.SecurityCardContainerMenu; + +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +public class SecurityCardPermissionPacket implements ServerPlayNetworking.PlayChannelHandler { + @Override + public void receive(final MinecraftServer server, + final ServerPlayer player, + final ServerGamePacketListenerImpl handler, + final FriendlyByteBuf buf, + final PacketSender responseSender) { + final ResourceLocation permissionId = buf.readResourceLocation(); + final boolean allowed = buf.readBoolean(); + if (player.containerMenu instanceof SecurityCardContainerMenu securityCardContainerMenu) { + server.execute(() -> securityCardContainerMenu.setPermission(permissionId, allowed)); + } + } +} diff --git a/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardResetPermissionPacket.java b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardResetPermissionPacket.java new file mode 100644 index 000000000..16e54f230 --- /dev/null +++ b/refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/packet/c2s/SecurityCardResetPermissionPacket.java @@ -0,0 +1,25 @@ +package com.refinedmods.refinedstorage2.platform.fabric.packet.c2s; + +import com.refinedmods.refinedstorage2.platform.common.security.SecurityCardContainerMenu; + +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerGamePacketListenerImpl; + +public class SecurityCardResetPermissionPacket implements ServerPlayNetworking.PlayChannelHandler { + @Override + public void receive(final MinecraftServer server, + final ServerPlayer player, + final ServerGamePacketListenerImpl handler, + final FriendlyByteBuf buf, + final PacketSender responseSender) { + final ResourceLocation permissionId = buf.readResourceLocation(); + if (player.containerMenu instanceof SecurityCardContainerMenu securityCardContainerMenu) { + server.execute(() -> securityCardContainerMenu.resetPermissionServer(permissionId)); + } + } +}