diff options
Diffstat (limited to 'src/main')
19 files changed, 1796 insertions, 3 deletions
diff --git a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java index 681e24f3..83f41c0b 100644 --- a/src/main/java/de/hysky/skyblocker/SkyblockerMod.java +++ b/src/main/java/de/hysky/skyblocker/SkyblockerMod.java @@ -6,6 +6,7 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.debug.Debug; import de.hysky.skyblocker.skyblock.*; import de.hysky.skyblocker.skyblock.dungeon.*; +import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.dungeon.puzzle.CreeperBeams; import de.hysky.skyblocker.skyblock.dungeon.puzzle.DungeonBlaze; import de.hysky.skyblocker.skyblock.dungeon.puzzle.TicTacToe; @@ -108,6 +109,7 @@ public class SkyblockerMod implements ClientModInitializer { DungeonBlaze.init(); Waterboard.init(); DungeonScore.init(); + PartyFinderScreen.initClass(); ChestValue.init(); FireFreezeStaffTimer.init(); GuardianHealth.init(); diff --git a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java index 609e7c2f..2eddea23 100644 --- a/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/SkyblockerConfig.java @@ -156,6 +156,9 @@ public class SkyblockerConfig { public boolean acceptReparty = true; @SerialEntry + public boolean betterPartyFinder = true; + + @SerialEntry public boolean backpackPreviewWithoutShift = false; @SerialEntry diff --git a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java index 3b9cbe60..406dd885 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/GeneralCategory.java @@ -35,6 +35,13 @@ public class GeneralCategory { .controller(ConfigUtils::createBooleanController) .build()) .option(Option.<Boolean>createBuilder() + .name(Text.translatable("text.autoconfig.skyblocker.option.general.betterPartyFinder")) + .binding(defaults.general.betterPartyFinder, + () -> config.general.betterPartyFinder, + newValue -> config.general.betterPartyFinder = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.<Boolean>createBuilder() .name(Text.translatable("text.autoconfig.skyblocker.option.general.backpackPreviewWithoutShift")) .binding(defaults.general.backpackPreviewWithoutShift, () -> config.general.backpackPreviewWithoutShift, diff --git a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java index 4abadcea..dd207dc0 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/ClientPlayerEntityMixin.java @@ -2,14 +2,19 @@ package de.hysky.skyblocker.mixin; import com.mojang.authlib.GameProfile; +import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; import de.hysky.skyblocker.skyblock.item.HotbarSlotLock; import de.hysky.skyblocker.skyblock.item.ItemProtection; import de.hysky.skyblocker.skyblock.rift.HealingMelonIndicator; import de.hysky.skyblocker.utils.Utils; +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.AbstractClientPlayerEntity; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.world.ClientWorld; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -17,6 +22,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(ClientPlayerEntity.class) public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity { + @Shadow @Final protected MinecraftClient client; + public ClientPlayerEntityMixin(ClientWorld world, GameProfile profile) { super(world, profile); } @@ -33,4 +40,15 @@ public abstract class ClientPlayerEntityMixin extends AbstractClientPlayerEntity public void skyblocker$updateHealth(CallbackInfo ci) { HealingMelonIndicator.updateHealth(); } + + @Inject(method = "openEditSignScreen", at = @At("HEAD"), cancellable = true) + public void skyblocker$partyFinderRange(SignBlockEntity sign, boolean front, CallbackInfo callbackInfo) { + if (PartyFinderScreen.isInKuudraPartyFinder) return; + if (client.currentScreen instanceof PartyFinderScreen partyFinderScreen && !partyFinderScreen.isAborted()) { + if (sign.getText(front).getMessage(3, false).getString().toLowerCase().contains("level")) { + partyFinderScreen.updateSign(sign, front); + callbackInfo.cancel(); + } + } + } }
\ No newline at end of file diff --git a/src/main/java/de/hysky/skyblocker/mixin/GenericContainerScreenHandlerMixin.java b/src/main/java/de/hysky/skyblocker/mixin/GenericContainerScreenHandlerMixin.java index 2608b69f..a7843ba2 100644 --- a/src/main/java/de/hysky/skyblocker/mixin/GenericContainerScreenHandlerMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixin/GenericContainerScreenHandlerMixin.java @@ -1,6 +1,8 @@ package de.hysky.skyblocker.mixin; import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; +import net.minecraft.client.MinecraftClient; import net.minecraft.item.ItemStack; import net.minecraft.screen.GenericContainerScreenHandler; import net.minecraft.screen.ScreenHandler; @@ -20,11 +22,17 @@ public abstract class GenericContainerScreenHandlerMixin extends ScreenHandler { public void setStackInSlot(int slot, int revision, ItemStack stack) { super.setStackInSlot(slot, revision, stack); SkyblockerMod.getInstance().containerSolverManager.markDirty(); + if (MinecraftClient.getInstance().currentScreen instanceof PartyFinderScreen screen) { + screen.markDirty(); + } } @Override public void updateSlotStacks(int revision, List<ItemStack> stacks, ItemStack cursorStack) { super.updateSlotStacks(revision, stacks, cursorStack); SkyblockerMod.getInstance().containerSolverManager.markDirty(); + if (MinecraftClient.getInstance().currentScreen instanceof PartyFinderScreen screen) { + screen.markDirty(); + } } } diff --git a/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java new file mode 100644 index 00000000..94eb53a5 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/HandledScreenProviderMixin.java @@ -0,0 +1,47 @@ +package de.hysky.skyblocker.mixin; + + +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.skyblock.dungeon.partyfinder.PartyFinderScreen; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.ingame.HandledScreens; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(HandledScreens.Provider.class) +public interface HandledScreenProviderMixin<T extends ScreenHandler> { + @Inject(method = "open", at = @At("HEAD"), cancellable = true) + default void skyblocker$open(Text name, ScreenHandlerType<T> type, MinecraftClient client, int id, CallbackInfo ci) { + if (!SkyblockerConfigManager.get().general.betterPartyFinder) return; + ClientPlayerEntity player = client.player; + if (player == null) return; + T screenHandler = type.create(id, player.getInventory()); + if (screenHandler instanceof GenericContainerScreenHandler containerScreenHandler && PartyFinderScreen.possibleInventoryNames.contains(name.getString().toLowerCase())) { + if (client.currentScreen != null) { + String lowerCase = client.currentScreen.getTitle().getString().toLowerCase(); + if (lowerCase.contains("group builder")) return; + if (lowerCase.contains("select tier")) { + PartyFinderScreen.isInKuudraPartyFinder = true; + } else if (lowerCase.contains("catacombs")) { + PartyFinderScreen.isInKuudraPartyFinder = false; + } + } + if (PartyFinderScreen.isInKuudraPartyFinder) return; + client.player.currentScreenHandler = containerScreenHandler; + if (client.currentScreen instanceof PartyFinderScreen screen) { + screen.updateHandler(containerScreenHandler, name); + } else { + client.setScreen(new PartyFinderScreen(containerScreenHandler, player.getInventory(), name)); + } + + ci.cancel(); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/mixin/accessor/SkullBlockEntityAccessor.java b/src/main/java/de/hysky/skyblocker/mixin/accessor/SkullBlockEntityAccessor.java new file mode 100644 index 00000000..dfe544bc --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixin/accessor/SkullBlockEntityAccessor.java @@ -0,0 +1,17 @@ +package de.hysky.skyblocker.mixin.accessor; + +import com.mojang.authlib.GameProfile; +import net.minecraft.block.entity.SkullBlockEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +@Mixin(SkullBlockEntity.class) +public interface SkullBlockEntityAccessor { + @Invoker + static CompletableFuture<Optional<GameProfile>> invokeFetchProfile(String name) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/FinderSettingsContainer.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/FinderSettingsContainer.java new file mode 100644 index 00000000..0a048775 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/FinderSettingsContainer.java @@ -0,0 +1,282 @@ +package de.hysky.skyblocker.skyblock.dungeon.partyfinder; + +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.ContainerWidget; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.Text; + +import java.util.ArrayList; +import java.util.List; + +public class FinderSettingsContainer extends ContainerWidget { + private boolean isInitialized = false; + private OptionDropdownWidget floorSelector; + private OptionDropdownWidget dungeonTypeSelector; + private OptionDropdownWidget sortGroupsSelector; + + private RangedValueWidget classLevelRange; + private RangedValueWidget dungeonLevelRange; + + private ContainerWidget currentlyOpenedOption = null; + + private final List<ContainerWidget> initializedWidgets = new ArrayList<>(); + + + public FinderSettingsContainer(int x, int y, int height) { + super(x, y, 336, height, Text.empty()); + } + + @Override + public void setDimensionsAndPosition(int width, int height, int x, int y) { + super.setDimensionsAndPosition(width, height, x, y); + if (this.floorSelector != null) floorSelector.setPosition(x + width / 4 - 70, y + 20); + if (this.dungeonTypeSelector != null) dungeonTypeSelector.setPosition(x + 3 * width / 4 - 70, y + 20); + if (this.sortGroupsSelector != null) sortGroupsSelector.setPosition(x + width / 2 - 70, y + 120); + if (this.classLevelRange != null) classLevelRange.setPosition(x + width / 4 - 50, y + 70); + if (this.dungeonLevelRange != null) dungeonLevelRange.setPosition(x + 3 * width / 4 - 50, y + 70); + + } + + /** + * Handles everything in the Settings page + * @param screen the parent Party Finder screen + * @param inventoryName le inventory name + * @return returns false if it doesn't know what's happening + */ + public boolean handle(PartyFinderScreen screen, String inventoryName) { + String nameLowerCase = inventoryName.toLowerCase(); + GenericContainerScreenHandler handler = screen.getHandler(); + if (!isInitialized) { + if (!nameLowerCase.contains("search settings")) return false; + isInitialized = true; + //System.out.println("initializing"); + for (Slot slot : handler.slots) { + if (slot.id > handler.getRows() * 9 - 1) break; + if (!slot.hasStack()) continue; + ItemStack stack = slot.getStack(); + //System.out.println(stack.toString()); + String name = stack.getName().getString().toLowerCase(); + if (name.contains("floor")) { + + //System.out.println("Floor selector created"); + this.floorSelector = new OptionDropdownWidget(screen, stack.getName(), null, getX() + getWidth() / 4 - 70, getY() + 20, 140, 170, slot.id); + if (!setSelectedElementFromTooltip(slot, stack, floorSelector)) return false; + + initializedWidgets.add(floorSelector); + + } else if (name.contains("dungeon type")) { + + this.dungeonTypeSelector = new OptionDropdownWidget(screen, stack.getName(), null, getX() + (3 * getWidth()) / 4 - 70, getY() + 20, 140, 100, slot.id); + if (!setSelectedElementFromTooltip(slot, stack, dungeonTypeSelector)) return false; + + initializedWidgets.add(dungeonTypeSelector); + + } else if (name.contains("groups")) { + + this.sortGroupsSelector = new OptionDropdownWidget(screen, stack.getName(), null, getX() + getWidth() / 2 - 70, getY() + 120, 140, 100, slot.id); + if (!setSelectedElementFromTooltip(slot, stack, sortGroupsSelector)) return false; + + initializedWidgets.add(sortGroupsSelector); + + } else if (name.contains("class level")) { + + this.classLevelRange = new RangedValueWidget(screen, stack.getName(), getX() + getWidth() / 4 - 50, getY() + 70, 100, slot.id); + if (!setRangeFromTooltip(stack, classLevelRange)) return false; + + initializedWidgets.add(classLevelRange); + + } else if (name.contains("dungeon level")) { + + this.dungeonLevelRange = new RangedValueWidget(screen, stack.getName(), getX() + 3 * (getWidth()) / 4 - 50, getY() + 70, 100, slot.id); + if (!setRangeFromTooltip(stack, dungeonLevelRange)) return false; + + initializedWidgets.add(dungeonLevelRange); + + } + } + } + if (nameLowerCase.contains("search settings")) { + if (floorSelector != null) floorSelector.close(); + if (dungeonTypeSelector != null) dungeonTypeSelector.close(); + if (sortGroupsSelector != null) sortGroupsSelector.close(); + if (classLevelRange != null) classLevelRange.setState(RangedValueWidget.State.CLOSED); + if (dungeonLevelRange != null) dungeonLevelRange.setState(RangedValueWidget.State.CLOSED); + + screen.partyFinderButton.active = true; + currentlyOpenedOption = null; + + for (int i = (handler.getRows() - 1) * 9; i < handler.getRows() * 9; i++) { + Slot slot = handler.slots.get(i); + if (slot.hasStack() && slot.getStack().isOf(Items.ARROW)) { + screen.partyButtonSlotId = slot.id; + } + } + return true; + } else { + screen.partyFinderButton.active = false; + + if (nameLowerCase.contains("floor")) { + updateDropdownOptionWidget(handler, floorSelector); + currentlyOpenedOption = floorSelector; + return true; + } else if (nameLowerCase.contains("select type")) { + updateDropdownOptionWidget(handler, dungeonTypeSelector); + currentlyOpenedOption = dungeonTypeSelector; + return true; + } else if (nameLowerCase.contains("class level range")) { + updateRangedValue(handler, classLevelRange); + return true; + } else if (nameLowerCase.contains("dungeon level range")) { + updateRangedValue(handler, dungeonLevelRange); + return true; + } else if (nameLowerCase.contains("sort")) { + updateDropdownOptionWidget(handler, sortGroupsSelector); + currentlyOpenedOption = sortGroupsSelector; + return true; + } + } + return false; + } + + private int findBackSlotId(GenericContainerScreenHandler handler) { + int backId = -1; + for (int i = (handler.getRows() - 1) * 9; i < handler.getRows() * 9; i++) { + Slot slot = handler.slots.get(i); + if (slot.hasStack() && slot.getStack().isOf(Items.ARROW)) { + backId = slot.id; + break; + } + } + return backId; + } + + /** + * @return true if all goes well + */ + private boolean setRangeFromTooltip(ItemStack stack, RangedValueWidget widget) { + for (Text text : stack.getTooltip(null, TooltipContext.BASIC)) { + String textLowerCase = text.getString().toLowerCase(); + if (textLowerCase.contains("selected:")) { + String[] split = text.getString().split(":"); + if (split.length < 2) return false; + String[] minAndMax = split[1].split("-"); + if (minAndMax.length < 2) return false; + //System.out.println(textLowerCase); + //System.out.println("Min and max: " + minAndMax[0] + " " + minAndMax[1]); + int leMin = -1; + int leMax = -1; + try {leMin = Integer.parseInt(minAndMax[0].trim());} catch (NumberFormatException ignored) {} + try {leMax = Integer.parseInt(minAndMax[1].trim());} catch (NumberFormatException ignored) {} + + widget.setMinAndMax(leMin, leMax); + return true; + } + } + return false; + } + + /** + * @return true if all goes well + */ + private boolean setSelectedElementFromTooltip(Slot slot, ItemStack stack, OptionDropdownWidget dropdownWidget) { + for (Text text : stack.getTooltip(null, TooltipContext.BASIC)) { + String textLowerCase = text.getString().toLowerCase(); + if (textLowerCase.contains("selected:")) { + String[] split = text.getString().split(":"); + if (split.length < 2) return false; + String floorName = split[1].trim(); + dropdownWidget.setSelectedOption(dropdownWidget.new Option(floorName, stack, slot.id)); + return true; + } + } + return false; + } + + public boolean handleSign(SignBlockEntity sign, boolean front) { + if (!isInitialized) return false; + if (currentlyOpenedOption == classLevelRange) { + return updateValues(sign, front, classLevelRange); + } else if (currentlyOpenedOption == dungeonLevelRange) { + return updateValues(sign, front, dungeonLevelRange); + } + return false; + } + + private boolean updateValues(SignBlockEntity sign, boolean front, RangedValueWidget valueWidget) { + RangedValueWidget.State state; + String lowerCase = sign.getText(front).getMessage(3, false).getString().toLowerCase(); + if (lowerCase.contains("max")) { + state = RangedValueWidget.State.MODIFYING_MAX; + } else if (lowerCase.contains("min")) { + state = RangedValueWidget.State.MODIFYING_MIN; + } else return false; + valueWidget.setState(state); + this.setFocused(valueWidget); + return true; + } + + private void updateDropdownOptionWidget(GenericContainerScreenHandler handler, OptionDropdownWidget dropdownWidget) { + List<OptionDropdownWidget.Option> entries = new ArrayList<>(); + for (Slot slot : handler.slots) { + if (slot.id > (handler.getRows() - 1) * 9 - 1) break; + if (slot.hasStack() && !slot.getStack().isOf(Items.BLACK_STAINED_GLASS_PANE)) { + entries.add(dropdownWidget.new Option(slot.getStack().getName().getString(), slot.getStack(), slot.id)); + } + } + int backId = findBackSlotId(handler); + dropdownWidget.open(entries, backId); + } + + private void updateRangedValue(GenericContainerScreenHandler handler, RangedValueWidget valueWidget) { + currentlyOpenedOption = valueWidget; + int min = -1; + int max = -1; + for (Slot slot : handler.slots) { + if (slot.id > (handler.getRows() - 1) * 9 - 1) break; + if (slot.hasStack() && slot.getStack().getName().getString().toLowerCase().contains("min")) { + min = slot.id; + } else if (slot.hasStack() && slot.getStack().getName().getString().toLowerCase().contains("max")) { + max = slot.id; + } + } + int backId = findBackSlotId(handler); + + valueWidget.setStateAndSlots(RangedValueWidget.State.OPEN, min, max, backId); + } + + public void setVisible(boolean visible) { + this.visible = visible; + if (floorSelector != null) this.floorSelector.visible = visible; + if (dungeonTypeSelector != null) this.dungeonTypeSelector.visible = visible; + if (classLevelRange != null) this.classLevelRange.visible = visible; + if (dungeonLevelRange != null) this.dungeonLevelRange.visible = visible; + if (sortGroupsSelector != null) this.sortGroupsSelector.visible = visible; + } + + public boolean canInteract(ContainerWidget widget) { + return currentlyOpenedOption == null || currentlyOpenedOption == widget; + } + + @Override + protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + if (!visible) return; + for (ContainerWidget initializedWidget : initializedWidgets) { + initializedWidget.render(context, mouseX, mouseY, delta); + } + } + + @Override + public List<? extends Element> children() { + return initializedWidgets; + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) {} +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/OptionDropdownWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/OptionDropdownWidget.java new file mode 100644 index 00000000..64e45283 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/OptionDropdownWidget.java @@ -0,0 +1,204 @@ +package de.hysky.skyblocker.skyblock.dungeon.partyfinder; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class OptionDropdownWidget extends ElementListWidget<OptionDropdownWidget.Option> { + private final int slotId; + private int backButtonId = -1; + private final Text name; + private @Nullable Option selectedOption; + protected final PartyFinderScreen screen; + private boolean isOpen = false; + + private float animationProgress = 0f; + + public OptionDropdownWidget(PartyFinderScreen screen, Text name, @Nullable Option selectedOption, int x, int y, int width, int height, int slotId) { + super(screen.getClient(), width, height, y, 15); + this.screen = screen; + this.slotId = slotId; + setX(x); + setRenderBackground(false); + setRenderHeader(true, 25); + this.name = name; + this.selectedOption = selectedOption; + } + + @Override + protected boolean clickedHeader(int x, int y) { + if (!(x >= 0 && y >= 10 && x < getWidth() && y < 26)) return false; + if (screen.isWaitingForServer()) return false; + if (isOpen) { + if (backButtonId != -1) screen.clickAndWaitForServer(backButtonId); + } else { + screen.clickAndWaitForServer(slotId); + screen.partyFinderButton.active = false; + } + animationProgress = 0f; + return true; + } + + @Override + public int getRowLeft() { + return getX() + 2; + } + + @Override + protected int getScrollbarPositionX() { + return getRowLeft() + getRowWidth(); + } + + @Override + public int getRowWidth() { + return getWidth() - 6; + } + + public void setSelectedOption(@NotNull OptionDropdownWidget.Option entry) { + selectedOption = entry; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (!screen.getSettingsContainer().canInteract(this)) return false; + if (isOpen && !isMouseOver(mouseX, mouseY) && backButtonId != -1) { + screen.clickAndWaitForServer(backButtonId); + return true; + } + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (screen.getSettingsContainer().canInteract(this)) return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + return false; + } + + @Override + protected void renderHeader(DrawContext context, int x, int y) { + context.drawText(MinecraftClient.getInstance().textRenderer, name, x, y + 1, 0xFFD0D0D0, false); + int offset = 10; + context.fill(x - 2, y + offset, x - 3 + getWidth(), y + 15 + offset, 0xFFF0F0F0); + context.fill(x - 1, y + 1 + offset, x - 3 + getWidth() - 1, y + 14 + offset, 0xFF000000); + if (selectedOption != null) { + context.drawText(MinecraftClient.getInstance().textRenderer, selectedOption.message, x + 2, y + 3 + offset, 0xFFFFFFFF, true); + } + else context.drawText(MinecraftClient.getInstance().textRenderer, "???", x + 2, y + 3 + offset, 0xFFFFFFFF, true); + } + + @Override + public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + MatrixStack matrices = context.getMatrices(); + if (isOpen) { + matrices.push(); + matrices.translate(0, 0, 100); + } + if (animationProgress < 1) animationProgress += delta * 0.5f; + else if (animationProgress != 1) animationProgress = 1; + if (PartyFinderScreen.DEBUG) { + context.drawText(MinecraftClient.getInstance().textRenderer, String.valueOf(slotId), getX(), getY() - 10, 0xFFFF0000, true); + context.drawText(MinecraftClient.getInstance().textRenderer, String.valueOf(backButtonId), getX() + 50, getY() - 10, 0xFFFF0000, true); + } + + int height1 = Math.min(getHeight(), getEntryCount() * itemHeight + 4); + int idk = isOpen ? (int) (height1 * animationProgress) : (int) (height1 * (1 - animationProgress)); + context.fill(getX(), getY() + headerHeight, getX() + getWidth() - 1, getY() + idk + headerHeight, 0xFFE0E0E0); + context.fill(getX() + 1, getY() + headerHeight + 1, getX() + getWidth() - 2, getY() + idk + headerHeight - 1, 0xFF000000); + + super.renderWidget(context, mouseX, mouseY, delta); + if (isOpen) { + matrices.pop(); + } + } + + public void open(List<Option> entries, int backButtonId) { + isOpen = true; + this.replaceEntries(entries); + animationProgress = 0f; + this.backButtonId = backButtonId; + } + + public void close() { + isOpen = false; + this.clearEntries(); + + } + + public class Option extends ElementListWidget.Entry<Option> { + + private final String message; + private final ItemStack icon; + private final int optionSlotId; + + public Option(@NotNull String message, @Nullable ItemStack icon, int slotId) { + + this.message = message; + this.icon = icon; + this.optionSlotId = slotId; + } + + + @Override + public List<? extends Selectable> selectableChildren() { + return List.of(); + } + + @Override + public List<? extends Element> children() { + return List.of(); + } + + @Override + public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) { + /*if (hovered) { + context.fill(x, y, x + entryWidth, y + 13, 0xFFF0F0F0); + context.fill(x+1, y+1, x + entryWidth-1, y + 12, 0xFF000000); + } else context.fill(x, y, x + entryWidth, y + 13, 0xFF000000);*/ + MatrixStack matrices = context.getMatrices(); + matrices.push(); + int iconY = y + 1; + matrices.translate(x, iconY, 0); + matrices.scale(0.8f, 0.8f, 1f); + matrices.translate(-x, -iconY, 0); + context.drawItem(icon, x, iconY); + matrices.pop(); + if (PartyFinderScreen.DEBUG) context.drawText(MinecraftClient.getInstance().textRenderer, String.valueOf(optionSlotId), x + 8, y, 0xFFFF0000, true); + context.drawText(MinecraftClient.getInstance().textRenderer, Text.literal(message).fillStyle(Style.EMPTY.withUnderline(hovered)), x + 14, y + 3, 0xFFFFFFFF, false); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Option that = (Option) o; + + return message.equals(that.message); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (screen.isWaitingForServer()) return false; + if (button == 0) { + screen.clickAndWaitForServer(this.optionSlotId); + setSelectedOption(this); + } + return true; + } + + @Override + public int hashCode() { + return message.hashCode(); + } + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntry.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntry.java new file mode 100644 index 00000000..b53047d8 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/partyfinder/PartyEntry.java @@ -0,0 +1,322 @@ +package de.hysky.skyblocker.skyblock.dungeon.partyfinder; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.mixin.accessor.SkullBlockEntityAccessor; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.Element; +import net.minecraft.client.gui.PlayerSkinDrawer; +import net.minecraft.client.gui.Selectable; +import net.minecraft.client.gui.widget.ElementListWidget; +import net.minecraft.client.util.DefaultSkinHelper; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.StringNbtReader; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text. |
