Skip to content

Commit 3b0feb9

Browse files
committed
Wurst Waypoint Importing
1 parent d5b68db commit 3b0feb9

File tree

8 files changed

+622
-27
lines changed

8 files changed

+622
-27
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ Supports [Wurst7-CevAPI](https://github.com/cev-api/Wurst7-CevAPI) waypoints, Xa
106106

107107
Can now finally remove SeedMapper waypoints with via a right click context menu.
108108

109+
Added the ability to set the waypoint compass overlay to be manually toggled instead of automatic with the command ```/sm:config ManualWaypointCompassOverlay set true/false```. When set to true you have to right click on a waypoint to manually enable the waypoint compass for that particular waypoint. This makes your screen less cluttered when you have multiple waypoints.
110+
111+
I also added the ability to import waypoints from [Wurst7-CevAPI](https://github.com/cev-api/Wurst7-CevAPI). Will soon be adding Xaero waypoint as well.
112+
113+
109114
![Map](https://i.imgur.com/1qDgQw7.png)
110115

111116
### Highlight Timeout Setting

src/main/java/dev/xpple/seedmapper/SeedMapper.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import dev.xpple.seedmapper.world.WorldPresetManager;
2727
import dev.xpple.seedmapper.render.RenderManager;
2828
import dev.xpple.seedmapper.seedmap.MapFeature;
29+
import dev.xpple.seedmapper.seedmap.ManualWaypointCompassOverlay;
2930
import dev.xpple.seedmapper.seedmap.SeedMapMinimapManager;
3031
import dev.xpple.seedmapper.util.SeedDatabaseHelper;
3132
import dev.xpple.seedmapper.util.SeedIdentifier;
@@ -79,10 +80,14 @@ public void onInitializeClient() {
7980
} catch (IllegalStateException _) {
8081
}
8182
}
83+
if (event.config().equals("ManualWaypointCompassOverlay")) {
84+
Configs.applyWaypointCompassOverlaySetting();
85+
}
8286
})
8387
.build();
8488

8589
SimpleWaypointsAPI.getInstance().registerCommandAlias("sm:waypoint");
90+
Configs.applyWaypointCompassOverlaySetting();
8691

8792
SeedDatabaseHelper.fetchSeeds();
8893

@@ -101,6 +106,7 @@ public void onInitializeClient() {
101106
WorldPresetManager.init();
102107
RenderManager.registerEvents();
103108
SeedMapMinimapManager.registerHud();
109+
ManualWaypointCompassOverlay.registerHud();
104110
}
105111

106112
private static void registerCommands(CommandDispatcher<FabricClientCommandSource> dispatcher, CommandBuildContext context) {

src/main/java/dev/xpple/seedmapper/config/Configs.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,51 @@ private static Component getPlayerDirectionArrowComment() {
213213
return Component.translatable("config.showPlayerDirectionArrow.comment");
214214
}
215215

216+
@Config(comment = "getManualWaypointCompassOverlayComment")
217+
public static boolean ManualWaypointCompassOverlay = false;
218+
219+
private static Component getManualWaypointCompassOverlayComment() {
220+
return Component.translatable("config.manualWaypointCompassOverlay.comment");
221+
}
222+
223+
@Config
224+
public static Map<String, String> WaypointCompassEnabled = new HashMap<>();
225+
226+
public static java.util.Set<String> getWaypointCompassEnabled(String worldIdentifier) {
227+
if (worldIdentifier == null || worldIdentifier.isBlank()) {
228+
return new java.util.HashSet<>();
229+
}
230+
String raw = WaypointCompassEnabled.get(worldIdentifier);
231+
if (raw == null || raw.isBlank()) {
232+
return new java.util.HashSet<>();
233+
}
234+
java.util.Set<String> names = new java.util.HashSet<>();
235+
for (String part : raw.split(",")) {
236+
if (!part.isBlank()) {
237+
names.add(part.trim());
238+
}
239+
}
240+
return names;
241+
}
242+
243+
public static void setWaypointCompassEnabled(String worldIdentifier, java.util.Set<String> names) {
244+
if (worldIdentifier == null || worldIdentifier.isBlank()) {
245+
return;
246+
}
247+
if (names == null || names.isEmpty()) {
248+
WaypointCompassEnabled.remove(worldIdentifier);
249+
return;
250+
}
251+
WaypointCompassEnabled.put(worldIdentifier, String.join(",", names));
252+
}
253+
254+
public static void applyWaypointCompassOverlaySetting() {
255+
try {
256+
dev.xpple.simplewaypoints.config.Configs.waypointMarkerRenderLimit = 0;
257+
} catch (Throwable ignored) {
258+
}
259+
}
260+
216261
@Config(chatRepresentation = "listToggledFeatures")
217262
public static EnumSet<MapFeature> ToggledFeatures = Util.make(() -> {
218263
EnumSet<MapFeature> toggledFeatures = EnumSet.allOf(MapFeature.class);
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package dev.xpple.seedmapper.seedmap;
2+
3+
import dev.xpple.seedmapper.config.Configs;
4+
import dev.xpple.simplewaypoints.api.SimpleWaypointsAPI;
5+
import dev.xpple.simplewaypoints.api.Waypoint;
6+
import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback;
7+
import net.minecraft.ChatFormatting;
8+
import net.minecraft.client.Camera;
9+
import net.minecraft.client.DeltaTracker;
10+
import net.minecraft.client.Minecraft;
11+
import net.minecraft.client.gui.GuiGraphics;
12+
import net.minecraft.client.renderer.GameRenderer;
13+
import net.minecraft.network.chat.Component;
14+
import net.minecraft.network.chat.ComponentUtils;
15+
import net.minecraft.world.entity.Entity;
16+
import net.minecraft.world.phys.Vec3;
17+
import org.joml.Vector2d;
18+
19+
import java.util.ArrayList;
20+
import java.util.Comparator;
21+
import java.util.List;
22+
import java.util.Map;
23+
import java.util.Set;
24+
25+
public final class ManualWaypointCompassOverlay {
26+
private ManualWaypointCompassOverlay() {
27+
}
28+
29+
public static void registerHud() {
30+
HudRenderCallback.EVENT.register(ManualWaypointCompassOverlay::render);
31+
}
32+
33+
private static void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker) {
34+
Configs.applyWaypointCompassOverlaySetting();
35+
if (!Configs.ManualWaypointCompassOverlay) {
36+
return;
37+
}
38+
Minecraft minecraft = Minecraft.getInstance();
39+
if (minecraft.level == null) {
40+
return;
41+
}
42+
SimpleWaypointsAPI api = SimpleWaypointsAPI.getInstance();
43+
String worldIdentifier = api.getWorldIdentifier(minecraft);
44+
if (worldIdentifier == null || worldIdentifier.isBlank()) {
45+
return;
46+
}
47+
Set<String> enabled = Configs.getWaypointCompassEnabled(worldIdentifier);
48+
if (enabled.isEmpty()) {
49+
return;
50+
}
51+
Map<String, Waypoint> worldWaypoints = api.getWorldWaypoints(worldIdentifier);
52+
if (worldWaypoints == null || worldWaypoints.isEmpty()) {
53+
return;
54+
}
55+
56+
GameRenderer gameRenderer = minecraft.gameRenderer;
57+
Camera camera = gameRenderer.getMainCamera();
58+
Entity cameraEntity = camera.entity();
59+
float partialTicks = deltaTracker.getGameTimeDeltaPartialTick(true);
60+
double verticalFovRad = Math.toRadians(readFov(gameRenderer, camera, partialTicks));
61+
double aspectRatio = (double) minecraft.getWindow().getGuiScaledWidth() / minecraft.getWindow().getGuiScaledHeight();
62+
double horizontalFovRad = 2 * Math.atan(Math.tan(verticalFovRad / 2) * aspectRatio);
63+
64+
Vec3 viewVector3 = cameraEntity.getViewVector(1.0f);
65+
Vector2d viewVector = new Vector2d(viewVector3.x, viewVector3.z);
66+
Vector2d position = new Vector2d(cameraEntity.getEyePosition().x, cameraEntity.getEyePosition().z);
67+
68+
List<WaypointMarkerLocation> xPositions = new ArrayList<>();
69+
worldWaypoints.forEach((waypointName, waypoint) -> {
70+
if (!enabled.contains(waypointName)) {
71+
return;
72+
}
73+
if (!waypoint.dimension().identifier().equals(minecraft.level.dimension().identifier())) {
74+
return;
75+
}
76+
if (!waypoint.visible()) {
77+
return;
78+
}
79+
80+
double distanceSquared = waypoint.location().distToCenterSqr(cameraEntity.position());
81+
long distance = Math.round(Math.sqrt(distanceSquared));
82+
Component marker = ComponentUtils.wrapInSquareBrackets(Component.literal(waypointName + ' ' + distance).withStyle(ChatFormatting.YELLOW));
83+
Vec3 waypointCenter = waypoint.location().getCenter();
84+
85+
Vector2d waypointLocation = new Vector2d(waypointCenter.x, waypointCenter.z);
86+
double angleRad = viewVector.angle(waypointLocation.sub(position, new Vector2d()));
87+
boolean right = angleRad > 0;
88+
angleRad = Math.abs(angleRad);
89+
90+
int x;
91+
if (angleRad > horizontalFovRad / 2) {
92+
int width = minecraft.font.width(marker);
93+
x = right ? guiGraphics.guiWidth() - width / 2 : width / 2;
94+
} else {
95+
double mv = Math.tan(angleRad) * GameRenderer.PROJECTION_Z_NEAR;
96+
double av = Math.tan(horizontalFovRad / 2) * GameRenderer.PROJECTION_Z_NEAR;
97+
double ab = 2 * av;
98+
double am = right ? mv + av : ab - (mv + av);
99+
double perc = am / ab;
100+
int guiWidth = guiGraphics.guiWidth();
101+
int halfWidth = minecraft.font.width(marker) / 2;
102+
x = Math.clamp((int) (perc * guiWidth), halfWidth, guiWidth - halfWidth);
103+
}
104+
xPositions.add(new WaypointMarkerLocation(marker, x));
105+
});
106+
107+
xPositions.sort(Comparator.comparingInt(WaypointMarkerLocation::location));
108+
109+
List<List<WaypointMarkerLocation>> positions = new ArrayList<>();
110+
positions.add(xPositions);
111+
112+
for (int line = 0; line < positions.size(); line++) {
113+
List<WaypointMarkerLocation> waypointMarkerLocations = positions.get(line);
114+
int i = 0;
115+
while (i < waypointMarkerLocations.size() - 1) {
116+
WaypointMarkerLocation left = waypointMarkerLocations.get(i);
117+
WaypointMarkerLocation right = waypointMarkerLocations.get(i + 1);
118+
int leftX = left.location();
119+
int rightX = right.location();
120+
int leftWidth = minecraft.font.width(left.marker());
121+
int rightWidth = minecraft.font.width(right.marker());
122+
if (leftWidth / 2 + rightWidth / 2 > rightX - leftX) {
123+
if (line + 1 == positions.size()) {
124+
positions.add(new ArrayList<>());
125+
}
126+
List<WaypointMarkerLocation> nextLevel = positions.get(line + 1);
127+
WaypointMarkerLocation removed = waypointMarkerLocations.remove(i + 1);
128+
nextLevel.add(removed);
129+
} else {
130+
i++;
131+
}
132+
}
133+
}
134+
135+
for (int line = 0; line < positions.size(); line++) {
136+
List<WaypointMarkerLocation> w = positions.get(line);
137+
for (WaypointMarkerLocation waypoint : w) {
138+
guiGraphics.drawCenteredString(minecraft.font, waypoint.marker(), waypoint.location(), 1 + line * minecraft.font.lineHeight, 0xFFFFFFFF);
139+
}
140+
}
141+
}
142+
143+
private record WaypointMarkerLocation(Component marker, int location) {
144+
}
145+
146+
private static double readFov(GameRenderer gameRenderer, Camera camera, float partialTicks) {
147+
try {
148+
java.lang.reflect.Method method = GameRenderer.class.getDeclaredMethod("getFov", Camera.class, float.class, boolean.class);
149+
method.setAccessible(true);
150+
Object value = method.invoke(gameRenderer, camera, partialTicks, true);
151+
if (value instanceof Number number) {
152+
return number.doubleValue();
153+
}
154+
} catch (Throwable ignored) {
155+
}
156+
Minecraft minecraft = Minecraft.getInstance();
157+
return minecraft.options.fov().get();
158+
}
159+
}

src/main/java/dev/xpple/seedmapper/seedmap/SeedMapMinimapScreen.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ private void renderMinimapIcons(GuiGraphics guiGraphics, double translateX, doub
151151
}
152152

153153
private void renderWaypointLabels(GuiGraphics guiGraphics, double translateX, double translateY, double centerX, double centerY, float rotationRadians) {
154-
if (this.waypointLabels.isEmpty()) {
154+
if (!Configs.ManualWaypointCompassOverlay || this.waypointLabels.isEmpty()) {
155155
return;
156156
}
157157
double cos = Math.cos(rotationRadians);

0 commit comments

Comments
 (0)