Skip to content

Commit cfa71fe

Browse files
Merge pull request SkyblockerMod#739 from olim88/improve-search-overlay
Improve search overlay
2 parents a275c48 + 652cf69 commit cfa71fe

File tree

3 files changed

+199
-23
lines changed

3 files changed

+199
-23
lines changed

Diff for: src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/OverlayScreen.java

+102-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import de.hysky.skyblocker.config.SkyblockerConfigManager;
44
import net.minecraft.client.gui.DrawContext;
55
import net.minecraft.client.gui.screen.Screen;
6+
import net.minecraft.client.gui.tooltip.Tooltip;
67
import net.minecraft.client.gui.widget.ButtonWidget;
78
import net.minecraft.client.gui.widget.TextFieldWidget;
89
import net.minecraft.item.ItemStack;
10+
import net.minecraft.text.MutableText;
911
import net.minecraft.text.Style;
1012
import net.minecraft.text.Text;
1113
import net.minecraft.util.Formatting;
@@ -17,9 +19,12 @@
1719
public class OverlayScreen extends Screen {
1820

1921
protected static final Identifier SEARCH_ICON_TEXTURE = new Identifier("icon/search");
22+
private static final Identifier BACKGROUND_TEXTURE = new Identifier("social_interactions/background");
2023
private static final int rowHeight = 20;
2124
private TextFieldWidget searchField;
2225
private ButtonWidget finishedButton;
26+
private ButtonWidget maxPetButton;
27+
private ButtonWidget dungeonStarButton;
2328
private ButtonWidget[] suggestionButtons;
2429
private ButtonWidget[] historyButtons;
2530

@@ -44,10 +49,11 @@ protected void init() {
4449
searchField.setMaxLength(30);
4550

4651
// finish buttons
47-
finishedButton = ButtonWidget.builder(Text.literal("").setStyle(Style.EMPTY.withColor(Formatting.GREEN)), a -> close())
52+
finishedButton = ButtonWidget.builder(Text.literal(""), a -> close())
4853
.position(startX + rowWidth - rowHeight, startY)
4954
.size(rowHeight, rowHeight).build();
5055

56+
5157
// suggested item buttons
5258
int rowOffset = rowHeight;
5359
int totalSuggestions = SkyblockerConfigManager.get().uiAndVisuals.searchOverlay.maxSuggestions;
@@ -80,6 +86,26 @@ protected void init() {
8086
break;
8187
}
8288
}
89+
//auction only elements
90+
if (SearchOverManager.isAuction) {
91+
//max pet level button
92+
maxPetButton = ButtonWidget.builder(Text.literal(""), a -> {
93+
SearchOverManager.maxPetLevel = !SearchOverManager.maxPetLevel;
94+
updateMaxPetText();
95+
})
96+
.tooltip(Tooltip.of(Text.translatable("skyblocker.config.general.searchOverlay.maxPet.@Tooltip")))
97+
.position(startX, startY - rowHeight - 8)
98+
.size(rowWidth / 2, rowHeight).build();
99+
updateMaxPetText();
100+
101+
//dungeon star input
102+
dungeonStarButton = ButtonWidget.builder(Text.literal("✪"), a -> updateStars())
103+
.tooltip(Tooltip.of(Text.translatable("skyblocker.config.general.searchOverlay.starsTooltip")))
104+
.position(startX + (int) (rowWidth * 0.5), startY - rowHeight - 8)
105+
.size(rowWidth / 2, rowHeight).build();
106+
107+
updateStars();
108+
}
83109

84110
//add drawables in order to make tab navigation sensible
85111
addDrawableChild(searchField);
@@ -93,10 +119,85 @@ protected void init() {
93119
}
94120
addDrawableChild(finishedButton);
95121

122+
if (SearchOverManager.isAuction) {
123+
addDrawableChild(maxPetButton);
124+
addDrawableChild(dungeonStarButton);
125+
}
126+
96127
//focus the search box
97128
this.setInitialFocus(searchField);
98129
}
99130

131+
/**
132+
* Finds if the mouse is clicked on the dungeon star button and if so works out what stars the user clicked on
133+
*
134+
* @param mouseX the X coordinate of the mouse
135+
* @param mouseY the Y coordinate of the mouse
136+
* @param button the mouse button number
137+
* @return super
138+
*/
139+
@Override
140+
public boolean mouseClicked(double mouseX, double mouseY, int button) {
141+
if (SearchOverManager.isAuction && dungeonStarButton.isHovered() && client != null) {
142+
double actualTextWidth = client.textRenderer.getWidth(dungeonStarButton.getMessage());
143+
double textOffset = (dungeonStarButton.getWidth() - actualTextWidth) / 2;
144+
double offset = mouseX - (dungeonStarButton.getX() + textOffset);
145+
int starCount = (int) ((offset / actualTextWidth) * 10);
146+
starCount = Math.clamp(starCount + 1, 0, 10);
147+
//if same as old value set stars to 0 else set to selected amount
148+
if (starCount == SearchOverManager.dungeonStars) {
149+
SearchOverManager.dungeonStars = 0;
150+
} else {
151+
SearchOverManager.dungeonStars = starCount;
152+
}
153+
}
154+
155+
return super.mouseClicked(mouseX, mouseY, button);
156+
}
157+
158+
/**
159+
* Updates the text displayed on the max pet level button to represent the settings current state
160+
*/
161+
private void updateMaxPetText() {
162+
if (SearchOverManager.maxPetLevel) {
163+
maxPetButton.setMessage(Text.translatable("skyblocker.config.general.searchOverlay.maxPet").append(Text.literal(" ✔")).formatted(Formatting.GREEN));
164+
} else {
165+
maxPetButton.setMessage(Text.translatable("skyblocker.config.general.searchOverlay.maxPet").append(Text.literal(" ❌")).formatted(Formatting.RED));
166+
}
167+
}
168+
169+
/**
170+
* Updates stars in dungeon star input to represent the current star value
171+
*/
172+
private void updateStars() {
173+
MutableText stars = Text.empty();
174+
for (int i = 0; i < SearchOverManager.dungeonStars; i++) {
175+
stars.append(Text.literal("✪").formatted(i < 5 ? Formatting.YELLOW : Formatting.RED));
176+
}
177+
for (int i = SearchOverManager.dungeonStars; i < 10; i++) {
178+
stars.append(Text.literal("✪"));
179+
}
180+
dungeonStarButton.setMessage(stars);
181+
}
182+
183+
/**
184+
* Renders the background for the search using the social interactions background
185+
* @param context context
186+
* @param mouseX mouseX
187+
* @param mouseY mouseY
188+
* @param delta delta
189+
*/
190+
@Override
191+
public void renderBackground(DrawContext context, int mouseX, int mouseY, float delta) {
192+
super.renderBackground(context, mouseX, mouseY, delta);
193+
//find max height
194+
int maxHeight = rowHeight * (1 + suggestionButtons.length + historyButtons.length);
195+
if (historyButtons.length > 0) { //add space for history label if it could exist
196+
maxHeight += (int) (rowHeight * 0.75);
197+
}
198+
context.drawGuiTexture(BACKGROUND_TEXTURE, searchField.getX() - 8, searchField.getY() - 8, (int) (this.width * 0.4) + 16, maxHeight + 16);
199+
}
200+
100201
/**
101202
* Renders the search icon, label for the history and item Stacks for item names
102203
*/

Diff for: src/main/java/de/hysky/skyblocker/skyblock/searchoverlay/SearchOverManager.java

+94-22
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import de.hysky.skyblocker.utils.NEURepoManager;
1111
import de.hysky.skyblocker.utils.scheduler.MessageScheduler;
1212
import io.github.moulberry.repo.data.NEUItem;
13+
import io.github.moulberry.repo.util.NEUId;
1314
import it.unimi.dsi.fastutil.Pair;
1415
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
1516
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
@@ -24,10 +25,7 @@
2425
import org.slf4j.Logger;
2526
import org.slf4j.LoggerFactory;
2627

27-
import java.util.Arrays;
28-
import java.util.HashMap;
29-
import java.util.HashSet;
30-
import java.util.Map;
28+
import java.util.*;
3129
import java.util.regex.Matcher;
3230
import java.util.regex.Pattern;
3331
import java.util.stream.Collectors;
@@ -40,8 +38,7 @@ public class SearchOverManager {
4038
private static final Logger LOGGER = LoggerFactory.getLogger("Skyblocker Search Overlay");
4139

4240
private static final Pattern BAZAAR_ENCHANTMENT_PATTERN = Pattern.compile("ENCHANTMENT_(\\D*)_(\\d+)");
43-
private static final Pattern AUCTION_PET_AND_RUNE_PATTERN = Pattern.compile("([A-Z0-9_]+);(\\d+)");
44-
41+
private static final String PET_NAME_START = "[Lvl {LVL}] ";
4542
/**
4643
* converts index (in array) +1 to a roman numeral
4744
*/
@@ -52,14 +49,18 @@ public class SearchOverManager {
5249

5350
private static @Nullable SignBlockEntity sign = null;
5451
private static boolean signFront = true;
55-
private static boolean isAuction;
52+
protected static boolean isAuction;
5653
private static boolean isCommand;
5754

5855
protected static String search = "";
56+
protected static Boolean maxPetLevel = false;
57+
protected static int dungeonStars = 0;
5958

6059
// Use non-final variables and swap them to prevent concurrent modification
6160
private static HashSet<String> bazaarItems;
6261
private static HashSet<String> auctionItems;
62+
private static HashSet<String> auctionPets;
63+
private static HashSet<String> starableItems;
6364
private static HashMap<String, String> namesToId;
6465

6566
public static String[] suggestionsArray = {};
@@ -91,6 +92,8 @@ private static int startCommand(boolean isAuction) {
9192
private static void loadItems() {
9293
HashSet<String> bazaarItems = new HashSet<>();
9394
HashSet<String> auctionItems = new HashSet<>();
95+
HashSet<String> auctionPets = new HashSet<>();
96+
HashSet<String> starableItems = new HashSet<>();
9497
HashMap<String, String> namesToId = new HashMap<>();
9598

9699
//get bazaar items
@@ -139,28 +142,28 @@ private static void loadItems() {
139142

140143
//get auction items
141144
try {
145+
Set<@NEUId String> essenceCosts = NEURepoManager.NEU_REPO.getConstants().getEssenceCost().getCosts().keySet();
142146
if (TooltipInfoType.THREE_DAY_AVERAGE.getData() == null) {
143147
TooltipInfoType.THREE_DAY_AVERAGE.run();
144148
}
145149
for (Map.Entry<String, JsonElement> entry : TooltipInfoType.THREE_DAY_AVERAGE.getData().entrySet()) {
146150
String id = entry.getKey();
147-
148-
Matcher matcher = AUCTION_PET_AND_RUNE_PATTERN.matcher(id);
149-
if (matcher.find()) {//is a pet or rune convert id to name
150-
String name = matcher.group(1).replace("_", " ");
151-
name = capitalizeFully(name);
152-
auctionItems.add(name);
153-
namesToId.put(name, id);
154-
continue;
155-
}
156-
//something else look up in NEU repo.
151+
//look up in NEU repo.
157152
id = id.split("[+-]")[0];
158153
NEUItem neuItem = NEURepoManager.NEU_REPO.getItems().getItemBySkyblockId(id);
159154
if (neuItem != null) {
160155
String name = Formatting.strip(neuItem.getDisplayName());
156+
//add names that are pets to the list of pets to work with the lvl 100 button
157+
if (name != null && name.startsWith(PET_NAME_START)) {
158+
name = name.replace(PET_NAME_START, "");
159+
auctionPets.add(name.toLowerCase());
160+
}
161+
//if it has essence cost add to starable items
162+
if (name != null && essenceCosts.contains(neuItem.getSkyblockItemId())) {
163+
starableItems.add(name.toLowerCase());
164+
}
161165
auctionItems.add(name);
162166
namesToId.put(name, id);
163-
continue;
164167
}
165168
}
166169
} catch (Exception e) {
@@ -169,11 +172,14 @@ private static void loadItems() {
169172

170173
SearchOverManager.bazaarItems = bazaarItems;
171174
SearchOverManager.auctionItems = auctionItems;
175+
SearchOverManager.auctionPets = auctionPets;
176+
SearchOverManager.starableItems = starableItems;
172177
SearchOverManager.namesToId = namesToId;
173178
}
174179

175180
/**
176181
* Capitalizes the first letter off every word in a string
182+
*
177183
* @param str string to capitalize
178184
*/
179185
private static String capitalizeFully(String str) {
@@ -188,8 +194,9 @@ private static String capitalizeFully(String str) {
188194

189195
/**
190196
* Receives data when a search is started and resets values
191-
* @param sign the sign that is being edited
192-
* @param front if it's the front of the sign
197+
*
198+
* @param sign the sign that is being edited
199+
* @param front if it's the front of the sign
193200
* @param isAuction if the sign is loaded from the auction house menu or bazaar
194201
*/
195202
public static void updateSign(@NotNull SignBlockEntity sign, boolean front, boolean isAuction) {
@@ -214,18 +221,38 @@ public static void updateSign(@NotNull SignBlockEntity sign, boolean front, bool
214221

215222
/**
216223
* Updates the search value and the suggestions based on that value.
224+
*
217225
* @param newValue new search value
218226
*/
219227
protected static void updateSearch(String newValue) {
220228
search = newValue;
221229
//update the suggestion values
222230
int totalSuggestions = SkyblockerConfigManager.get().uiAndVisuals.searchOverlay.maxSuggestions;
223231
if (newValue.isBlank() || totalSuggestions == 0) return; //do not search for empty value
224-
suggestionsArray = (isAuction ? auctionItems : bazaarItems).stream().filter(item -> item.toLowerCase().contains(search.toLowerCase())).limit(totalSuggestions).toArray(String[]::new);
232+
suggestionsArray = (isAuction ? auctionItems : bazaarItems).stream().sorted(Comparator.comparing(SearchOverManager::shouldFrontLoad, Comparator.reverseOrder())).filter(item -> item.toLowerCase().contains(search.toLowerCase())).limit(totalSuggestions).toArray(String[]::new);
233+
}
234+
235+
/**
236+
* determines if a value should be moved to the front of the search
237+
*
238+
* @param name name of the suggested item
239+
* @return if the value should be at the front of the search queue
240+
*/
241+
private static boolean shouldFrontLoad(String name) {
242+
if (!isAuction) {
243+
return false;
244+
}
245+
//do nothing to non pets
246+
if (!auctionPets.contains(name.toLowerCase())) {
247+
return false;
248+
}
249+
//only front load pets when there is enough of the pet typed, so it does not spoil searching for other items
250+
return (double) search.length() / name.length() > 0.5;
225251
}
226252

227253
/**
228254
* Gets the suggestion in the suggestion array at the index
255+
*
229256
* @param index index of suggestion
230257
*/
231258
protected static String getSuggestion(int index) {
@@ -242,6 +269,7 @@ protected static String getSuggestionId(int index) {
242269

243270
/**
244271
* Gets the item name in the history array at the index
272+
*
245273
* @param index index of suggestion
246274
*/
247275
protected static String getHistory(int index) {
@@ -286,20 +314,64 @@ private static void saveHistory() {
286314
}
287315

288316
/**
289-
*Saves the current value of ({@link SearchOverManager#search}) then pushes it to a command or sign depending on how the gui was opened
317+
* Saves the current value of ({@link SearchOverManager#search}) then pushes it to a command or sign depending on how the gui was opened
290318
*/
291319
protected static void pushSearch() {
292320
//save to history
293321
if (!search.isEmpty()) {
294322
saveHistory();
295323
}
324+
//add pet level or dungeon starts if in ah
325+
if (isAuction) {
326+
addExtras();
327+
}
328+
//push
296329
if (isCommand) {
297330
pushCommand();
298331
} else {
299332
pushSign();
300333
}
301334
}
302335

336+
/**
337+
* Adds pet level 100 or necessary dungeon starts if needed
338+
*/
339+
private static void addExtras() {
340+
// pet level
341+
if (maxPetLevel) {
342+
if (auctionPets.contains(search.toLowerCase())) {
343+
if (search.equalsIgnoreCase("golden dragon")) {
344+
search = "[Lvl 200] " + search;
345+
} else {
346+
search = "[Lvl 100] " + search;
347+
}
348+
}
349+
} else {
350+
// still filter for only pets
351+
if (auctionPets.contains(search.toLowerCase())) {
352+
// add bracket so only get pets
353+
search = "] " + search;
354+
}
355+
}
356+
357+
// dungeon stars
358+
// check if it's a dungeon item and if so add correct stars
359+
if (dungeonStars > 0 && starableItems.contains(search.toLowerCase())) {
360+
StringBuilder starString = new StringBuilder(" ");
361+
//add stars up to 5
362+
starString.append("✪".repeat(Math.max(0, Math.min(dungeonStars, 5))));
363+
//add number for other stars
364+
switch (dungeonStars) {
365+
case 6 -> starString.append("➊");
366+
case 7 -> starString.append("➋");
367+
case 8 -> starString.append("➌");
368+
case 9 -> starString.append("➍");
369+
case 10 -> starString.append("➎");
370+
}
371+
search += starString.toString();
372+
}
373+
}
374+
303375
/**
304376
* runs the command to search for the value in ({@link SearchOverManager#search})
305377
*/

0 commit comments

Comments
 (0)