diff --git a/gradle.properties b/gradle.properties index c8094f9..4730d8e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,7 +11,7 @@ loader_version=0.16.0 fabric_version=0.102.1+1.21.1 # Mod Properties -mod_version=3.1.2 +mod_version=3.2 maven_group=systems.brn archives_base_name=Serverstorage diff --git a/src/main/java/systems/brn/serverstorage/ServerStorage.java b/src/main/java/systems/brn/serverstorage/ServerStorage.java index 925b138..13721a1 100644 --- a/src/main/java/systems/brn/serverstorage/ServerStorage.java +++ b/src/main/java/systems/brn/serverstorage/ServerStorage.java @@ -2,6 +2,7 @@ package systems.brn.serverstorage; import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.player.UseItemCallback; import net.fabricmc.fabric.api.gamerule.v1.GameRuleFactory; import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry; import net.minecraft.block.entity.BlockEntityType; @@ -11,16 +12,19 @@ import net.minecraft.util.Identifier; import net.minecraft.world.GameRules; import systems.brn.serverstorage.blockentities.HardDriveContainerBlockEntity; import systems.brn.serverstorage.blockentities.InventoryInterfaceBlockEntity; +import systems.brn.serverstorage.blockentities.RadioInterfaceBlockEntity; import systems.brn.serverstorage.blockentities.StorageInterfaceBlockEntity; -import systems.brn.serverstorage.blocks.BusConnectorBlock; -import systems.brn.serverstorage.blocks.HardDriveContainerBlock; -import systems.brn.serverstorage.blocks.InventoryInterfaceBlock; -import systems.brn.serverstorage.blocks.StorageInterfaceBlock; +import systems.brn.serverstorage.blocks.*; import systems.brn.serverstorage.items.HardDriveItem; import systems.brn.serverstorage.items.SimpleBlockItem; import systems.brn.serverstorage.items.SimpleItem; +import systems.brn.serverstorage.items.WirelessTerminalItem; +import systems.brn.serverstorage.lib.Antenna; +import systems.brn.serverstorage.lib.EventHandler; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; public class ServerStorage implements ModInitializer { @@ -30,6 +34,8 @@ public class ServerStorage implements ModInitializer { public static final String MOD_ID = "serverstorage"; + public static final String WIRELESS_TERMINAL_ID = "wireless_terminal"; + public static final String BUS_CONNECTOR_MODEL_ID = "bus_connector"; public static BusConnectorBlock BUS_CONNECTOR_BLOCK; @@ -37,6 +43,10 @@ public class ServerStorage implements ModInitializer { public static BlockEntityType HARD_DRIVE_CONTAINER_BLOCK_ENTITY; public static HardDriveContainerBlock HARD_DRIVE_CONTAINER_BLOCK; + public static final String RADIO_INTERFACE_BLOCK_MODEL_ID = "radio_interface"; + public static BlockEntityType RADIO_INTERFACE_BLOCK_ENTITY; + public static RadioInterfaceBlock RADIO_INTERFACE_BLOCK; + public static final String STORAGE_MODEL_ID = "storage"; public static StorageInterfaceBlock STORAGE_INTERFACE_BLOCK; public static BlockEntityType STORAGE_INTERFACE_BLOCK_ENTITY; @@ -60,6 +70,10 @@ public class ServerStorage implements ModInitializer { public static List PLATTERS; public static List DRIVES; public static List HEADS; + public static List ANTENNA_LIST = new ArrayList<>(); + public static final HashMap ANTENNA_RANGES = new HashMap<>(); + + public static Item WIRELESS_TERMINAL; public static Identifier id(String path) { @@ -80,6 +94,9 @@ public class ServerStorage implements ModInitializer { InventoryInterfaceBlock.register(); SimpleBlockItem.register(INVENTORY_INTERFACE_BLOCK); + RadioInterfaceBlock.register(); + SimpleBlockItem.register(RADIO_INTERFACE_BLOCK); + MATERIALS = SimpleItem.register("material", materialList, false, ItemGroups.INGREDIENTS); MODULES = SimpleItem.register("module", moduleList, false, ItemGroups.INGREDIENTS); @@ -88,6 +105,12 @@ public class ServerStorage implements ModInitializer { DRIVES = HardDriveItem.register(tiers); + ANTENNA_LIST = Antenna.register(tiers); + + WIRELESS_TERMINAL = WirelessTerminalItem.register(); + + UseItemCallback.EVENT.register(EventHandler::onItemUse); + systems.brn.serverstorage.lib.ItemGroups.register(); PolymerResourcePackUtils.addModAssets(MOD_ID); PolymerResourcePackUtils.markAsRequired(); diff --git a/src/main/java/systems/brn/serverstorage/blockentities/RadioInterfaceBlockEntity.java b/src/main/java/systems/brn/serverstorage/blockentities/RadioInterfaceBlockEntity.java new file mode 100644 index 0000000..4ad1da6 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/blockentities/RadioInterfaceBlockEntity.java @@ -0,0 +1,129 @@ +package systems.brn.serverstorage.blockentities; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventories; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtList; +import net.minecraft.registry.RegistryWrapper; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.math.BlockPos; +import systems.brn.serverstorage.lib.Session; +import systems.brn.serverstorage.screenhandlers.RadioInterfaceScreenHandler; + +import java.util.ArrayList; +import java.util.UUID; + +import static systems.brn.serverstorage.ServerStorage.ANTENNA_RANGES; +import static systems.brn.serverstorage.ServerStorage.RADIO_INTERFACE_BLOCK_ENTITY; + +public class RadioInterfaceBlockEntity extends LootableContainerBlockEntity { + public DefaultedList inventory; + public int antennaRange = 0; + public final ArrayList sessions = new ArrayList<>(); + public static final int INVENTORY_SIZE = 1; + + public RadioInterfaceBlockEntity(BlockPos pos, BlockState state) { + super(RADIO_INTERFACE_BLOCK_ENTITY, pos, state); + this.inventory = DefaultedList.ofSize(INVENTORY_SIZE, ItemStack.EMPTY); + updateAntenna(); + } + + public boolean isSessionAuthorized(UUID sessionKey, UUID playerUUID) { + for (Session session : sessions) { + if (session.sessionKey().equals(sessionKey) && session.playerUUID().equals(playerUUID)) { + return true; + } + } + return false; + } + + public void authorizeSession(UUID sessionKey, ServerPlayerEntity player) { + if (!isSessionAuthorized(sessionKey, player.getUuid())) { + sessions.add(new Session(sessionKey, player.getUuid())); + markDirty(); + } + } + + public void deAuthorizeSession(UUID sessionKey, UUID playerUUID) { + for (Session session : sessions) { + if (session.sessionKey().equals(sessionKey) && session.playerUUID().equals(playerUUID)) { + sessions.remove(session); + markDirty(); + break; + } + } + } + + public void updateAntenna() { + ItemStack stack = inventory.getFirst(); + if (!stack.isEmpty()) { + Item antennaItem = stack.getItem(); + antennaRange = ANTENNA_RANGES.getOrDefault(antennaItem, 0); + } + } + + @Override + protected Text getContainerName() { + return Text.translatable("block.serverstorage.radio_interface"); + } + + @Override + protected DefaultedList getHeldStacks() { + return inventory; + } + + @Override + protected void setHeldStacks(DefaultedList inventory) { + this.inventory = inventory; + } + + @Override + protected ScreenHandler createScreenHandler(int syncId, PlayerInventory playerInventory) { + return new RadioInterfaceScreenHandler(syncId, playerInventory, this); + } + + @Override + public int size() { + return INVENTORY_SIZE; + } + + @Override + protected void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + super.readNbt(nbt, registryLookup); + this.inventory = DefaultedList.ofSize(this.size(), ItemStack.EMPTY); + this.antennaRange = nbt.getInt("AntennaRange"); + if (!this.readLootTable(nbt)) { + Inventories.readNbt(nbt, this.inventory, registryLookup); + } + updateAntenna(); + // Deserialize sessions list + this.sessions.clear(); + NbtList sessionsNbtList = nbt.getList("Sessions", 10); // 10 = NbtCompound type + for (int i = 0; i < sessionsNbtList.size(); i++) { + NbtCompound sessionNbt = sessionsNbtList.getCompound(i); + this.sessions.add(Session.fromNbt(sessionNbt)); + } + } + + @Override + protected void writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { + super.writeNbt(nbt, registryLookup); + nbt.putInt("AntennaRange", antennaRange); + if (!this.writeLootTable(nbt)) { + Inventories.writeNbt(nbt, this.inventory, registryLookup); + } + // Serialize sessions list + NbtList sessionsNbtList = new NbtList(); + for (Session session : sessions) { + sessionsNbtList.add(session.toNbt()); + } + nbt.put("Sessions", sessionsNbtList); + } +} diff --git a/src/main/java/systems/brn/serverstorage/blockentities/StorageInterfaceBlockEntity.java b/src/main/java/systems/brn/serverstorage/blockentities/StorageInterfaceBlockEntity.java index 587d90f..8a6de5a 100644 --- a/src/main/java/systems/brn/serverstorage/blockentities/StorageInterfaceBlockEntity.java +++ b/src/main/java/systems/brn/serverstorage/blockentities/StorageInterfaceBlockEntity.java @@ -37,6 +37,12 @@ public class StorageInterfaceBlockEntity extends BlockEntity { } } + public void enforceNetwork() { + if (this.network == null) { + this.network = new StorageNetwork(world, this.pos, sortAlphabetically, searchString); + } + } + public void refreshTerminals() { reindexDrives(); this.network.updateDisplays(); diff --git a/src/main/java/systems/brn/serverstorage/blocks/RadioInterfaceBlock.java b/src/main/java/systems/brn/serverstorage/blocks/RadioInterfaceBlock.java new file mode 100644 index 0000000..f9fbfab --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/blocks/RadioInterfaceBlock.java @@ -0,0 +1,151 @@ +package systems.brn.serverstorage.blocks; + +import eu.pb4.polymer.blocks.api.BlockModelType; +import eu.pb4.polymer.blocks.api.PolymerBlockModel; +import eu.pb4.polymer.blocks.api.PolymerBlockResourceUtils; +import eu.pb4.polymer.blocks.api.PolymerTexturedBlock; +import eu.pb4.polymer.core.api.block.PolymerBlockUtils; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.block.*; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.DirectionProperty; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; +import systems.brn.serverstorage.blockentities.RadioInterfaceBlockEntity; +import systems.brn.serverstorage.items.WirelessTerminalItem; +import systems.brn.serverstorage.lib.SessionStorageClass; +import systems.brn.serverstorage.lib.WirelessTerminalComponents; +import systems.brn.serverstorage.screens.RadioBlockPlayerMangementScreen; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static systems.brn.serverstorage.ServerStorage.*; +import static systems.brn.serverstorage.lib.Util.removePosition; + +public class RadioInterfaceBlock extends ConnectedBlock implements PolymerTexturedBlock, BlockEntityProvider { + final Identifier identifier; + public static final DirectionProperty FACING = FacingBlock.FACING; + private final BlockState polymerBlockState; + + public RadioInterfaceBlock(Settings settings, Identifier identifier) { + super(settings, Blocks.NOTE_BLOCK); + this.identifier = identifier; + this.setDefaultState(this.stateManager.getDefaultState().with(FACING, Direction.NORTH)); + this.polymerBlockState = PolymerBlockResourceUtils.requestBlock(BlockModelType.FULL_BLOCK, PolymerBlockModel.of(identifier.withPath("block/" + identifier.getPath()))); + } + + @Override + public BlockState getPlacementState(ItemPlacementContext ctx) { + return this.getDefaultState().with(FACING, ctx.getHorizontalPlayerFacing().getOpposite()); + } + + @Override + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder); + builder.add(FACING); + } + + @Override + public BlockState getPolymerBlockState(BlockState state) { + return this.polymerBlockState; + } + + public static void register() { + var modId = id(RADIO_INTERFACE_BLOCK_MODEL_ID); + RADIO_INTERFACE_BLOCK = Registry.register(Registries.BLOCK, modId, + new RadioInterfaceBlock(Settings.copy(Blocks.WHITE_WOOL), modId)); + UseBlockCallback.EVENT.register(RadioInterfaceBlock::onUse); + + RADIO_INTERFACE_BLOCK.setDefaultState(); + + RADIO_INTERFACE_BLOCK_ENTITY = Registry.register( + Registries.BLOCK_ENTITY_TYPE, + modId, + BlockEntityType.Builder.create(RadioInterfaceBlockEntity::new, RADIO_INTERFACE_BLOCK).build(null) + ); + PolymerBlockUtils.registerBlockEntity(RADIO_INTERFACE_BLOCK_ENTITY); + } + + private static ActionResult onUse(PlayerEntity plr, World world, Hand hand, BlockHitResult hitResult) { + BlockPos pos = hitResult.getBlockPos(); + BlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + + if (block instanceof RadioInterfaceBlock) { + if (!world.isClient && !plr.isSpectator() && plr instanceof ServerPlayerEntity player && hand == Hand.MAIN_HAND) { + BlockEntity storageBlockEntity = world.getBlockEntity(pos); + if (storageBlockEntity instanceof RadioInterfaceBlockEntity radioInterfaceBlockEntity) { + if (!player.isSneaking()) { + RadioBlockPlayerMangementScreen radioBlockPlayerMangementScreen = new RadioBlockPlayerMangementScreen(player, radioInterfaceBlockEntity); + radioBlockPlayerMangementScreen.updateDisplay(); + radioBlockPlayerMangementScreen.open(); + } else { + ItemStack stack = player.getStackInHand(hand); + Item item = stack.getItem(); + if (item == WIRELESS_TERMINAL) { + WirelessTerminalItem.ensureUUID(stack, player.getServer()); + UUID wirelessTerminalSession = stack.getOrDefault(WirelessTerminalComponents.SESSION_KEY, null); + List wirelessTerminalSessions = new ArrayList<>(stack.getOrDefault(WirelessTerminalComponents.SESSIONS, new ArrayList<>())); + if (wirelessTerminalSession != null) { + if (radioInterfaceBlockEntity.isSessionAuthorized(wirelessTerminalSession, player.getUuid())) { + radioInterfaceBlockEntity.deAuthorizeSession(wirelessTerminalSession, player.getUuid()); + removePosition(pos, stack); + } else { + radioInterfaceBlockEntity.authorizeSession(wirelessTerminalSession, player); + SessionStorageClass sessionStorageClass = null; + for (SessionStorageClass sessionStorageClassLoop : wirelessTerminalSessions) { + if (sessionStorageClassLoop.getTerminalPos().equals(pos)) { + sessionStorageClass = sessionStorageClassLoop; + break; + } + } + if (sessionStorageClass == null || !sessionStorageClass.getPlayerUUID().equals(player.getUuid())) { + sessionStorageClass = new SessionStorageClass(player.getUuid(), player.getServerWorld(), pos); + wirelessTerminalSessions.add(sessionStorageClass); + } + stack.set(WirelessTerminalComponents.SESSIONS, wirelessTerminalSessions); + } + } + WirelessTerminalItem.updateLore(stack, player.getServer()); + player.setStackInHand(hand, stack); + } else { + player.openHandledScreen(radioInterfaceBlockEntity); + } + } + } + } + return ActionResult.SUCCESS; + } + return ActionResult.PASS; + } + + @Nullable + @Override + public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { + return new RadioInterfaceBlockEntity(pos, state); + } + + @Override + protected void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { + ItemScatterer.onStateReplaced(state, newState, world, pos); + super.onStateReplaced(state, world, pos, newState, moved); + } +} diff --git a/src/main/java/systems/brn/serverstorage/items/SimpleItem.java b/src/main/java/systems/brn/serverstorage/items/SimpleItem.java index b69fa8c..b5a60cb 100644 --- a/src/main/java/systems/brn/serverstorage/items/SimpleItem.java +++ b/src/main/java/systems/brn/serverstorage/items/SimpleItem.java @@ -22,8 +22,8 @@ public class SimpleItem extends SimplePolymerItem implements PolymerItem { private final PolymerModelData polymerModel; public SimpleItem(Settings settings, Identifier identifier) { - super(settings, Items.BARRIER); - this.polymerModel = PolymerResourcePackUtils.requestModel(Items.BARRIER, identifier.withPath("item/" + identifier.getPath())); + super(settings, Items.STICK); + this.polymerModel = PolymerResourcePackUtils.requestModel(Items.STICK, identifier.withPath("item/" + identifier.getPath())); } @Override diff --git a/src/main/java/systems/brn/serverstorage/items/WirelessTerminalItem.java b/src/main/java/systems/brn/serverstorage/items/WirelessTerminalItem.java new file mode 100644 index 0000000..3498ffc --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/items/WirelessTerminalItem.java @@ -0,0 +1,252 @@ +package systems.brn.serverstorage.items; + +import com.mojang.authlib.GameProfile; +import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.LoreComponent; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroups; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.Text; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import systems.brn.serverstorage.blockentities.RadioInterfaceBlockEntity; +import systems.brn.serverstorage.lib.*; +import systems.brn.serverstorage.screens.StorageScreen; +import systems.brn.serverstorage.screens.WirelessTerminalSelectorScreen; + +import java.util.*; + +import static systems.brn.serverstorage.ServerStorage.*; + +public class WirelessTerminalItem extends SimpleItem { + public WirelessTerminalItem(Settings settings, Identifier identifier) { + super(settings, identifier); + } + + public static Item register() { + Identifier identifier = id(WIRELESS_TERMINAL_ID); + Item item = Registry.register(Registries.ITEM, identifier, new SimpleItem( + new Settings() + .maxCount(1) + .component(WirelessTerminalComponents.SESSION_KEY, null) + .component(WirelessTerminalComponents.SESSIONS, new ArrayList<>()) + .component(WirelessTerminalComponents.SELECTED_POSITION, -1) + .component(WirelessTerminalComponents.SORT_ALPHABETICALLY, false) + .component(WirelessTerminalComponents.QUERY_STRING, "") + .component(WirelessTerminalComponents.PAGE, 0) + , identifier)); + ItemGroupEvents.modifyEntriesEvent(ItemGroups.FUNCTIONAL).register(content -> content.add(item)); + return item; + } + + public static RadioInterfaceBlockEntity getRadioInterface(BlockPos pos, ServerWorld world) { + if (world.getBlockState(pos).getBlock() == RADIO_INTERFACE_BLOCK && world.getBlockEntity(pos) instanceof RadioInterfaceBlockEntity radioInterfaceBlockEntity) { + return radioInterfaceBlockEntity; + } + return null; + } + + public static RadioDistance getDistance(ServerPlayerEntity player, RadioInterfaceBlockEntity radioInterfaceBlockEntity) { + Vec3d playerTempPos = player.getPos(); + BlockPos playerPos = player.getBlockPos(); + BlockPos pos = radioInterfaceBlockEntity.getPos(); + ServerWorld playerWorld = player.getServerWorld(); + ServerWorld terminalWorld = playerWorld; + int finalDistance = 0; + int actualDistance = 0; + if (radioInterfaceBlockEntity.getWorld() instanceof ServerWorld terminalWorldTemp) { + double distanceCoefficient = 1; + terminalWorld = terminalWorldTemp; + if (playerWorld.getRegistryKey() != terminalWorld.getRegistryKey()) { + int playerWorldScale = (int) playerWorld.getDimension().coordinateScale(); + int terminalWorldScale = (int) terminalWorld.getDimension().coordinateScale(); + playerTempPos = new Vec3d(playerTempPos.getX() * playerWorldScale, playerTempPos.getY(), playerTempPos.getZ() * terminalWorldScale); + playerTempPos = new Vec3d(playerTempPos.getX() / terminalWorldScale, playerTempPos.getY(), playerTempPos.getZ() / terminalWorldScale); + distanceCoefficient = 0.4; + } + playerPos = BlockPos.ofFloored(playerTempPos); + finalDistance = (int) (radioInterfaceBlockEntity.antennaRange * distanceCoefficient); + finalDistance = Math.max(finalDistance, 1); + actualDistance = (int) Math.sqrt(playerPos.getSquaredDistance(pos)); + } + return new RadioDistance(radioInterfaceBlockEntity, finalDistance, actualDistance, playerPos, pos, playerWorld, terminalWorld); + } + + public static boolean openTerminal(BlockPos pos, ServerPlayerEntity player, ItemStack stack, ServerWorld world) { + + ServerWorld playerWorld = player.getServerWorld(); + String playerWorldName = playerWorld.getRegistryKey().getValue().toString(); + String terminalWorldName = world.getRegistryKey().getValue().toString(); + if (stack.getItem() == WIRELESS_TERMINAL) { + RadioInterfaceBlockEntity radioInterfaceBlockEntity = WirelessTerminalItem.getRadioInterface(pos, world); + if (radioInterfaceBlockEntity != null) { + RadioDistance radioDistance = getDistance(player, radioInterfaceBlockEntity); + if (radioInterfaceBlockEntity.antennaRange > 0 && radioDistance.actualDistance() <= radioDistance.finalDistance()) { + player.sendMessage(Text.translatable("gui.serverstorage.radio_connected", pos.toShortString(), terminalWorldName, radioDistance.playerPos().toShortString(), playerWorldName, radioDistance.actualDistance(), radioDistance.finalDistance()), true); + UUID wirelessTerminalSession = stack.getOrDefault(WirelessTerminalComponents.SESSION_KEY, null); + if (radioInterfaceBlockEntity.isSessionAuthorized(wirelessTerminalSession, player.getUuid())) { + boolean sortAlphabetically = stack.getOrDefault(WirelessTerminalComponents.SORT_ALPHABETICALLY, false); + String searchQuery = stack.getOrDefault(WirelessTerminalComponents.QUERY_STRING, ""); + StorageNetwork storageNetwork = new StorageNetwork(world, pos, sortAlphabetically, searchQuery); + StorageScreen storageScreen = new StorageScreen(player, stack, storageNetwork, radioInterfaceBlockEntity); + storageScreen.updateDisplay(); + storageScreen.open(); + } else { + player.sendMessage(Text.translatable("gui.serverstorage.radio_unauthorized", pos.toShortString(), terminalWorldName), true); + player.playSoundToPlayer(SoundEvents.BLOCK_NOTE_BLOCK_BASS.value(), SoundCategory.PLAYERS, 1f, 1f); + return false; + } + } else { + player.sendMessage(Text.translatable("gui.serverstorage.radio_out_of_range", pos.toShortString(), terminalWorldName, radioDistance.playerPos().toShortString(), playerWorldName, radioDistance.actualDistance(), radioDistance.finalDistance()), true); + player.playSoundToPlayer(SoundEvents.BLOCK_NOTE_BLOCK_COW_BELL.value(), SoundCategory.PLAYERS, 1f, 1f); + } + return true; + } else { + player.sendMessage(Text.translatable("gui.serverstorage.radio_not_found", pos.toShortString(), terminalWorldName, player.getBlockPos().toShortString(), playerWorldName), true); + player.playSoundToPlayer(SoundEvents.BLOCK_NOTE_BLOCK_SNARE.value(), SoundCategory.PLAYERS, 1f, 1f); + } + } + return false; + } + + private static void setSelectedPosition(ItemStack stack, List sessions) { + int selectedIndex = stack.getOrDefault(WirelessTerminalComponents.SELECTED_POSITION, -1); + if (selectedIndex >= sessions.size()) { + selectedIndex = sessions.size() - 1; + } + stack.set(WirelessTerminalComponents.SELECTED_POSITION, selectedIndex); + } + + public static void removePosition(BlockPos pos, ItemStack stack) { + List sessions = Util.removePosition(pos, stack); + setSelectedPosition(stack, sessions); + } + + public static void ensureUUID(ItemStack stack, MinecraftServer server) { + UUID wirelessTerminalSession = stack.getOrDefault(WirelessTerminalComponents.SESSION_KEY, null); + if (wirelessTerminalSession == null) { + stack.set(WirelessTerminalComponents.SESSION_KEY, UUID.randomUUID()); + updateLore(stack, server); + } + } + + public static void updateLore(ItemStack stack, MinecraftServer server) { + UUID wirelessTerminalSessionKey = stack.getOrDefault(WirelessTerminalComponents.SESSION_KEY, null); + List sessions = new ArrayList<>(stack.getOrDefault(WirelessTerminalComponents.SESSIONS, new ArrayList<>())); + int selectedPositionIndex = stack.getOrDefault(WirelessTerminalComponents.SELECTED_POSITION, -1); + Text radioPlacedAt = Text.translatable("gui.serverstorage.radio_position_error"); + Text ownedBy = Text.translatable("gui.serverstorage.player_management_session_owner_error"); + if (selectedPositionIndex >= 0 && !sessions.isEmpty()) { + SessionStorageClass session = sessions.get(selectedPositionIndex); + BlockPos pos = session.getTerminalPos(); + radioPlacedAt = Text.translatable("gui.serverstorage.radio_position", pos.toShortString(), session.getWorldKey().getValue().getPath()); + GameProfile owner = session.getPlayerProfile(server); + String ownerName = owner != null ? owner.getName() : "No one"; + ownedBy = Text.translatable("gui.serverstorage.player_management_session_owner", ownerName); + } + int page = stack.getOrDefault(WirelessTerminalComponents.PAGE, 0); + boolean sortingAlphabetically = stack.getOrDefault(WirelessTerminalComponents.SORT_ALPHABETICALLY, false); + String searchQuery = stack.getOrDefault(WirelessTerminalComponents.QUERY_STRING, "*"); + if (selectedPositionIndex < 0 && !sessions.isEmpty()) { + selectedPositionIndex = sessions.size() - 1; + stack.set(WirelessTerminalComponents.SELECTED_POSITION, selectedPositionIndex); + } + stack.set(DataComponentTypes.LORE, new LoreComponent(List.of( + Text.translatable("gui.serverstorage.player_management_session_key", wirelessTerminalSessionKey == null ? "Missing UUID" : wirelessTerminalSessionKey.toString()), + Text.translatable("gui.serverstorage.wireless_terminal_link_count", sessions.size()), + ownedBy, + Text.translatable("gui.serverstorage.wireless_terminal_link_index", selectedPositionIndex), + Text.translatable("gui.serverstorage.wireless_terminal_page", page), + Text.translatable("gui.serverstorage.wireless_terminal_search_query", searchQuery), + Text.translatable(sortingAlphabetically ? "gui.serverstorage.wireless_terminal_sorting_alphabetically" : "gui.serverstorage.wireless_terminal_sorting_numerically"), + radioPlacedAt + ))); + } + + public static boolean stackMatches(ItemStack stack, ItemStack stack2) { + UUID stack1UUID = stack.getOrDefault(WirelessTerminalComponents.SESSION_KEY, null); + UUID stack2UUID = stack2.getOrDefault(WirelessTerminalComponents.SESSION_KEY, null); + return stack.getItem() == WIRELESS_TERMINAL && stack2.getItem() == WIRELESS_TERMINAL && stack1UUID != null && stack1UUID.equals(stack2UUID); + } + + public static void saveStack(ItemStack changedStack, ItemStack originalStack, ServerPlayerEntity player) { + ItemStack stackInMainHand = player.getMainHandStack(); + ItemStack stackInOffHand = player.getOffHandStack(); + if (stackMatches(originalStack, stackInMainHand)) { + player.setStackInHand(Hand.MAIN_HAND, changedStack); + } else if (stackMatches(originalStack, stackInOffHand)) { + player.setStackInHand(Hand.OFF_HAND, changedStack); + } else { + PlayerInventory playerInventory = player.getInventory(); + for (int i = 0; i < playerInventory.size(); i++) { + ItemStack stackInSlot = playerInventory.getStack(i); + if (stackMatches(stackInSlot, stackInMainHand)) { + playerInventory.setStack(i, changedStack); + break; + } + } + } + } + + public static boolean useItem(ServerWorld world, ServerPlayerEntity playerEntity, ItemStack stackTemp) { + MinecraftServer server = world.getServer(); + ensureUUID(stackTemp, server); + updateLore(stackTemp, server); + if (!playerEntity.isSneaking()) { + ItemStack stack = stackTemp.copy(); + List wirelessTerminalPositions = new ArrayList<>(stack.getOrDefault(WirelessTerminalComponents.SESSIONS, new ArrayList<>())); + int selectedPosition = stack.getOrDefault(WirelessTerminalComponents.SELECTED_POSITION, -1); + + if (selectedPosition < 0 && !wirelessTerminalPositions.isEmpty()) { + selectedPosition = wirelessTerminalPositions.size() - 1; + stack.set(WirelessTerminalComponents.SELECTED_POSITION, selectedPosition); + saveStack(stack, stackTemp, playerEntity); + } + + if (wirelessTerminalPositions.isEmpty()) { + stack.remove(WirelessTerminalComponents.SELECTED_POSITION); + saveStack(stack, stackTemp, playerEntity); + selectedPosition = -1; + } + + if (selectedPosition < 0) { + WirelessTerminalSelectorScreen wirelessTerminalSelectorScreen = new WirelessTerminalSelectorScreen(playerEntity, null); + wirelessTerminalSelectorScreen.open(); + return false; + } + + SessionStorageClass sessionStorageClass = wirelessTerminalPositions.get(selectedPosition); + BlockPos selectedPos = sessionStorageClass.getTerminalPos(); + + if (sessionStorageClass.getPlayerUUID().equals(playerEntity.getUuid()) && sessionStorageClass.getWorld(server).getBlockEntity(selectedPos) instanceof RadioInterfaceBlockEntity) { + boolean success = openTerminal(selectedPos, playerEntity, stack, sessionStorageClass.getWorld(server)); + if (!success) { + removePosition(selectedPos, stack); + saveStack(stack, stackTemp, playerEntity); + } + return true; + } else { + removePosition(selectedPos, stack); + saveStack(stack, stackTemp, playerEntity); + playerEntity.playSoundToPlayer(SoundEvents.BLOCK_NOTE_BLOCK_BASS.value(), SoundCategory.PLAYERS, 1f, 1f); + WirelessTerminalSelectorScreen wirelessTerminalSelectorScreen = new WirelessTerminalSelectorScreen(playerEntity, null); + wirelessTerminalSelectorScreen.open(); + } + } else { + WirelessTerminalSelectorScreen wirelessTerminalSelectorScreen = new WirelessTerminalSelectorScreen(playerEntity, null); + wirelessTerminalSelectorScreen.open(); + } + return false; + } +} diff --git a/src/main/java/systems/brn/serverstorage/lib/Antenna.java b/src/main/java/systems/brn/serverstorage/lib/Antenna.java new file mode 100644 index 0000000..dc3b410 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/Antenna.java @@ -0,0 +1,46 @@ +package systems.brn.serverstorage.lib; + +import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.component.type.LoreComponent; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroups; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import systems.brn.serverstorage.items.SimpleItem; + +import java.util.ArrayList; +import java.util.List; + +import static systems.brn.serverstorage.ServerStorage.ANTENNA_RANGES; +import static systems.brn.serverstorage.ServerStorage.id; + +public class Antenna extends SimpleItem { + public final int range; + + public Antenna(Settings settings, Identifier identifier, int range) { + super(settings.component(DataComponentTypes.LORE, + new LoreComponent(List.of( + Text.translatable("gui.serverstorage.antenna_range", range) + ))), identifier); + this.range = range; + } + + public static List register(List tiers) { + ArrayList items = new ArrayList<>(); + int range = 16; + for (String tier : tiers) { + Identifier identifier = id(tier + "_antenna"); + Item item = Registry.register(Registries.ITEM, identifier, new Antenna(new Settings() + .maxCount(1) + , identifier, range)); + ItemGroupEvents.modifyEntriesEvent(ItemGroups.FUNCTIONAL).register(content -> content.add(item)); + items.add(item); + ANTENNA_RANGES.put(item, range); + range *= 3; + } + return items; + } +} diff --git a/src/main/java/systems/brn/serverstorage/lib/AntennaSlot.java b/src/main/java/systems/brn/serverstorage/lib/AntennaSlot.java new file mode 100644 index 0000000..03e6351 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/AntennaSlot.java @@ -0,0 +1,24 @@ +package systems.brn.serverstorage.lib; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; + +import static systems.brn.serverstorage.ServerStorage.ANTENNA_LIST; + +public class AntennaSlot extends Slot { + public AntennaSlot(Inventory inventory, int index, int x, int y) { + super(inventory, index, x, y); + } + + public static boolean isAntenna(Item item) { + return ANTENNA_LIST.contains(item); + } + + @Override + public boolean canInsert(ItemStack stack) { + return isAntenna(stack.getItem()); + } + +} diff --git a/src/main/java/systems/brn/serverstorage/lib/EventHandler.java b/src/main/java/systems/brn/serverstorage/lib/EventHandler.java new file mode 100644 index 0000000..430a45a --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/EventHandler.java @@ -0,0 +1,31 @@ +package systems.brn.serverstorage.lib; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.world.World; +import systems.brn.serverstorage.items.WirelessTerminalItem; + +import static systems.brn.serverstorage.ServerStorage.WIRELESS_TERMINAL; + +public class EventHandler { + public static TypedActionResult onItemUse(PlayerEntity playerEntity, World worldTemp, Hand hand) { + ItemStack itemStack = playerEntity.getStackInHand(hand); + Item item = itemStack.getItem(); + if (!worldTemp.isClient) { + if (playerEntity instanceof ServerPlayerEntity player) { + if (worldTemp instanceof ServerWorld world) { + if (item == WIRELESS_TERMINAL) { + return WirelessTerminalItem.useItem(world, player, itemStack) ? TypedActionResult.success(itemStack) : TypedActionResult.pass(itemStack); + } + } + } + } + + return TypedActionResult.pass(itemStack); + } +} diff --git a/src/main/java/systems/brn/serverstorage/lib/GenericPlayerListGui.java b/src/main/java/systems/brn/serverstorage/lib/GenericPlayerListGui.java new file mode 100644 index 0000000..476ba3b --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/GenericPlayerListGui.java @@ -0,0 +1,73 @@ +package systems.brn.serverstorage.lib; + +import com.mojang.authlib.GameProfile; +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import net.minecraft.item.Items; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.UserCache; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.UUID; + +//inspired by: https://github.com/Patbox/get-off-my-lawn-reserved/blob/1.21/src/main/java/draylar/goml/ui/GenericPlayerListGui.java +public class GenericPlayerListGui extends PagedGui { + public final List uuids = new ArrayList<>(); + + public GenericPlayerListGui(ServerPlayerEntity player, @Nullable Runnable onClose) { + super(player, onClose); + } + + @Override + protected int getPageAmount() { + return (this.getEntryCount()) / PAGE_SIZE; + } + + protected int getEntryCount() { + return this.uuids.size(); + } + + @Override + protected DisplayElement getElement(int id) { + return getPlayerElement(id); + } + + protected DisplayElement getPlayerElement(int id) { + if (this.uuids.size() > id) { + return getPlayerElement(this.uuids.get(id)); + } + + return DisplayElement.empty(); + } + + protected DisplayElement getPlayerElement(UUID uuid) { + UserCache userCache = this.player.server.getUserCache(); + GameProfile gameProfile = null; + Optional gameProfileTemp; + boolean exists = false; + + if (userCache != null) { + gameProfileTemp = userCache.getByUuid(uuid); + exists = gameProfileTemp.isPresent(); + gameProfile = exists ? gameProfileTemp.get() : null; + } + + + var builder = new GuiElementBuilder(exists ? Items.PLAYER_HEAD : Items.SKELETON_SKULL) + .setName(Text.literal(exists ? gameProfile.getName() : "<" + uuid.toString() + ">") + .formatted(Formatting.WHITE) + ); + + if (exists) { + builder.setSkullOwner(gameProfile, null); + } else { + builder.setSkullOwner(PagedGui.GUI_QUESTION_MARK); + } + + return DisplayElement.of(builder); + } +} diff --git a/src/main/java/systems/brn/serverstorage/lib/ItemGroups.java b/src/main/java/systems/brn/serverstorage/lib/ItemGroups.java index a167f64..ca9923c 100644 --- a/src/main/java/systems/brn/serverstorage/lib/ItemGroups.java +++ b/src/main/java/systems/brn/serverstorage/lib/ItemGroups.java @@ -16,6 +16,7 @@ public class ItemGroups { entries.add(HARD_DRIVE_CONTAINER_BLOCK); entries.add(BUS_CONNECTOR_BLOCK); entries.add(INVENTORY_INTERFACE_BLOCK); + entries.add(RADIO_INTERFACE_BLOCK); })) .build(); @@ -36,6 +37,10 @@ public class ItemGroups { entries.add(HEADS.get(i)); } } + for (Item antenna : ANTENNA_LIST) { + entries.add(antenna); + } + entries.add(WIRELESS_TERMINAL); })) .build(); diff --git a/src/main/java/systems/brn/serverstorage/lib/RadioDistance.java b/src/main/java/systems/brn/serverstorage/lib/RadioDistance.java new file mode 100644 index 0000000..fbf4304 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/RadioDistance.java @@ -0,0 +1,16 @@ +package systems.brn.serverstorage.lib; + +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import systems.brn.serverstorage.blockentities.RadioInterfaceBlockEntity; + +public record RadioDistance( + RadioInterfaceBlockEntity radioInterfaceBlockEntity, + int finalDistance, + int actualDistance, + BlockPos playerPos, + BlockPos terminalPos, + ServerWorld playerWorld, + ServerWorld terminalWorld +) { +} diff --git a/src/main/java/systems/brn/serverstorage/lib/Session.java b/src/main/java/systems/brn/serverstorage/lib/Session.java new file mode 100644 index 0000000..7138ca1 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/Session.java @@ -0,0 +1,23 @@ +package systems.brn.serverstorage.lib; + +import net.minecraft.nbt.NbtCompound; + +import java.util.UUID; + +public record Session(UUID sessionKey, UUID playerUUID) { + + // Serialize to NBT + public NbtCompound toNbt() { + NbtCompound nbt = new NbtCompound(); + nbt.putUuid("SessionKey", this.sessionKey); + nbt.putUuid("PlayerUUID", this.playerUUID); + return nbt; + } + + // Deserialize from NBT + public static Session fromNbt(NbtCompound nbt) { + UUID sessionKey = nbt.getUuid("SessionKey"); + UUID playerUUID = nbt.getUuid("PlayerUUID"); + return new Session(sessionKey, playerUUID); + } +} diff --git a/src/main/java/systems/brn/serverstorage/lib/SessionStorageClass.java b/src/main/java/systems/brn/serverstorage/lib/SessionStorageClass.java new file mode 100644 index 0000000..78b90e9 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/SessionStorageClass.java @@ -0,0 +1,50 @@ +package systems.brn.serverstorage.lib; + +import com.mojang.authlib.GameProfile; +import net.minecraft.registry.RegistryKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.UUID; + +import static systems.brn.serverstorage.lib.Util.getGameProfile; + +public class SessionStorageClass { + private final BlockPos terminalPos; + private final UUID playerUUID; + private final RegistryKey worldKey; + + public SessionStorageClass(UUID playerUUID, ServerWorld world, BlockPos terminalPos) { + this.playerUUID = playerUUID; + this.worldKey = world.getRegistryKey(); + this.terminalPos = terminalPos; + } + + public SessionStorageClass(UUID playerUUID, RegistryKey worldKey, BlockPos terminalPos) { + this.playerUUID = playerUUID; + this.worldKey = worldKey; + this.terminalPos = terminalPos; + } + + public BlockPos getTerminalPos() { + return terminalPos; + } + + public UUID getPlayerUUID() { + return playerUUID; + } + + public GameProfile getPlayerProfile(MinecraftServer server) { + return getGameProfile(playerUUID, server); + } + + public RegistryKey getWorldKey() { + return worldKey; + } + + public ServerWorld getWorld(MinecraftServer server) { + return server.getWorld(this.worldKey); + } +} \ No newline at end of file diff --git a/src/main/java/systems/brn/serverstorage/lib/Util.java b/src/main/java/systems/brn/serverstorage/lib/Util.java index e22b227..973555d 100644 --- a/src/main/java/systems/brn/serverstorage/lib/Util.java +++ b/src/main/java/systems/brn/serverstorage/lib/Util.java @@ -1,5 +1,6 @@ package systems.brn.serverstorage.lib; +import com.mojang.authlib.GameProfile; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.LoreComponent; import net.minecraft.item.Item; @@ -10,11 +11,10 @@ import net.minecraft.text.RawFilteredPair; import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +import net.minecraft.util.UserCache; +import net.minecraft.util.math.BlockPos; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; public class Util { @@ -86,6 +86,31 @@ public class Util { } } + public static GameProfile getGameProfile(UUID playerUUID, MinecraftServer server) { + UserCache userCache = server.getUserCache(); + GameProfile gameProfile = null; + Optional gameProfileTemp; + + if (userCache != null) { + gameProfileTemp = userCache.getByUuid(playerUUID); + boolean exists = gameProfileTemp.isPresent(); + gameProfile = exists ? gameProfileTemp.get() : null; + } + return gameProfile; + } + + public static List removePosition(BlockPos pos, ItemStack stack) { + List sessions = new ArrayList<>(stack.getOrDefault(WirelessTerminalComponents.SESSIONS, new ArrayList<>())); + for (SessionStorageClass session : sessions) { + if (session.getTerminalPos().equals(pos)) { + sessions.remove(session); + break; + } + } + stack.set(WirelessTerminalComponents.SESSIONS, sessions); + return sessions; + } + public static ItemStack removeCountFromLore(ItemStack stack) { LoreComponent oldLore = stack.get(DataComponentTypes.LORE); diff --git a/src/main/java/systems/brn/serverstorage/lib/WirelessTerminalComponents.java b/src/main/java/systems/brn/serverstorage/lib/WirelessTerminalComponents.java new file mode 100644 index 0000000..ba1af9c --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/lib/WirelessTerminalComponents.java @@ -0,0 +1,71 @@ +package systems.brn.serverstorage.lib; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import eu.pb4.polymer.core.api.other.PolymerComponent; +import net.minecraft.component.ComponentType; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; + +import java.util.List; +import java.util.UUID; +import java.util.function.UnaryOperator; + +import static systems.brn.serverstorage.lib.DriveComponents.UUID_CODEC; + + +public class WirelessTerminalComponents { + + public static final Codec SESSION_CODEC = RecordCodecBuilder.create(instance -> instance.group( + UUID_CODEC.fieldOf("playerUUID").forGetter(SessionStorageClass::getPlayerUUID), + ServerWorld.CODEC.fieldOf("worldKey").forGetter(SessionStorageClass::getWorldKey), + BlockPos.CODEC.fieldOf("terminalPos").forGetter(SessionStorageClass::getTerminalPos) + ).apply(instance, SessionStorageClass::new)); + + public static final Codec> SESSIONS_CODEC = Codec.list(SESSION_CODEC); + + + public static final ComponentType SESSION_KEY = register( + "session_key", + builder -> builder.codec(UUID_CODEC) // No packetCodec needed for this example + ); + + public static final ComponentType> SESSIONS = register( + "sessions", + builder -> builder.codec(SESSIONS_CODEC) // No packetCodec needed for this example + ); + + public static final ComponentType SELECTED_POSITION = register( + "selected_position", + builder -> builder.codec(Codec.INT) // No packetCodec needed for this example + ); + + public static final ComponentType PAGE = register( + "page", + builder -> builder.codec(Codec.INT) // No packetCodec needed for this example + ); + + + public static final ComponentType SORT_ALPHABETICALLY = register( + "sort_alphabetically", + builder -> builder.codec(Codec.BOOL) // No packetCodec needed for this example + ); + + public static final ComponentType QUERY_STRING = register( + "query_string", + builder -> builder.codec(Codec.STRING) // No packetCodec needed for this example + ); + + + private static ComponentType register(String id, UnaryOperator> builderOperator) { + ComponentType componentType = Registry.register( + Registries.DATA_COMPONENT_TYPE, + id, + builderOperator.apply(ComponentType.builder()).build() + ); + PolymerComponent.registerDataComponent(componentType); + return componentType; + } +} diff --git a/src/main/java/systems/brn/serverstorage/screenhandlers/RadioInterfaceScreenHandler.java b/src/main/java/systems/brn/serverstorage/screenhandlers/RadioInterfaceScreenHandler.java new file mode 100644 index 0000000..f00abf1 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/screenhandlers/RadioInterfaceScreenHandler.java @@ -0,0 +1,85 @@ +package systems.brn.serverstorage.screenhandlers; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.screen.slot.Slot; +import systems.brn.serverstorage.blockentities.RadioInterfaceBlockEntity; +import systems.brn.serverstorage.lib.AntennaSlot; + +public class RadioInterfaceScreenHandler extends ScreenHandler { + private final Inventory inventory; + private final RadioInterfaceBlockEntity blockEntity; + + public RadioInterfaceScreenHandler(int syncId, PlayerInventory playerInventory, RadioInterfaceBlockEntity blockEntity) { + super(ScreenHandlerType.BEACON, syncId); + this.blockEntity = blockEntity; + checkSize(blockEntity, RadioInterfaceBlockEntity.INVENTORY_SIZE); + this.inventory = blockEntity; + inventory.onOpen(playerInventory.player); + + int j; + this.addSlot(new AntennaSlot(inventory, 0, 44, 20)); + + for (j = 0; j < 3; ++j) { + for (int k = 0; k < 9; ++k) { + this.addSlot(new Slot(playerInventory, k + j * 9 + 9, 8 + k * 18, j * 18 + 51)); + } + } + + for (j = 0; j < 9; ++j) { + this.addSlot(new Slot(playerInventory, j, 8 + j * 18, 109)); + } + } + + @Override + public boolean canUse(PlayerEntity player) { + return this.inventory.canPlayerUse(player); + } + + + @Override + public ItemStack quickMove(PlayerEntity player, int slot) { + return quickMoveHelper(player, slot); + } + + public ItemStack quickMoveHelper(PlayerEntity player, int slot) { + ItemStack itemStack = ItemStack.EMPTY; + Slot slot2 = this.slots.get(slot); + if (slot2.hasStack()) { + ItemStack itemStack2 = slot2.getStack(); + itemStack = itemStack2.copy(); + if (slot < this.inventory.size()) { + if (!this.insertItem(itemStack2, this.inventory.size(), this.slots.size(), true)) { + return ItemStack.EMPTY; + } + } else if (!this.insertItem(itemStack2, 0, this.inventory.size(), false)) { + return ItemStack.EMPTY; + } + + if (itemStack2.isEmpty()) { + slot2.setStack(ItemStack.EMPTY); + } else { + slot2.markDirty(); + } + + if (itemStack2.getCount() == itemStack.getCount()) { + return ItemStack.EMPTY; + } + + slot2.onTakeItem(player, itemStack2); + } + + return itemStack; + } + + @Override + public void onClosed(PlayerEntity player) { + super.onClosed(player); + this.inventory.onClose(player); + this.blockEntity.updateAntenna(); + } +} diff --git a/src/main/java/systems/brn/serverstorage/screens/CraftingScreen.java b/src/main/java/systems/brn/serverstorage/screens/CraftingScreen.java index 210c20b..342b087 100644 --- a/src/main/java/systems/brn/serverstorage/screens/CraftingScreen.java +++ b/src/main/java/systems/brn/serverstorage/screens/CraftingScreen.java @@ -35,15 +35,26 @@ public class CraftingScreen extends PagedGui { this.updateDisplay(); } + public void reindexDrives() { + if (blockEntity == null) { + storageScreen.getNetwork().reindexNetwork(); + } else { + blockEntity.reindexDrives(); + } + } + @Override public void updateDisplay() { - blockEntity.reindexDrives(); // Use justReindexDrives to avoid looping + Map itemStackMap = new HashMap<>(); addInventoryToMap(storageScreen.getPlayer().getInventory(), itemStackMap); - itemStackMap.putAll(blockEntity.network.itemStackMap); + itemStackMap.putAll(storageScreen.getNetwork().itemStackMap); Map items = sortAndFilterMap(itemStackMap, false, null); this.craftingEntries = getCraftableRecipes(items, Objects.requireNonNull(player.getServer())); this.recipesList = getAvailableRecipes(); + if (blockEntity != null){ + blockEntity.refreshTerminals(); + } super.updateDisplay(); } @@ -92,7 +103,7 @@ public class CraftingScreen extends PagedGui { } private boolean canCraft(RecipeEntry recipeEntry) { - blockEntity.reindexDrives(); + reindexDrives(); for (Ingredient ingredient : recipeEntry.value().getIngredients()) { if (findMatchingStack(ingredient) == null) { return false; @@ -131,8 +142,8 @@ public class CraftingScreen extends PagedGui { } } else { ItemStack insertStack = outputStack.copy(); - if (this.blockEntity.network.canAddItemStack(insertStack)) { - this.blockEntity.network.putItemStackRemainder(insertStack); + if (this.storageScreen.getNetwork().canAddItemStack(insertStack)) { + this.storageScreen.getNetwork().putItemStackRemainder(insertStack); } else { return true; // Storage full or unable to insert all items } @@ -148,7 +159,7 @@ public class CraftingScreen extends PagedGui { ItemStack playerStack = playerInventory.getStack(i); if (ingredient.test(playerStack)) { ItemStack stackToRemove = playerStack.copy(); - for (ItemStack matchingStack : ingredient.getMatchingStacks()){ + for (ItemStack matchingStack : ingredient.getMatchingStacks()) { if (matchingStack.getItem() == stackToRemove.getItem()) { stackToRemove.setCount(matchingStack.getCount()); // Set count to ingredient requirement break; @@ -160,7 +171,7 @@ public class CraftingScreen extends PagedGui { // Check storage network for (ItemStack stack : ingredient.getMatchingStacks()) { - if (this.blockEntity.network.canRemove(stack)) { + if (this.storageScreen.getNetwork().canRemove(stack)) { ItemStack stackToRemove = stack.copy(); stackToRemove.setCount(ingredient.getMatchingStacks()[0].getCount()); // Set count to ingredient requirement return stackToRemove; @@ -170,7 +181,7 @@ public class CraftingScreen extends PagedGui { } private void removeItems(ItemStack stack) { - ItemStack removedFromStorage = this.blockEntity.network.removeItemStack(stack); + ItemStack removedFromStorage = this.storageScreen.getNetwork().removeItemStack(stack); if (removedFromStorage.getCount() > 0) { Inventory playerInventory = player.getInventory(); for (int i = 0; i < playerInventory.size(); i++) { @@ -184,22 +195,29 @@ public class CraftingScreen extends PagedGui { @Override public boolean open() { - page = blockEntity.page; - this.blockEntity.openCraftingScreens.add(this); - blockEntity.updateDisplays(); + if (this.blockEntity != null) { + this.blockEntity.openCraftingScreens.add(this); + blockEntity.updateDisplays(); + } else { + updateDisplay(); + } return super.open(); } @Override public void onClose() { super.onClose(); - this.blockEntity.openCraftingScreens.remove(this); + if (this.blockEntity != null) { + this.blockEntity.openCraftingScreens.remove(this); + this.blockEntity.refreshTerminals(); + } storageScreen.open(); + storageScreen.updateDisplay(); } @Override protected int getPageAmount() { - return Math.ceilDivExact(recipesList.size(), 9 * 6); + return Math.ceilDivExact(recipesList.size(), PAGE_SIZE); } @Override diff --git a/src/main/java/systems/brn/serverstorage/screens/RadioBlockPlayerMangementScreen.java b/src/main/java/systems/brn/serverstorage/screens/RadioBlockPlayerMangementScreen.java new file mode 100644 index 0000000..39c4f1e --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/screens/RadioBlockPlayerMangementScreen.java @@ -0,0 +1,67 @@ +package systems.brn.serverstorage.screens; + +import com.mojang.authlib.GameProfile; +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import net.minecraft.item.Items; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import systems.brn.serverstorage.blockentities.RadioInterfaceBlockEntity; +import systems.brn.serverstorage.lib.PagedGui; +import systems.brn.serverstorage.lib.Session; + +import static systems.brn.serverstorage.lib.Util.getGameProfile; + +public class RadioBlockPlayerMangementScreen extends PagedGui { + public final RadioInterfaceBlockEntity radioInterfaceBlockEntity; + + public RadioBlockPlayerMangementScreen(ServerPlayerEntity player, RadioInterfaceBlockEntity radioInterfaceBlockEntity) { + super(player, null); + this.radioInterfaceBlockEntity = radioInterfaceBlockEntity; + this.setTitle(Text.translatable("gui.serverstorage.player_management")); + } + + protected DisplayElement getSessionElement(Session session, int index) { + + GameProfile gameProfile = null; + if (player != null && player.getServer() != null) { + gameProfile = getGameProfile(session.playerUUID(), player.getServer()); + } + + var builder = new GuiElementBuilder(gameProfile != null ? Items.PLAYER_HEAD : Items.SKELETON_SKULL) + .setName(Text.translatable("gui.serverstorage.player_management_session", index)) + .addLoreLine(Text.translatable("gui.serverstorage.player_management_session_owner", + gameProfile != null ? gameProfile.getName() : "<" + session.playerUUID().toString() + ">") + .formatted(Formatting.WHITE) + ) + .addLoreLine(Text.translatable("gui.serverstorage.player_management_session_key", session.sessionKey().toString())) + .addLoreLine(Text.translatable("gui.serverstorage.player_management_session_click_deauthorize")) + .setCallback((clickIndex, clickType, slotActionType) -> { + playClickSound(getPlayer()); + radioInterfaceBlockEntity.deAuthorizeSession(session.sessionKey(), session.playerUUID()); + updateDisplay(); + }); + + if (gameProfile != null) { + builder.setSkullOwner(gameProfile, null); + } else { + builder.setSkullOwner(PagedGui.GUI_QUESTION_MARK); + } + + return DisplayElement.of(builder); + } + + @Override + protected int getPageAmount() { + return radioInterfaceBlockEntity.sessions.size() / PAGE_SIZE; + } + + @Override + protected DisplayElement getElement(int id) { + if (id < radioInterfaceBlockEntity.sessions.size()) { + Session session = radioInterfaceBlockEntity.sessions.get(id); + return getSessionElement(session, id); + } + return DisplayElement.empty(); + } +} diff --git a/src/main/java/systems/brn/serverstorage/screens/SettingsScreen.java b/src/main/java/systems/brn/serverstorage/screens/SettingsScreen.java index 01e0f76..6238429 100644 --- a/src/main/java/systems/brn/serverstorage/screens/SettingsScreen.java +++ b/src/main/java/systems/brn/serverstorage/screens/SettingsScreen.java @@ -58,7 +58,7 @@ public class SettingsScreen extends PagedGui { @Override protected int getPageAmount() { - return Math.ceilDivExact(settingsList.size(), 9 * 5); + return Math.ceilDivExact(settingsList.size(), PAGE_SIZE); } @Override diff --git a/src/main/java/systems/brn/serverstorage/screens/StorageScreen.java b/src/main/java/systems/brn/serverstorage/screens/StorageScreen.java index c5d801a..6a80bc7 100644 --- a/src/main/java/systems/brn/serverstorage/screens/StorageScreen.java +++ b/src/main/java/systems/brn/serverstorage/screens/StorageScreen.java @@ -8,15 +8,24 @@ import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.screen.slot.SlotActionType; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; +import systems.brn.serverstorage.blockentities.RadioInterfaceBlockEntity; import systems.brn.serverstorage.blockentities.StorageInterfaceBlockEntity; import systems.brn.serverstorage.lib.PagedGui; +import systems.brn.serverstorage.lib.RadioDistance; +import systems.brn.serverstorage.lib.StorageNetwork; +import systems.brn.serverstorage.lib.WirelessTerminalComponents; + +import java.util.Map; import static systems.brn.serverstorage.ServerStorage.ServerStorage_Crafting_Enable; +import static systems.brn.serverstorage.items.WirelessTerminalItem.getDistance; import static systems.brn.serverstorage.lib.StorageOperations.*; import static systems.brn.serverstorage.lib.Util.addCountToLore; import static systems.brn.serverstorage.lib.Util.removeCountFromLore; @@ -24,6 +33,27 @@ import static systems.brn.serverstorage.lib.Util.removeCountFromLore; public class StorageScreen extends PagedGui { private final ServerPlayerEntity player; public final StorageInterfaceBlockEntity blockEntity; + public final StorageNetwork network; + public final ItemStack itemStack; + public final ServerWorld world; + public final RadioInterfaceBlockEntity radioInterfaceBlockEntity; + + public boolean checkDistance() { + if (radioInterfaceBlockEntity != null) { + RadioDistance radioDistance = getDistance(player, radioInterfaceBlockEntity); + if (radioDistance.actualDistance() > radioDistance.finalDistance()) { + close(); + ServerWorld playerWorld = radioDistance.playerWorld(); + ServerWorld terminalWorld = radioDistance.terminalWorld(); + String playerWorldName = playerWorld.getRegistryKey().getValue().toString(); + String terminalWorldName = terminalWorld.getRegistryKey().getValue().toString(); + player.sendMessage(Text.translatable("gui.serverstorage.radio_out_of_range", radioDistance.terminalPos().toShortString(), terminalWorldName, player.getBlockPos().toShortString(), playerWorldName, radioDistance.actualDistance(), radioDistance.finalDistance()), true); + player.playSoundToPlayer(SoundEvents.BLOCK_NOTE_BLOCK_COW_BELL.value(), SoundCategory.PLAYERS, 1f, 1f); + return false; + } + } + return true; + } public StorageScreen(ServerPlayerEntity player, BlockPos pos, @Nullable Runnable closeCallback) { super(player, closeCallback); @@ -31,30 +61,122 @@ public class StorageScreen extends PagedGui { this.setLockPlayerInventory(false); this.blockEntity = (StorageInterfaceBlockEntity) player.getWorld().getBlockEntity(pos); assert blockEntity != null; + this.network = null; + this.itemStack = ItemStack.EMPTY; + this.world = player.getServerWorld(); + this.radioInterfaceBlockEntity = null; + } + + public StorageScreen(ServerPlayerEntity player, ItemStack itemStack, StorageNetwork storageNetwork, RadioInterfaceBlockEntity radioInterfaceBlockEntity) { + super(player, null); + this.player = player; + this.blockEntity = null; + this.setLockPlayerInventory(false); + this.network = storageNetwork; + this.itemStack = itemStack; + this.world = player.getServerWorld(); + this.radioInterfaceBlockEntity = radioInterfaceBlockEntity; + } + + public StorageNetwork getNetwork() { + if (blockEntity != null) { + blockEntity.enforceNetwork(); + return blockEntity.network; + } + return network; + } + + public boolean getAlphabeticalSorting() { + if (blockEntity == null) { + return itemStack.getOrDefault(WirelessTerminalComponents.SORT_ALPHABETICALLY, false); + } else { + return blockEntity.sortAlphabetically; + } + } + + public void setAlphabeticalSorting(boolean sorting) { + if (blockEntity == null) { + itemStack.set(WirelessTerminalComponents.SORT_ALPHABETICALLY, sorting); + } else { + blockEntity.sortAlphabetically = sorting; + } + } + + public String getQueryString() { + if (blockEntity == null) { + return itemStack.getOrDefault(WirelessTerminalComponents.QUERY_STRING, ""); + } else { + return blockEntity.searchString; + } + } + + public void setQueryString(String queryString) { + if (blockEntity == null) { + itemStack.set(WirelessTerminalComponents.QUERY_STRING, queryString); + } else { + blockEntity.searchString = queryString; + } + } + + public int getPage() { + if (blockEntity == null) { + return itemStack.getOrDefault(WirelessTerminalComponents.PAGE, 0); + } else { + return blockEntity.page; + } + } + + public void setPage(int page) { + if (page > getPageAmount()) { + page = getPageAmount() - 1; + } + if (blockEntity == null) { + itemStack.set(WirelessTerminalComponents.PAGE, page); + } else { + blockEntity.page = page; + } + } + + public void refreshTerminals() { + if (blockEntity == null) { + this.network.sortAlphabetically = getAlphabeticalSorting(); + this.network.searchString = getQueryString(); + getNetwork().reindexNetwork(); + getNetwork().updateDisplays(); + updateDisplay(); + } else { + blockEntity.refreshTerminals(); + } } @Override public boolean open() { - page = blockEntity.page; - this.blockEntity.openStorageScreens.add(this); - blockEntity.updateDisplays(); + page = getPage(); + if (blockEntity == null) { + updateDisplay(); + if (!checkDistance()) { + return false; + } + } else { + blockEntity.openStorageScreens.add(this); + blockEntity.updateDisplays(); + } return super.open(); } @Override public void updateDisplay() { - blockEntity.reindexDrives(); - String title = blockEntity.network.driveUsedSlots + + String title = getNetwork().driveUsedSlots + "u/" + - blockEntity.network.driveTotalSlots + + getNetwork().driveTotalSlots + "t(" + - blockEntity.network.driveFreeSlots + + getNetwork().driveFreeSlots + "f)" + "[" + - blockEntity.network.driveContainerCount + + getNetwork().driveContainerCount + "c]" + "[" + - blockEntity.network.drivesCount + + getNetwork().drivesCount + "d]"; setTitle(Text.of(title)); @@ -63,15 +185,15 @@ public class StorageScreen extends PagedGui { @Override protected int getPageAmount() { - return Math.ceilDivExact(blockEntity.network.filteredItemStackMap.size(), 9 * 5); + return Math.ceilDivExact(getNetwork().filteredItemStackMap.size(), PAGE_SIZE); } @Override protected DisplayElement getElement(int id) { - if (blockEntity.network.filteredItemStackMap.size() > id) { - ItemStack itemStackKey = (ItemStack) blockEntity.network.filteredItemStackMap.keySet().toArray()[id]; + if (getNetwork().filteredItemStackMap.size() > id) { + ItemStack itemStackKey = (ItemStack) getNetwork().filteredItemStackMap.keySet().toArray()[id]; ItemStack aestheticStack = itemStackKey.copy(); - int count = blockEntity.network.filteredItemStackMap.get(itemStackKey); + int count = getNetwork().filteredItemStackMap.get(itemStackKey); aestheticStack.setCount(Math.min(aestheticStack.getMaxCount(), count)); ItemStack newStack = addCountToLore(count, aestheticStack, null); GuiElementBuilder guiElement = new GuiElementBuilder(newStack); @@ -82,12 +204,15 @@ public class StorageScreen extends PagedGui { @Override public boolean onClick(int index, ClickType type, SlotActionType action, GuiElementInterface element) { + if (!checkDistance()) { + return false; + } GuiElementInterface clickedElement = getSlot(index); ItemStack cursorStack = getPlayer().currentScreenHandler.getCursorStack(); if (clickedElement != null && cursorStack.isEmpty()) { ItemStack clickedItem = clickedElement.getItemStack(); ItemStack noLoreStack = removeCountFromLore(clickedItem); - noLoreStack = blockEntity.network.findSimilarStack(noLoreStack); + noLoreStack = getNetwork().findSimilarStack(noLoreStack); if (type.isRight) { if (!type.shift) { noLoreStack.setCount(Math.min(noLoreStack.getMaxCount(), noLoreStack.getCount() / 2)); //half stack @@ -110,11 +235,11 @@ public class StorageScreen extends PagedGui { int insertCount = canInsertItemIntoInventory(playerInventory, noLoreStack); ItemStack insertingStack = noLoreStack.copy(); insertingStack.setCount(insertCount); - blockEntity.refreshTerminals(); - if (blockEntity.network.canRemove(noLoreStack) && insertCount > 0) { + refreshTerminals(); + if (getNetwork().canRemove(noLoreStack) && insertCount > 0) { playerInventory.insertStack(insertingStack.copy()); - blockEntity.network.removeItemStack(insertingStack); - blockEntity.refreshTerminals(); + getNetwork().removeItemStack(insertingStack); + refreshTerminals(); } } } else if (!cursorStack.isEmpty()) { @@ -124,23 +249,29 @@ public class StorageScreen extends PagedGui { } public void insertItem(ItemStack stack) { - int canPutIn = stack.getCount() - blockEntity.network.putItemStackRemainder(stack); + if (!checkDistance()) { + return; + } + int canPutIn = stack.getCount() - getNetwork().putItemStackRemainder(stack); if (canPutIn > 0) { removeFromInventory(player.getInventory(), stack, canPutIn); - blockEntity.refreshTerminals(); + refreshTerminals(); } } @Override public boolean insertItem(ItemStack stack, int startIndex, int endIndex, boolean fromLast) { - blockEntity.refreshTerminals(); + if (!checkDistance()) { + return false; + } + refreshTerminals(); insertItem(stack); return super.insertItem(stack, startIndex, endIndex, fromLast); } @Override protected DisplayElement search() { - String searchString = blockEntity.searchString; + String searchString = getQueryString(); if (searchString == null || searchString.isEmpty() || searchString.equals("*")) { searchString = "Filter not set"; } @@ -151,11 +282,13 @@ public class StorageScreen extends PagedGui { .setSkullOwner(GUI_QUESTION_MARK) .setCallback((x, y, z) -> { playClickSound(getPlayer()); - if (y.isRight) { - doSearch(""); - } else if (y.isLeft) { - SearchScreen searchScreen = new SearchScreen(this, ""); - searchScreen.open(); + if (checkDistance()) { + if (y.isRight) { + doSearch(""); + } else if (y.isLeft) { + SearchScreen searchScreen = new SearchScreen(this, ""); + searchScreen.open(); + } } }) ); @@ -163,6 +296,10 @@ public class StorageScreen extends PagedGui { @Override protected DisplayElement settings() { + if (blockEntity == null) { + WirelessTerminalSelectorScreen wirelessTerminalSelectorScreen = new WirelessTerminalSelectorScreen(this); + return wirelessTerminalSelectorScreen.getItem(); + } SettingsScreen settingsScreen = new SettingsScreen(this); return settingsScreen.getItem(); } @@ -171,17 +308,43 @@ public class StorageScreen extends PagedGui { protected DisplayElement sorting() { return DisplayElement.of( new GuiElementBuilder(Items.PLAYER_HEAD) - .setName(Text.translatable(this.blockEntity.sortAlphabetically ? "A->Z" : "9->1").formatted(Formatting.WHITE)) + .setName(Text.translatable(getAlphabeticalSorting() ? "A->Z" : "9->1").formatted(Formatting.WHITE)) .hideDefaultTooltip().noDefaults() - .setSkullOwner(this.blockEntity.sortAlphabetically ? GUI_A : GUI_1) + .setSkullOwner(getAlphabeticalSorting() ? GUI_A : GUI_1) .setCallback((x, y, z) -> { - this.blockEntity.sortAlphabetically ^= true; playClickSound(getPlayer()); - this.blockEntity.refreshTerminals(); + if (checkDistance()) { + setAlphabeticalSorting(!getAlphabeticalSorting()); + this.refreshTerminals(); + } }) ); } + private int insertIntoPlayer(ItemStack stack, int count, PlayerInventory playerInventory) { + int maxFit = howMuchFits(stack, playerInventory); + int finalCount = Math.min(count, maxFit); + ItemStack insertedStack = stack.copy(); + insertedStack.setCount(finalCount); + getNetwork().removeItemStack(insertedStack); + getNetwork().updateDisplays(); + updateDisplay(); + int remainingToInsert = finalCount; + for (int i = 0; i < Math.ceilDivExact(finalCount, stack.getMaxCount()); i++) { + ItemStack cappedStack = insertedStack.copy(); + cappedStack.setCount(Math.min(insertedStack.getMaxCount(), remainingToInsert)); + + ItemStack remaining = insertStackIntoInventory(playerInventory, cappedStack.copy()); + if (!remaining.isEmpty()) { + ItemStack reverseStack = stack.copy(); + reverseStack.setCount(remaining.getCount() + remainingToInsert); + getNetwork().putItemStackRemainder(reverseStack); + break; + } + remainingToInsert -= cappedStack.getCount(); + } + return count - (finalCount - remainingToInsert); + } @Override protected DisplayElement storeAll() { @@ -192,9 +355,22 @@ public class StorageScreen extends PagedGui { .setSkullOwner(GUI_STORE_ALL) .setCallback((x, y, z) -> { playClickSound(player); - for (int i = 0; i < player.getInventory().main.size(); i++) { - ItemStack stack = player.getInventory().main.get(i); - insertItem(stack, 0, getVirtualSize(), false); + if (checkDistance()) { + if (y.isLeft) { + for (int i = 0; i < player.getInventory().main.size(); i++) { + ItemStack stack = player.getInventory().main.get(i); + insertItem(stack, 0, getVirtualSize(), false); + } + } + if (y.isRight) { + //give to player + for (Map.Entry entry : getNetwork().filteredItemStackMap.entrySet()) { + int leftOver = insertIntoPlayer(entry.getKey(), entry.getValue(), player.getInventory()); + if (leftOver > 0) { + break; + } + } + } } }) ); @@ -202,7 +378,6 @@ public class StorageScreen extends PagedGui { @Override protected DisplayElement crafting() { - World world = blockEntity.getWorld(); if (world != null && world.getGameRules().getBoolean(ServerStorage_Crafting_Enable)) { return DisplayElement.of( new GuiElementBuilder(Items.PLAYER_HEAD) @@ -211,9 +386,11 @@ public class StorageScreen extends PagedGui { .setSkullOwner(GUI_CRAFTING) .setCallback((x, y, z) -> { playClickSound(player); - CraftingScreen craftingScreen = new CraftingScreen(this); - playClickSound(getPlayer()); - craftingScreen.open(); + if (checkDistance()) { + CraftingScreen craftingScreen = new CraftingScreen(this); + playClickSound(getPlayer()); + craftingScreen.open(); + } }) ); } else { @@ -222,9 +399,9 @@ public class StorageScreen extends PagedGui { } public void doSearch(String query) { - this.blockEntity.searchString = query; - this.blockEntity.refreshTerminals(); - this.page = 0; + setQueryString(query); + refreshTerminals(); + setPage(0); } @Override @@ -236,18 +413,22 @@ public class StorageScreen extends PagedGui { .hideDefaultTooltip().noDefaults() .setCallback((x, y, z) -> { playClickSound(player); - this.page = 0; - this.blockEntity.searchString = ""; - this.blockEntity.refreshTerminals(); + if (checkDistance()) { + setPage(0); + setQueryString(""); + refreshTerminals(); + } }) ); } @Override public void onClose() { - this.blockEntity.page = page; - this.blockEntity.markDirty(); - this.blockEntity.openStorageScreens.remove(this); + setPage(page); + if (blockEntity != null) { + this.blockEntity.markDirty(); + this.blockEntity.openStorageScreens.remove(this); + } super.onClose(); } } diff --git a/src/main/java/systems/brn/serverstorage/screens/WirelessTerminalSelectorScreen.java b/src/main/java/systems/brn/serverstorage/screens/WirelessTerminalSelectorScreen.java new file mode 100644 index 0000000..7e6ba55 --- /dev/null +++ b/src/main/java/systems/brn/serverstorage/screens/WirelessTerminalSelectorScreen.java @@ -0,0 +1,156 @@ +package systems.brn.serverstorage.screens; + +import com.mojang.authlib.GameProfile; +import eu.pb4.sgui.api.elements.GuiElementBuilder; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.BlockPos; +import org.jetbrains.annotations.Nullable; +import systems.brn.serverstorage.items.WirelessTerminalItem; +import systems.brn.serverstorage.lib.PagedGui; +import systems.brn.serverstorage.lib.SessionStorageClass; +import systems.brn.serverstorage.lib.Util; +import systems.brn.serverstorage.lib.WirelessTerminalComponents; + +import java.util.ArrayList; +import java.util.List; + +import static systems.brn.serverstorage.ServerStorage.WIRELESS_TERMINAL; +import static systems.brn.serverstorage.items.WirelessTerminalItem.saveStack; + +public class WirelessTerminalSelectorScreen extends PagedGui { + + final public ItemStack stack; + final public ItemStack stackOriginal; + public List sessions; + public int selectedIndex; + public final StorageScreen storageScreen; + + public WirelessTerminalSelectorScreen(ServerPlayerEntity player, @Nullable StorageScreen storageScreen) { + super(player, null); + final ItemStack stackOriginal = player.getStackInHand(player.getActiveHand()); + final ItemStack stack = stackOriginal.copy(); + if (stack.getItem() == WIRELESS_TERMINAL) { + this.stack = stack; + this.stackOriginal = stackOriginal; + this.sessions = new ArrayList<>(stack.getOrDefault(WirelessTerminalComponents.SESSIONS, new ArrayList<>())); + this.selectedIndex = stack.getOrDefault(WirelessTerminalComponents.SELECTED_POSITION, -1); + this.setTitle(Text.translatable("gui.serverstorage.radio_selector")); + this.storageScreen = storageScreen; + this.updateDisplay(); + } else { + this.stack = ItemStack.EMPTY; + this.stackOriginal = stack; + this.sessions = new ArrayList<>(); + this.selectedIndex = -1; + this.storageScreen = storageScreen; + } + } + + public WirelessTerminalSelectorScreen(StorageScreen storageScreen) { + this(storageScreen.getPlayer(), storageScreen); + } + + private void commitStack() { + saveStack(stack, stackOriginal, player); + } + + private void setSelectedPosition() { + if (selectedIndex >= sessions.size()) { + selectedIndex = sessions.size() - 1; + } + stack.set(WirelessTerminalComponents.SELECTED_POSITION, selectedIndex); + commitStack(); + } + + private void removePosition(BlockPos pos) { + this.sessions = Util.removePosition(pos, stack); + setSelectedPosition(); + } + + protected DisplayElement getRadioTerminal(BlockPos position, SessionStorageClass sessionStorageClass, int index) { + if (player != null && player.getServer() != null) { + MinecraftServer server = player.getServer(); + GameProfile gameProfile = sessionStorageClass.getPlayerProfile(server); + + String playerName = gameProfile != null ? gameProfile.getName() : "Profile nonexistent"; + + var builder = new GuiElementBuilder(gameProfile != null ? Items.PLAYER_HEAD : Items.SKELETON_SKULL) + .setName(Text.translatable("gui.serverstorage.radio_entry", index)) + .setSkullOwner(gameProfile, player.getServer()) + .addLoreLine(Text.translatable("gui.serverstorage.radio_position", + position.toShortString(), sessionStorageClass.getWorldKey().getValue().getPath() + .formatted(Formatting.WHITE) + )) + .addLoreLine(Text.translatable("gui.serverstorage.player_management_session_owner", playerName)) + .addLoreLine(Text.translatable("gui.serverstorage.radio_session_click_select")) + .addLoreLine(Text.translatable("gui.serverstorage.radio_session_click_open")) + .addLoreLine(Text.translatable("gui.serverstorage.radio_session_click_delete")) + .setCallback((clickIndex, clickType, slotActionType) -> { + playClickSound(getPlayer()); + if (clickType.isLeft) { + if (clickType.shift) { + removePosition(position); + } else { + boolean success = WirelessTerminalItem.openTerminal(position, player, player.getStackInHand(player.getActiveHand()), sessionStorageClass.getWorld(server)); + if (!success) { + removePosition(position); + } + } + } else if (clickType.isRight) { + this.selectedIndex = index; + setSelectedPosition(); + boolean success = WirelessTerminalItem.openTerminal(position, player, player.getStackInHand(player.getActiveHand()), sessionStorageClass.getWorld(server)); + if (!success) { + removePosition(position); + } + } + updateDisplay(); + }); + + return DisplayElement.of(builder); + } else { + return DisplayElement.empty(); + } + } + + @Override + protected int getPageAmount() { + return sessions.size() / PAGE_SIZE; + } + + @Override + protected DisplayElement getElement(int id) { + if (id < sessions.size()) { + SessionStorageClass sessionStorageClass = sessions.get(id); + return getRadioTerminal(sessionStorageClass.getTerminalPos(), sessionStorageClass, id); + } + return DisplayElement.empty(); + } + + @Override + public void onClose() { + super.onClose(); + WirelessTerminalItem.updateLore(stack, player.getServer()); + if (storageScreen != null) { + storageScreen.open(); + } + } + + public DisplayElement getItem() { + return DisplayElement.of( + new GuiElementBuilder(Items.PLAYER_HEAD) + .setName(Text.translatable("mco.configure.world.settings.title").formatted(Formatting.WHITE)) + .hideDefaultTooltip().noDefaults() + .setSkullOwner(GUI_SETTINGS) + .setCallback((x, y, z) -> { + playClickSound(getPlayer()); + this.open(); + }) + ); + } +} diff --git a/src/main/resources/assets/serverstorage/lang/en_us.json b/src/main/resources/assets/serverstorage/lang/en_us.json index edd2c5d..be1c13a 100644 --- a/src/main/resources/assets/serverstorage/lang/en_us.json +++ b/src/main/resources/assets/serverstorage/lang/en_us.json @@ -1,51 +1,84 @@ { - "block.serverstorage.storage": "Networked storage interface", + "block.serverstorage.storage": "Networked Storage Interface", - "block.serverstorage.inventory_interface": "Networked inventory interface", + "block.serverstorage.inventory_interface": "Networked Inventory Interface", - "block.serverstorage.drive_container": "Hard drive container", + "block.serverstorage.drive_container": "Hard Drive Container", - "block.serverstorage.bus_connector": "Storage network connector", + "block.serverstorage.bus_connector": "Storage Network Connector", - "item.serverstorage.iron_drive": "Iron hard drive", - "item.serverstorage.iron_head": "Iron hard drive head", - "item.serverstorage.iron_platter": "Iron hard drive platter", + "block.serverstorage.radio_interface": "Networked Radio Interface", - "item.serverstorage.golden_drive": "Golden hard drive", - "item.serverstorage.golden_head": "Golden hard drive head", - "item.serverstorage.golden_platter": "Golden hard drive platter", + "item.serverstorage.iron_drive": "Iron Hard Drive", + "item.serverstorage.iron_head": "Iron Hard Drive Head", + "item.serverstorage.iron_platter": "Iron Hard Drive Platter", - "item.serverstorage.diamond_drive": "Diamond hard drive", - "item.serverstorage.diamond_head": "Diamond hard drive head", - "item.serverstorage.diamond_platter": "Diamond hard drive platter", + "item.serverstorage.golden_drive": "Golden Hard Drive", + "item.serverstorage.golden_head": "Golden Hard Drive Head", + "item.serverstorage.golden_platter": "Golden Hard Drive Platter", - "item.serverstorage.netherite_drive": "Netherite hard drive", - "item.serverstorage.netherite_head": "Netherite hard drive head", - "item.serverstorage.netherite_platter": "Netherite hard drive platter", + "item.serverstorage.diamond_drive": "Diamond Hard Drive", + "item.serverstorage.diamond_head": "Diamond Hard Drive Head", + "item.serverstorage.diamond_platter": "Diamond Hard Drive Platter", - "item.serverstorage.module_bus": "Bus module", - "item.serverstorage.module_configuration": "Configuration module", - "item.serverstorage.module_container": "Container module", - "item.serverstorage.module_display": "Display module", - "item.serverstorage.module_drive": "Drive module", - "item.serverstorage.module_filtering": "Filtering module", - "item.serverstorage.module_inventory": "Inventory module", - "item.serverstorage.module_pagination": "Pagination module", - "item.serverstorage.module_transport": "Transport module", - "item.serverstorage.module_netherite_upgrade": "Netherite upgrade module", + "item.serverstorage.netherite_drive": "Netherite Hard Drive", + "item.serverstorage.netherite_head": "Netherite Hard Drive Head", + "item.serverstorage.netherite_platter": "Netherite Hard Drive Platter", + + "item.serverstorage.module_bus": "Bus Module", + "item.serverstorage.module_configuration": "Configuration Module", + "item.serverstorage.module_container": "Container Module", + "item.serverstorage.module_display": "Display Module", + "item.serverstorage.module_drive": "Drive Module", + "item.serverstorage.module_filtering": "Filtering Module", + "item.serverstorage.module_inventory": "Inventory Module", + "item.serverstorage.module_pagination": "Pagination Module", + "item.serverstorage.module_transport": "Transport Module", + "item.serverstorage.module_netherite_upgrade": "Netherite Upgrade Module", "item.serverstorage.module_pcb": "Module PCB", - "item.serverstorage.material_drive_casing": "Hard drive casing", - "item.serverstorage.material_drive_controller": "Drive controller", + "item.serverstorage.material_drive_casing": "Hard Drive Casing", + "item.serverstorage.material_drive_controller": "Drive Controller", "item.serverstorage.material_cpu": "Central Processing Unit", - "item.serverstorage.material_cpu_substrate": "CPU substrate", + "item.serverstorage.material_cpu_substrate": "CPU Substrate", "item.serverstorage.material_pcb": "Printed Circuit Board", - "item.serverstorage.material_pcb_substrate": "PCB substrate", + "item.serverstorage.material_pcb_substrate": "PCB Substrate", + "item.serverstorage.iron_antenna": "Iron Antenna", + "item.serverstorage.golden_antenna": "Golden Antenna", + "item.serverstorage.diamond_antenna": "Diamond Antenna", + "item.serverstorage.netherite_antenna": "Netherite Antenna", + + "item.serverstorage.wireless_terminal": "Wireless terminal", "gui.serverstorage.store_all": "Store all items from inventory", + "gui.serverstorage.player_management": "Player management", + "gui.serverstorage.player_management_session": "Session %d", + "gui.serverstorage.player_management_session_owner": "Owned by: %s", + "gui.serverstorage.player_management_session_owner_error": "Not owned", + "gui.serverstorage.player_management_session_key": "Session key: %s", + + "gui.serverstorage.wireless_terminal_link_count": "Linked to %d devices", + "gui.serverstorage.wireless_terminal_link_index": "Current link index is %d", + "gui.serverstorage.wireless_terminal_page": "Page: %d", + "gui.serverstorage.wireless_terminal_search_query": "Search query: %s", + "gui.serverstorage.wireless_terminal_sorting_alphabetically": "Sorting alphabetically", + "gui.serverstorage.wireless_terminal_sorting_numerically": "Sorting numerically", + "gui.serverstorage.antenna_range": "Range: %d blocks", + "gui.serverstorage.player_management_session_click_deauthorize": "Click to deauthorize", + "gui.serverstorage.radio_selector": "Radio selector", + "gui.serverstorage.radio_entry": "Radio %d", + "gui.serverstorage.radio_connected": "Connected to radio at %s in %s from %s in %s, distance %d/%d", + "gui.serverstorage.radio_unauthorized": "Session unauthorized in radio at %s in %s", + "gui.serverstorage.radio_out_of_range": "Radio out of range at %s in %s from %s in %s, distance %d/%d", + "gui.serverstorage.radio_not_found": "Radio not found at %s in %s from %s in %s", + "gui.serverstorage.radio_position": "Placed at %s in %s", + "gui.serverstorage.radio_position_error": "Not Placed", + "gui.serverstorage.radio_session_click_select": "Left click to connect", + "gui.serverstorage.radio_session_click_open": "Right click to select", + "gui.serverstorage.radio_session_click_delete": "Shift Left click to remove", "gui.serverstorage.filter": "Filter", "gui.serverstorage.sort_alphabetically": "Sort alphabetically", "gui.serverstorage.sort_descending": "Sort by count descending", @@ -58,9 +91,9 @@ "gui.serverstorage.direction_up": "Up", "gui.serverstorage.direction_down": "Down", - "serverstorage.groups.blocks" : "Serverstorage blocks", - "serverstorage.groups.materials" : "Serverstorage materials", - "serverstorage.groups.drives" : "Serverstorage drives", + "serverstorage.groups.blocks" : "Serverstorage Blocks", + "serverstorage.groups.materials" : "Serverstorage Materials", + "serverstorage.groups.drives" : "Serverstorage Drives", "message.serverstorage.block_disabled": "This block was disabled in a gamerule, contact admins" } \ No newline at end of file