aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorvicisacat <victor.branchu@gmail.com>2024-04-23 13:51:45 +0200
committerviciscat <51047087+viciscat@users.noreply.github.com>2024-06-02 13:26:45 +0200
commitc645892f94f9017b3685733c04520c47beedfed9 (patch)
tree6350476d0d7c137008922a956cd39e6eb26c7a96 /src
parent84ffa6d5f466a52b7927070447f71c816bcc6c94 (diff)
downloadSkyblocker-c645892f94f9017b3685733c04520c47beedfed9.tar.gz
Skyblocker-c645892f94f9017b3685733c04520c47beedfed9.tar.bz2
Skyblocker-c645892f94f9017b3685733c04520c47beedfed9.zip
upcoming events tab!!! so cool
Diffstat (limited to 'src')
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java28
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java8
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java2
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListTab.java89
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java128
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java15
-rw-r--r--src/main/java/de/hysky/skyblocker/skyblock/itemlist/UpcomingEventsTab.java168
-rw-r--r--src/main/java/de/hysky/skyblocker/utils/render/gui/SideTabButtonWidget.java39
8 files changed, 400 insertions, 77 deletions
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java
index 02dbc132..a0b5f0b9 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/auction/widgets/CategoryTabWidget.java
@@ -1,42 +1,26 @@
package de.hysky.skyblocker.skyblock.auction.widgets;
import de.hysky.skyblocker.skyblock.auction.SlotClickHandler;
+import de.hysky.skyblocker.utils.render.gui.SideTabButtonWidget;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
-import net.minecraft.client.gui.screen.ButtonTextures;
-import net.minecraft.client.gui.widget.ToggleButtonWidget;
import net.minecraft.client.item.TooltipType;
import net.minecraft.item.Item.TooltipContext;
import net.minecraft.item.ItemStack;
-import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
-public class CategoryTabWidget extends ToggleButtonWidget {
- private static final ButtonTextures TEXTURES = new ButtonTextures(new Identifier("recipe_book/tab"), new Identifier("recipe_book/tab_selected"));
-
- public void setIcon(@NotNull ItemStack icon) {
- this.icon = icon.copy();
- }
-
- private @NotNull ItemStack icon;
+public class CategoryTabWidget extends SideTabButtonWidget {
private final SlotClickHandler slotClick;
private int slotId = -1;
public CategoryTabWidget(@NotNull ItemStack icon, SlotClickHandler slotClick) {
- super(0, 0, 35, 27, false);
- this.icon = icon.copy(); // copy prevents item disappearing on click
+ super(0, 0, false, icon);
this.slotClick = slotClick;
- setTextures(TEXTURES);
}
@Override
public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
- if (textures == null) return;
- Identifier identifier = textures.get(true, this.toggled);
- int x = getX();
- if (toggled) x -= 2;
- context.drawGuiTexture(identifier, x, this.getY(), this.width, this.height);
- context.drawItem(icon, x + 9, getY() + 5);
+ super.renderWidget(context, mouseX, mouseY, delta);
if (isMouseOver(mouseX, mouseY)) {
context.getMatrices().push();
@@ -52,8 +36,8 @@ public class CategoryTabWidget extends ToggleButtonWidget {
@Override
public void onClick(double mouseX, double mouseY) {
- if (this.toggled || slotId == -1) return;
+ if (isToggled() || slotId == -1) return;
+ super.onClick(mouseX, mouseY);
slotClick.click(slotId);
- this.setToggled(true);
}
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java
index ad85e7da..d2f99040 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/events/EventNotifications.java
@@ -28,13 +28,15 @@ public class EventNotifications {
private static long currentTime = System.currentTimeMillis() / 1000;
+ public static final String JACOBS = "Jacob's Farming Contest";
+
public static final Map<String, ItemStack> eventIcons = new Object2ObjectOpenHashMap<>();
static {
eventIcons.put("Dark Auction", new ItemStack(Items.NETHER_BRICK));
eventIcons.put("Bonus Fishing Festival", new ItemStack(Items.FISHING_ROD));
eventIcons.put("Bonus Mining Fiesta", new ItemStack(Items.IRON_PICKAXE));
- eventIcons.put("Jacob's Farming Contest", new ItemStack(Items.IRON_HOE));
+ eventIcons.put(JACOBS, new ItemStack(Items.IRON_HOE));
eventIcons.put("New Year Celebration", new ItemStack(Items.CAKE));
eventIcons.put("Election Over!", new ItemStack(Items.JUKEBOX));
eventIcons.put("Election Booth Opens", new ItemStack(Items.JUKEBOX));
@@ -68,6 +70,10 @@ public class EventNotifications {
private static final Map<String, LinkedList<SkyblockEvent>> events = new Object2ObjectOpenHashMap<>();
+ public static Map<String, LinkedList<SkyblockEvent>> getEvents() {
+ return events;
+ }
+
public static void refreshEvents() {
CompletableFuture.supplyAsync(() -> {
try {
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java b/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java
index 12590d09..a7a5f9c0 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java
@@ -15,7 +15,7 @@ public class JacobEventToast extends EventToast{
private final String[] crops;
- private static final Map<String, ItemStack> cropItems = new HashMap<>();
+ public static final Map<String, ItemStack> cropItems = new HashMap<>();
static {
cropItems.put("Wheat", new ItemStack(Items.WHEAT));
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListTab.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListTab.java
new file mode 100644
index 00000000..4109246d
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListTab.java
@@ -0,0 +1,89 @@
+package de.hysky.skyblocker.skyblock.itemlist;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import net.minecraft.client.MinecraftClient;
+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.TextFieldWidget;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.text.Text;
+import net.minecraft.util.Formatting;
+
+import java.util.List;
+
+public class ItemListTab extends ItemListWidget.TabContainerWidget {
+
+ private SearchResultsWidget results;
+ private final MinecraftClient client;
+ private TextFieldWidget searchField;
+
+ public ItemListTab(int x, int y, MinecraftClient client, TextFieldWidget searchField) {
+ super(x, y, Text.literal("Item List Tab"));
+ this.client = client;
+ this.searchField = searchField;
+ if (ItemRepository.filesImported()) {
+ this.results = new SearchResultsWidget(this.client, x - 9, y - 9 );
+ this.results.updateSearchResult(searchField == null ? "": this.searchField.getText());
+ }
+ }
+
+ @Override
+ public List<? extends Element> children() {
+ return List.of(results, searchField);
+ }
+
+ @Override
+ protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
+ MatrixStack matrices = context.getMatrices();
+ matrices.push();
+ matrices.translate(0.0D, 0.0D, 100.0D);
+ RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
+ int x = getX();
+ int y = getY();
+
+ // all coordinates offseted -9
+ if (!ItemRepository.filesImported() && !this.searchField.isFocused() && this.searchField.getText().isEmpty()) {
+ Text hintText = (Text.literal("Loading...")).formatted(Formatting.ITALIC).formatted(Formatting.GRAY);
+ context.drawTextWithShadow(this.client.textRenderer, hintText, x + 16, y + 7, -1);
+ } else if (!this.searchField.isFocused() && this.searchField.getText().isEmpty()) {
+ Text hintText = (Text.translatable("gui.recipebook.search_hint")).formatted(Formatting.ITALIC).formatted(Formatting.GRAY);
+ context.drawTextWithShadow(this.client.textRenderer, hintText, x + 16, y + 7, -1);
+ } else {
+ this.searchField.render(context, mouseX, mouseY, delta);
+ }
+ if (ItemRepository.filesImported()) {
+ if (results == null) {
+ this.results = new SearchResultsWidget(this.client, x - 9, y - 9);
+ }
+ this.results.updateSearchResult(this.searchField.getText());
+ this.results.render(context, mouseX, mouseY, delta);
+ }
+ matrices.pop();
+ }
+
+ @Override
+ protected void appendClickableNarrations(NarrationMessageBuilder builder) {}
+
+ public void setSearchField(TextFieldWidget searchField) {
+ this.searchField = searchField;
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (!visible) return false;
+ if (this.searchField.mouseClicked(mouseX, mouseY, button)) {
+ this.results.closeRecipeView();
+ this.searchField.setFocused(true);
+ return true;
+ } else {
+ this.searchField.setFocused(false);
+ return this.results.mouseClicked(mouseX, mouseY, button);
+ }
+ }
+
+ @Override
+ public void drawTooltip(DrawContext context, int mouseX, int mouseY) {
+ if (this.results != null) this.results.drawTooltip(context, mouseX, mouseY);
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java
index 6120528c..4a258b9e 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/ItemListWidget.java
@@ -1,103 +1,127 @@
package de.hysky.skyblocker.skyblock.itemlist;
-import com.mojang.blaze3d.systems.RenderSystem;
-
import de.hysky.skyblocker.mixins.accessors.RecipeBookWidgetAccessor;
+import de.hysky.skyblocker.utils.render.gui.SideTabButtonWidget;
+import it.unimi.dsi.fastutil.Pair;
+import it.unimi.dsi.fastutil.objects.ObjectObjectImmutablePair;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget;
+import net.minecraft.client.gui.tooltip.Tooltip;
+import net.minecraft.client.gui.widget.ContainerWidget;
import net.minecraft.client.gui.widget.TextFieldWidget;
-import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
import net.minecraft.screen.AbstractRecipeScreenHandler;
import net.minecraft.text.Text;
-import net.minecraft.util.Formatting;
+
+import java.util.ArrayList;
+import java.util.List;
@Environment(value = EnvType.CLIENT)
public class ItemListWidget extends RecipeBookWidget {
private int parentWidth;
private int parentHeight;
private int leftOffset;
- private TextFieldWidget searchField;
- private SearchResultsWidget results;
+
+ private TabContainerWidget currentTabContent;
+ private final List<Pair<SideTabButtonWidget, TabContainerWidget>> tabs = new ArrayList<>(2);
+ private ItemListTab itemListTab;
public ItemListWidget() {
super();
}
- public void updateSearchResult() {
- this.results.updateSearchResult(((RecipeBookWidgetAccessor) this).getSearchText());
- }
-
@Override
public void initialize(int parentWidth, int parentHeight, MinecraftClient client, boolean narrow, AbstractRecipeScreenHandler<?> craftingScreenHandler) {
super.initialize(parentWidth, parentHeight, client, narrow, craftingScreenHandler);
this.parentWidth = parentWidth;
this.parentHeight = parentHeight;
this.leftOffset = narrow ? 0 : 86;
- this.searchField = ((RecipeBookWidgetAccessor) this).getSearchField();
- int x = (this.parentWidth - 147) / 2 - this.leftOffset;
- int y = (this.parentHeight - 166) / 2;
- if (ItemRepository.filesImported()) {
- this.results = new SearchResultsWidget(this.client, x, y);
- this.updateSearchResult();
- }
+ TextFieldWidget searchField = ((RecipeBookWidgetAccessor) this).getSearchField();
+ int x = (parentWidth - 147) / 2 - leftOffset;
+ int y = (parentHeight - 166) / 2;
+
+ // Init all the tabs, content and the tab button on the left
+ tabs.clear();
+ itemListTab = new ItemListTab(x + 9, y + 9, this.client, searchField);
+
+ SideTabButtonWidget itemListTabButton = new SideTabButtonWidget(x - 30, y + 3, true, new ItemStack(Items.CRAFTING_TABLE));
+ itemListTabButton.setTooltip(Tooltip.of(Text.literal("Item List")));
+ tabs.add(new ObjectObjectImmutablePair<>(
+ itemListTabButton,
+ this.currentTabContent = this.itemListTab));
+
+ SideTabButtonWidget eventsTabButtonWidget = new SideTabButtonWidget(x - 30, y + 3 + 27, false, new ItemStack(Items.CLOCK));
+ eventsTabButtonWidget.setTooltip(Tooltip.of(Text.literal("Upcoming Events")));
+ tabs.add(new ObjectObjectImmutablePair<>(
+ eventsTabButtonWidget,
+ new UpcomingEventsTab(x + 9, y + 9, this.client)
+ ));
+
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ if (itemListTab != null) itemListTab.setSearchField(((RecipeBookWidgetAccessor) this).getSearchField());
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
if (this.isOpen()) {
- MatrixStack matrices = context.getMatrices();
- matrices.push();
- matrices.translate(0.0D, 0.0D, 100.0D);
- RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
- this.searchField = ((RecipeBookWidgetAccessor) this).getSearchField();
int i = (this.parentWidth - 147) / 2 - this.leftOffset;
int j = (this.parentHeight - 166) / 2;
+ // Draw the texture
context.drawTexture(TEXTURE, i, j, 1, 1, 147, 166);
- this.searchField = ((RecipeBookWidgetAccessor) this).getSearchField();
-
- if (!ItemRepository.filesImported() && !this.searchField.isFocused() && this.searchField.getText().isEmpty()) {
- Text hintText = (Text.literal("Loading...")).formatted(Formatting.ITALIC).formatted(Formatting.GRAY);
- context.drawTextWithShadow(this.client.textRenderer, hintText, i + 25, j + 14, -1);
- } else if (!this.searchField.isFocused() && this.searchField.getText().isEmpty()) {
- Text hintText = (Text.translatable("gui.recipebook.search_hint")).formatted(Formatting.ITALIC).formatted(Formatting.GRAY);
- context.drawTextWithShadow(this.client.textRenderer, hintText, i + 25, j + 14, -1);
- } else {
- this.searchField.render(context, mouseX, mouseY, delta);
- }
- if (ItemRepository.filesImported()) {
- if (results == null) {
- int x = (this.parentWidth - 147) / 2 - this.leftOffset;
- int y = (this.parentHeight - 166) / 2;
- this.results = new SearchResultsWidget(this.client, x, y);
- }
- this.updateSearchResult();
- this.results.render(context, mouseX, mouseY, delta);
+ // Draw the tab's content
+ if (currentTabContent != null) currentTabContent.render(context, mouseX, mouseY, delta);
+ // Draw the tab buttons
+ for (Pair<SideTabButtonWidget, TabContainerWidget> tab : tabs) {
+ tab.left().render(context, mouseX, mouseY, delta);
}
- matrices.pop();
+
}
}
@Override
public void drawTooltip(DrawContext context, int x, int y, int mouseX, int mouseY) {
- if (this.isOpen() && ItemRepository.filesImported() && results != null) {
- this.results.drawTooltip(context, mouseX, mouseY);
+ if (this.isOpen() && currentTabContent != null) {
+ this.currentTabContent.drawTooltip(context, mouseX, mouseY);
}
}
@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
- if (this.isOpen() && this.client.player != null && !this.client.player.isSpectator() && ItemRepository.filesImported() && this.searchField != null && results != null) {
- if (this.searchField.mouseClicked(mouseX, mouseY, button)) {
- this.results.closeRecipeView();
- this.searchField.setFocused(true);
- return true;
- } else {
- this.searchField.setFocused(false);
- return this.results.mouseClicked(mouseX, mouseY, button);
+ if (this.isOpen() && this.client.player != null && !this.client.player.isSpectator()) {
+ // check if a tab is clicked
+ for (Pair<SideTabButtonWidget, TabContainerWidget> tab : tabs) {
+ if (tab.first().mouseClicked(mouseX, mouseY, button) && currentTabContent != tab.right()) {
+ for (Pair<SideTabButtonWidget, TabContainerWidget> tab2 : tabs) {
+ tab2.first().setToggled(false);
+ }
+ tab.first().setToggled(true);
+ currentTabContent = tab.right();
+ return true;
+ }
}
+ // click the tab content
+ if (currentTabContent != null) return currentTabContent.mouseClicked(mouseX, mouseY, button);
+ else return false;
} else return false;
}
+
+ /**
+ * A container widget but with a fixed width and height and a drawTooltip method to implement
+ */
+ public abstract static class TabContainerWidget extends ContainerWidget {
+
+ public TabContainerWidget(int x, int y, Text text) {
+ super(x, y, 131, 150, text);
+ }
+
+ public abstract void drawTooltip(DrawContext context, int mouseX, int mouseY);
+ }
} \ No newline at end of file
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java
index 1ef352e3..48d3a8f6 100644
--- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java
+++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/SearchResultsWidget.java
@@ -6,6 +6,7 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Drawable;
+import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.screen.ButtonTextures;
import net.minecraft.client.gui.widget.ToggleButtonWidget;
import net.minecraft.component.DataComponentTypes;
@@ -23,7 +24,7 @@ import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class SearchResultsWidget implements Drawable {
+public class SearchResultsWidget implements Drawable, Element {
private static final ButtonTextures PAGE_FORWARD_TEXTURES = new ButtonTextures(new Identifier("recipe_book/page_forward"), new Identifier("recipe_book/page_forward_highlighted"));
private static final ButtonTextures PAGE_BACKWARD_TEXTURES = new ButtonTextures(new Identifier("recipe_book/page_backward"), new Identifier("recipe_book/page_backward_highlighted"));
private static final int COLS = 5;
@@ -225,4 +226,16 @@ public class SearchResultsWidget implements Drawable {
return false;
}
+ private boolean focused = false;
+
+ @Override
+ public void setFocused(boolean focused) {
+ this.focused = focused;
+ }
+
+ @Override
+ public boolean isFocused() {
+ return focused;
+ }
+
}
diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/UpcomingEventsTab.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/UpcomingEventsTab.java
new file mode 100644
index 00000000..134c5d4d
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/UpcomingEventsTab.java
@@ -0,0 +1,168 @@
+package de.hysky.skyblocker.skyblock.itemlist;
+
+import de.hysky.skyblocker.mixin.accessor.DrawContextInvoker;
+import de.hysky.skyblocker.skyblock.events.EventNotifications;
+import de.hysky.skyblocker.skyblock.events.JacobEventToast;
+import de.hysky.skyblocker.utils.Utils;
+import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
+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.screen.narration.NarrationMessageBuilder;
+import net.minecraft.client.gui.tooltip.HoveredTooltipPositioner;
+import net.minecraft.client.gui.tooltip.TooltipComponent;
+import net.minecraft.item.ItemStack;
+import net.minecraft.item.Items;
+import net.minecraft.text.MutableText;
+import net.minecraft.text.Style;
+import net.minecraft.text.Text;
+import net.minecraft.util.Colors;
+import net.minecraft.util.Formatting;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class UpcomingEventsTab extends ItemListWidget.TabContainerWidget {
+ private static final ItemStack CLOCK = new ItemStack(Items.CLOCK);
+ private final MinecraftClient client;
+ private final List<EventRenderer> events;
+
+ public UpcomingEventsTab(int x, int y, MinecraftClient client) {
+ super(x, y, Text.literal("Upcoming Events Tab"));
+ this.client = client;
+ events = EventNotifications.getEvents().entrySet()
+ .stream()
+ .sorted(Comparator.comparingLong(a -> a.getValue().isEmpty() ? Long.MAX_VALUE : a.getValue().peekFirst().start()))
+ .map(stringLinkedListEntry -> new EventRenderer(stringLinkedListEntry.getKey(), stringLinkedListEntry.getValue()))
+ .toList();
+ }
+
+ @Override
+ public void drawTooltip(DrawContext context, int mouseX, int mouseY) {
+ if (hovered != null) {
+ ((DrawContextInvoker) context).invokeDrawTooltip(this.client.textRenderer, hovered.getTooltip(), mouseX, mouseY, HoveredTooltipPositioner.INSTANCE);
+ }
+ }
+
+ @Override
+ public List<? extends Element> children() {
+ return List.of();
+ }
+
+ private EventRenderer hovered = null;
+
+ @Override
+ protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
+ int x = getX();
+ int y = getY();
+ context.enableScissor(x, y, getRight(), getBottom());
+ context.drawItem(CLOCK, x, y + 4);
+ context.drawText(this.client.textRenderer, "Upcoming Events", x + 17, y + 7, -1, true);
+
+ int eventsY = y + 7 + 24;
+ hovered = null;
+ for (EventRenderer eventRenderer : events) {
+ eventRenderer.render(context, x + 1, eventsY, mouseX, mouseY);
+ if (eventRenderer.isMouseOver(mouseX, mouseY, x+1, eventsY)) hovered = eventRenderer;
+ eventsY += eventRenderer.getHeight();
+
+ }
+ context.disableScissor();
+ }
+
+ @Override
+ public boolean mouseClicked(double mouseX, double mouseY, int button) {
+ if (hovered != null && hovered.getWarpCommand() != null) {
+ MessageScheduler.INSTANCE.sendMessageAfterCooldown(hovered.getWarpCommand());
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void appendClickableNarrations(NarrationMessageBuilder builder) {
+
+ }
+
+ public static class EventRenderer {
+
+ private final LinkedList<EventNotifications.SkyblockEvent> events;
+ private final String eventName;
+
+ public EventRenderer(String eventName, LinkedList<EventNotifications.SkyblockEvent> events) {
+ this.events = events;
+ this.eventName = eventName;
+ }
+
+ public void render(DrawContext context, int x, int y, int mouseX, int mouseY) {
+ long time = System.currentTimeMillis() / 1000;
+ TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
+ context.drawText(textRenderer, Text.literal(eventName).fillStyle(Style.EMPTY.withUnderline(isMouseOver(mouseX, mouseY, x, y))), x, y, -1, true);
+ if (events.isEmpty()) {
+ context.drawText(textRenderer, " No more this year!", x, y + textRenderer.fontHeight, Colors.GRAY, false);
+ } else if (events.peekFirst().start() > time) {
+ MutableText formatted = Text.literal(" Starts in ").append(Utils.getDurationText((int) (events.peekFirst().start() - time))).formatted(Formatting.YELLOW);
+ context.drawText(textRenderer, formatted, x, y + textRenderer.fontHeight, -1, true);
+ } else {
+ MutableText formatted = Text.literal(" Ends in ").append(Utils.getDurationText((int) (events.peekFirst().start() + events.peekFirst().duration() - time))).formatted(Formatting.GREEN);
+ context.drawText(textRenderer, formatted, x, y + textRenderer.fontHeight, -1, true);
+ }
+
+ }
+
+ public int getHeight() {
+ return 20;
+ }
+
+ public boolean isMouseOver(int mouseX, int mouseY, int x, int y) {
+ return mouseX >= x && mouseX <= x + 131 && mouseY >= y && mouseY <= y+getHeight();
+ }
+
+ public List<TooltipComponent> getTooltip() {
+ List<TooltipComponent> components = new ArrayList<>();
+ if (events.peekFirst() == null) return components;
+ if (eventName.equals(EventNotifications.JACOBS)) {
+ components.add(new JacobsTooltip(events.peekFirst().extras()));
+ }
+ //noinspection DataFlowIssue
+ if (events.peekFirst().warpCommand() != null) {
+ components.add(TooltipComponent.of(Text.literal("Click to warp!").formatted(Formatting.ITALIC).asOrderedText()));
+ }
+
+ return components;
+ }
+
+ public @Nullable String getWarpCommand() {
+ if (events.isEmpty()) return null;
+ return events.peek().warpCommand();
+ }
+ }
+
+ private record JacobsTooltip(String[] crops) implements TooltipComponent {
+
+ private static final ItemStack BARRIER = new ItemStack(Items.BARRIER);
+
+ @Override
+ public int getHeight() {
+ return 20;
+ }
+
+ @Override
+ public int getWidth(TextRenderer textRenderer) {
+ return 16 * 3 + 4;
+ }
+
+ @Override
+ public void drawItems(TextRenderer textRenderer, int x, int y, DrawContext context) {
+ for (int i = 0; i < crops.length; i++) {
+ String crop = crops[i];
+ context.drawItem(JacobEventToast.cropItems.getOrDefault(crop, BARRIER), x + 18 * i, y + 2);
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/de/hysky/skyblocker/utils/render/gui/SideTabButtonWidget.java b/src/main/java/de/hysky/skyblocker/utils/render/gui/SideTabButtonWidget.java
new file mode 100644
index 00000000..87da0d36
--- /dev/null
+++ b/src/main/java/de/hysky/skyblocker/utils/render/gui/SideTabButtonWidget.java
@@ -0,0 +1,39 @@
+package de.hysky.skyblocker.utils.render.gui;
+
+import net.minecraft.client.gui.DrawContext;
+import net.minecraft.client.gui.screen.ButtonTextures;
+import net.minecraft.client.gui.widget.ToggleButtonWidget;
+import net.minecraft.item.ItemStack;
+import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.NotNull;
+
+public class SideTabButtonWidget extends ToggleButtonWidget {
+ private static final ButtonTextures TEXTURES = new ButtonTextures(new Identifier("recipe_book/tab"), new Identifier("recipe_book/tab_selected"));
+ protected @NotNull ItemStack icon;
+
+ public void setIcon(@NotNull ItemStack icon) {
+ this.icon = icon.copy();
+ }
+
+ public SideTabButtonWidget(int x, int y, boolean toggled, @NotNull ItemStack icon) {
+ super(x, y, 35, 27, toggled);
+ this.icon = icon.copy();
+ setTextures(TEXTURES);
+ }
+
+ @Override
+ public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
+ if (textures == null) return;
+ Identifier identifier = textures.get(true, this.toggled);
+ int x = getX();
+ if (toggled) x -= 2;
+ context.drawGuiTexture(identifier, x, this.getY(), this.width, this.height);
+ context.drawItem(icon, x + 9, getY() + 5);
+ }
+
+ @Override
+ public void onClick(double mouseX, double mouseY) {
+ super.onClick(mouseX, mouseY);
+ if (!isToggled()) this.setToggled(true);
+ }
+}