Skip to content

Commit d5db9a6

Browse files
authored
prospector UI fixes (#5099)
1 parent 9f01c3d commit d5db9a6

2 files changed

Lines changed: 80 additions & 23 deletions

File tree

src/main/java/com/gregtechceu/gtceu/common/item/behavior/ProspectorScannerBehavior.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,16 @@ public ModularPanel<?> buildUI(PlayerInventoryGuiData<?> guiData, PanelSyncManag
119119
panelSyncManager, guiData.getPlayer());
120120

121121
int mapSize = (this.radius * 2 - 1) * 16 + 1;
122-
return ModularPanel.defaultPanel("prospector_scanner", mapSize + 156, mapSize + 24)
122+
return ModularPanel.defaultPanel("prospector_scanner", mapSize + 152, 200)
123123
.margin(4)
124124
.child(new ToggleButton()
125125
.size(18)
126126
.top(4).leftRelAnchor(0f, 1f)
127127
.decoration()
128128
.stateBackground(GTGuiTextures.PROGRESS_BAR_SOLAR_STEEL)
129129
.value(new BoolValue.Dynamic(mapHandler::isDarkMode,
130-
mapHandler::setDarkMode)))
130+
mapHandler::setDarkMode))
131+
.excludeAreaInRecipeViewer())
131132
.child(Flow.row()
132133
.childPadding(10)
133134
.margin(6)

src/main/java/com/gregtechceu/gtceu/common/mui/widgets/prospector/ProspectorMapHandler.java

Lines changed: 77 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import brachy.modularui.widgets.*;
3434
import brachy.modularui.widgets.layout.Flow;
3535
import com.google.common.base.Strings;
36+
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
3637
import lombok.Getter;
3738
import org.jetbrains.annotations.NotNull;
3839
import org.jetbrains.annotations.Nullable;
@@ -65,8 +66,10 @@ public class ProspectorMapHandler<T> extends Widget<ProspectorMapHandler<T>> imp
6566
// runtime
6667
@Getter
6768
private @Nullable String selected = null;
68-
private final Set<T> items = new HashSet<>();
69+
// keyed by uniqueId so entries are deduplicated across chunks
70+
private final Map<String, T> items = new Object2ObjectOpenHashMap<>();
6971
private int chunkIndex = 0;
72+
private String lastSearch = "";
7073

7174
public ProspectorMapHandler(ProspectorMode<T> mode, int chunkRadius, int scanInterval,
7275
StringValue searchValue, DynamicSyncedWidget<?> searchListWidget,
@@ -87,6 +90,16 @@ public ProspectorMapHandler(ProspectorMode<T> mode, int chunkRadius, int scanInt
8790
this.texture = new ProspectorMapTexture<>(this);
8891
background(this.texture);
8992
size(this.texture.getImageWidth(), this.texture.getImageHeight());
93+
94+
tooltipAutoUpdate(true);
95+
tooltipDynamic(tooltip -> {
96+
tooltip.clearText();
97+
List<T[]> cells = getHoveredChunkCells();
98+
if (cells.isEmpty()) return;
99+
List<Component> lines = new ArrayList<>();
100+
this.mode.appendTooltips(cells, lines, null);
101+
lines.forEach(tooltip::addLine);
102+
});
90103
} else {
91104
int diameter = (chunkRadius * 2 - 1) * 16 + 1;
92105
size(diameter, diameter);
@@ -108,7 +121,14 @@ private DynamicSyncHandler createListSyncHandler() {
108121
.collapseDisabledChildren()
109122
.expanded()
110123
.sizeRel(1f)
111-
.children(this.items, item -> {
124+
.onUpdateListener(list -> {
125+
String current = searchValue.getStringValue();
126+
if (!Objects.equals(current, this.lastSearch)) {
127+
this.lastSearch = current;
128+
list.getScrollData().scrollTo(list.getScrollArea(), 0);
129+
}
130+
})
131+
.children(this.items.values(), item -> {
112132
String uniqueId = mode.getUniqueId(item);
113133
Component description = mode.getDescription(item);
114134

@@ -126,7 +146,8 @@ private DynamicSyncHandler createListSyncHandler() {
126146
if (Strings.isNullOrEmpty(searched)) {
127147
return true;
128148
} else {
129-
return description.getString().toLowerCase().contains(searched);
149+
return description.getString().toLowerCase()
150+
.contains(searched.toLowerCase());
130151
}
131152
})
132153
.child(Flow.row()
@@ -178,7 +199,11 @@ private void scanOres() {
178199
private void addOresToList(T[][][] data) {
179200
for (int x = 0; x < mode.cellSize; x++) {
180201
for (int z = 0; z < mode.cellSize; z++) {
181-
Collections.addAll(this.items, data[x][z]);
202+
for (T item : data[x][z]) {
203+
if (item != null) {
204+
this.items.putIfAbsent(mode.getUniqueId(item), item);
205+
}
206+
}
182207
}
183208
}
184209
}
@@ -219,39 +244,70 @@ public void setDarkMode(boolean darkMode) {
219244
Component.translatable("behavior.prospector.added_waypoint",
220245
clickedItem.name.copy().withStyle(style -> style.withColor(clickedItem.color))),
221246
false);
247+
this.getContext().getScreen().getMainPanel().closeIfOpen();
222248

223249
Interactable.playButtonClickSound();
224250
return Result.SUCCESS;
225251
}
226252

253+
/**
254+
* @return every non-empty data cell of the chunk currently under the cursor, or an empty list if the
255+
* cursor is off the map.
256+
*/
257+
private List<T[]> getHoveredChunkCells() {
258+
if (this.texture == null) return List.of();
259+
int relX = getContext().getMouseX();
260+
int relZ = getContext().getMouseY();
261+
262+
int mapPixels = (this.chunkRadius * 2 - 1) * 16;
263+
if (relX < 0 || relZ < 0 || relX >= mapPixels || relZ >= mapPixels) {
264+
return List.of();
265+
}
266+
267+
int chunkX = relX / 16;
268+
int chunkZ = relZ / 16;
269+
int cellSize = this.mode.cellSize;
270+
List<T[]> cells = new ArrayList<>();
271+
for (int i = 0; i < cellSize; i++) {
272+
for (int j = 0; j < cellSize; j++) {
273+
T[] cell = this.texture.data[chunkX * cellSize + i][chunkZ * cellSize + j];
274+
if (cell != null && cell.length > 0) {
275+
cells.add(cell);
276+
}
277+
}
278+
}
279+
return cells;
280+
}
281+
227282
private @Nullable WaypointItem getClickedVein(double mouseX, double mouseY) {
228283
if (this.texture == null) return null;
229-
int chunkX = (int) (mouseX - getArea().x()) / 16;
230-
int chunkZ = (int) (mouseY - getArea().y()) / 16;
231-
int offsetX = (int) (mouseX - getArea().x()) % 16;
232-
int offsetZ = (int) (mouseY - getArea().y()) % 16;
284+
int relX = (int) mouseX;
285+
int relZ = (int) mouseY;
286+
287+
int mapPixels = (this.chunkRadius * 2 - 1) * 16;
288+
if (relX < 0 || relZ < 0 || relX >= mapPixels || relZ >= mapPixels) {
289+
return null;
290+
}
291+
292+
int chunkX = relX / 16;
293+
int chunkZ = relZ / 16;
294+
int offsetX = relX % 16;
295+
int offsetZ = relZ % 16;
233296
int xDiff = chunkX - (this.chunkRadius - 1);
234297
int zDiff = chunkZ - (this.chunkRadius - 1);
235298

236299
int x = SectionPos.sectionToBlockCoord(player.chunkPosition().x + xDiff) + offsetX;
237300
int z = SectionPos.sectionToBlockCoord(player.chunkPosition().z + zDiff) + offsetZ;
238301
int y = player.level().getHeight(Heightmap.Types.WORLD_SURFACE, x, z);
239302

240-
if (chunkX < 0 || chunkZ < 0 || chunkX >= this.chunkRadius * 2 - 1 || chunkZ >= this.chunkRadius * 2 - 1) {
241-
return null;
242-
}
243-
244303
BlockPos pos = new BlockPos(x, y, z);
245304
// If the ores are filtered use its name
246-
if (this.getSelected() != null) {
247-
for (T item : this.items) {
248-
String uniqueId = mode.getUniqueId(item);
249-
if (!this.getSelected().equals(uniqueId)) continue;
250-
251-
Component name = mode.getDescription(item);
252-
int color = mode.getItemColor(item);
253-
return new WaypointItem(pos, uniqueId, name, color);
254-
}
305+
T item = this.items.get(this.getSelected());
306+
if (item != null) {
307+
Component name = mode.getDescription(item);
308+
int color = mode.getItemColor(item);
309+
String uniqueId = mode.getUniqueId(item);
310+
return new WaypointItem(pos, uniqueId, name, color);
255311
}
256312

257313
// If the cursor is over an ore use its name

0 commit comments

Comments
 (0)