Try implementing "copy to clipboard" waypoint menu action

This commit is contained in:
Vftdan 2024-09-04 22:49:57 +02:00
parent d6f3a35191
commit 0e55d1cc37
6 changed files with 351 additions and 1 deletions

View File

@ -1,10 +1,52 @@
package io.github.vftdan.xaeromapaddon; package io.github.vftdan.xaeromapaddon;
import java.lang.reflect.Field;
import net.fabricmc.api.ClientModInitializer; import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.loader.api.FabricLoader;
import io.github.vftdan.xaeromapaddon.worldmap.WaypointRightClickOptionsRegistry;
import io.github.vftdan.xaeromapaddon.worldmap.waypointactions.ClipboardCopyWaypointAction;
import io.github.vftdan.xaeromapaddon.worldmap.WaypointReaderDecorator;
import xaero.map.mods.SupportMods;
import xaero.map.mods.SupportXaeroMinimap;
import xaero.map.mods.gui.WaypointRenderer;
import xaero.map.mods.gui.WaypointReader;
import xaero.map.element.MapElementRenderer;
public class VftdansXaerosMapAddonClient implements ClientModInitializer { public class VftdansXaerosMapAddonClient implements ClientModInitializer {
@Override @Override
public void onInitializeClient() { public void onInitializeClient() {
// This entrypoint is suitable for setting up client-specific logic, such as rendering. // This entrypoint is suitable for setting up client-specific logic, such as rendering.
{
WaypointRightClickOptionsRegistry registry = WaypointRightClickOptionsRegistry.getInstance();
registry.addFactory(new ClipboardCopyWaypointAction());
}
if (FabricLoader.getInstance().isModLoaded("xaeros-world-map")) {
injectWaypointReaderDecorator();
} else {
System.err.println("No xaeros-world-map");
}
} }
}
void injectWaypointReaderDecorator() {
try {
SupportXaeroMinimap supportMinimap = SupportMods.xaeroMinimap;
if (supportMinimap == null) {
System.err.println("No xaeroMinimap mod support");
return;
}
Field waypointRendererField = SupportXaeroMinimap.class.getDeclaredField("waypointRenderer");
waypointRendererField.setAccessible(true);
WaypointRenderer waypointRenderer = (WaypointRenderer) waypointRendererField.get(supportMinimap);
Field waypointReaderField = MapElementRenderer.class.getDeclaredField("reader");
waypointReaderField.setAccessible(true);
waypointReaderField.set(waypointRenderer, new WaypointReaderDecorator((WaypointReader) waypointReaderField.get(waypointRenderer)));
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,157 @@
package io.github.vftdan.xaeromapaddon.worldmap;
import java.util.ArrayList;
import net.minecraft.client.MinecraftClient;
import xaero.map.mods.gui.WaypointReader;
import xaero.map.mods.gui.Waypoint;
import xaero.map.mods.gui.WaypointRenderContext;
import xaero.map.gui.CursorBox;
import xaero.map.gui.IRightClickableElement;
import xaero.map.gui.dropdown.rightclick.RightClickOption;
public class WaypointReaderDecorator extends WaypointReader {
private WaypointReader wrapped;
public WaypointReaderDecorator(WaypointReader wrapped) {
this.wrapped = wrapped;
}
@Override
public boolean isMouseOverMenuElement(Waypoint element, int x, int y, int mouseX, int mouseY, MinecraftClient mc) {
return wrapped.isMouseOverMenuElement(element, x, y, mouseX, mouseY, mc);
}
@Override
public boolean isHoveredOnMap(int location, Waypoint element, double mouseX, double mouseZ, double scale, double screenSizeBasedScale, double rendererDimDiv, WaypointRenderContext context, float partialTicks) {
return wrapped.isHoveredOnMap(location, element, mouseX, mouseZ, scale, screenSizeBasedScale, rendererDimDiv, context, partialTicks);
}
@Override
public boolean isOnScreen(Waypoint element, double cameraX, double cameraZ, int width, int height, double scale, double screenSizeBasedScale, double rendererDimDiv, WaypointRenderContext context, float partialTicks) {
return wrapped.isOnScreen(element, cameraX, cameraZ, width, height, scale, screenSizeBasedScale, rendererDimDiv, context, partialTicks);
}
@Override
public CursorBox getTooltip(Waypoint element, WaypointRenderContext context, boolean overMenu) {
return wrapped.getTooltip(element, context, overMenu);
}
@Override
public boolean waypointIsGood(Waypoint w, WaypointRenderContext context) {
return wrapped.waypointIsGood(w, context);
}
@Override
public boolean isHidden(Waypoint element, WaypointRenderContext context) {
return wrapped.isHidden(element, context);
}
@Override
public boolean isInteractable(int location, Waypoint element) {
return wrapped.isInteractable(location, element);
}
@Override
public float getBoxScale(int location, Waypoint element, WaypointRenderContext context) {
return wrapped.getBoxScale(location, element, context);
}
@Override
public double getRenderX(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getRenderX(element, context, partialTicks);
}
@Override
public double getRenderZ(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getRenderZ(element, context, partialTicks);
}
@Override
public int getInteractionBoxLeft(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getInteractionBoxLeft(element, context, partialTicks);
}
@Override
public int getInteractionBoxRight(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getInteractionBoxRight(element, context, partialTicks);
}
@Override
public int getInteractionBoxTop(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getInteractionBoxTop(element, context, partialTicks);
}
@Override
public int getInteractionBoxBottom(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getInteractionBoxBottom(element, context, partialTicks);
}
@Override
public int getLeftSideLength(Waypoint element, MinecraftClient mc) {
return wrapped.getLeftSideLength(element, mc);
}
@Override
public String getMenuName(Waypoint element) {
return wrapped.getMenuName(element);
}
@Override
public int getMenuTextFillLeftPadding(Waypoint element) {
return wrapped.getMenuTextFillLeftPadding(element);
}
@Override
public String getFilterName(Waypoint element) {
return wrapped.getFilterName(element);
}
@Override
public ArrayList<RightClickOption> getRightClickOptions(final Waypoint element, IRightClickableElement target) {
ArrayList<RightClickOption> rightClickOptions = wrapped.getRightClickOptions(element, target);
for (WaypointRightClickOptionFactory factory: WaypointRightClickOptionsRegistry.getInstance()) {
RightClickOption option = factory.create(element, target, rightClickOptions.size());
if (option != null) {
rightClickOptions.add(option);
}
}
return rightClickOptions;
}
@Override
public boolean isRightClickValid(Waypoint element) {
return wrapped.isRightClickValid(element);
}
@Override
public int getRightClickTitleBackgroundColor(Waypoint element) {
return wrapped.getRightClickTitleBackgroundColor(element);
}
@Override
public boolean shouldScaleBoxWithOptionalScale() {
return wrapped.shouldScaleBoxWithOptionalScale();
}
@Override
public int getRenderBoxLeft(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getRenderBoxLeft(element, context, partialTicks);
}
@Override
public int getRenderBoxRight(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getRenderBoxRight(element, context, partialTicks);
}
@Override
public int getRenderBoxTop(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getRenderBoxTop(element, context, partialTicks);
}
@Override
public int getRenderBoxBottom(Waypoint element, WaypointRenderContext context, float partialTicks) {
return wrapped.getRenderBoxBottom(element, context, partialTicks);
}
}

View File

@ -0,0 +1,9 @@
package io.github.vftdan.xaeromapaddon.worldmap;
import xaero.map.mods.gui.Waypoint;
import xaero.map.gui.IRightClickableElement;
import xaero.map.gui.dropdown.rightclick.RightClickOption;
public interface WaypointRightClickOptionFactory {
RightClickOption create(Waypoint waypoint, IRightClickableElement target, int index);
}

View File

@ -0,0 +1,31 @@
package io.github.vftdan.xaeromapaddon.worldmap;
import java.util.ArrayList;
import java.util.Iterator;
public class WaypointRightClickOptionsRegistry implements Iterable<WaypointRightClickOptionFactory> {
private static WaypointRightClickOptionsRegistry instance = null;
public static WaypointRightClickOptionsRegistry getInstance() {
if (instance == null) {
instance = new WaypointRightClickOptionsRegistry();
}
return instance;
}
private ArrayList<WaypointRightClickOptionFactory> factories = new ArrayList();
private WaypointRightClickOptionsRegistry() {
}
public void addFactory(WaypointRightClickOptionFactory factory) {
if (factory == null) {
return;
}
factories.add(factory);
}
public Iterator<WaypointRightClickOptionFactory> iterator() {
return factories.iterator();
}
}

View File

@ -0,0 +1,76 @@
package io.github.vftdan.xaeromapaddon.worldmap.waypointactions;
import java.util.Arrays;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.Clipboard;
import xaero.common.XaeroMinimapSession;
import xaero.common.minimap.waypoints.WaypointWorld;
import xaero.common.minimap.waypoints.WaypointWorldRootContainer;
import xaero.map.mods.gui.Waypoint;
import xaero.map.mods.SupportMods;
public class ClipboardCopyWaypointAction implements WaypointAction {
@Override
public void performAction(Screen screen, Waypoint waypoint) {
String serialized = waypointToShareableString(waypoint);
MinecraftClient client = MinecraftClient.getInstance();
if (client.player != null) {
Clipboard clipboard = new Clipboard();
clipboard.setClipboard(client.getWindow().getHandle(), serialized);
}
}
@Override
public String translationKey() {
return "gui.vftdan.xaero_right_click_waypoint.copy_to_clipboard";
}
public static String waypointToShareableString(Waypoint w) {
WaypointWorld waypointWorld = SupportMods.xaeroMinimap.getWaypointWorld();
String dimInfo;
if (isWaypointWorldInternal(waypointWorld)) {
String containerKey = waypointWorld.getContainer().getKey();
String[] containerKeyElements = containerKey.split("/");
String internalInfo;
if (containerKeyElements.length < 2) {
internalInfo = "waypoints";
} else {
String dim = containerKeyElements[1];
if (dim.equals("dim%0")) {
dim = "overworld";
} else if (dim.equals("dim%-1")) {
dim = "the_nether";
} else if (dim.equals("dim%1")) {
dim = "the_end";
}
containerKeyElements[1] = dim;
internalInfo = String.join("/", Arrays.copyOfRange(containerKeyElements, 1, containerKeyElements.length));
}
dimInfo = "Internal_" + internalInfo;
} else {
dimInfo = "External";
}
String title = escapeWaypointComponent(w.getName());
String icon = escapeWaypointComponent(w.getSymbol());
String x = w.getX() + "";
String y = w.isyIncluded() ? Integer.valueOf(w.getY()) + "" : "~";
String z = w.getZ() + "";
String color = w.getColor() + "";
String isRotation = w.isRotation() + "";
String yaw = w.getYaw() + "";
String dimInfoEscaped = escapeWaypointComponent(dimInfo);
return "xaero-waypoint:" + title + ":" + icon + ":" + x + ":" + y + ":" + z + ":" + color + ":" + isRotation + ":" + yaw + ":" + dimInfoEscaped;
}
public static String escapeWaypointComponent(String unsafe) {
return unsafe.replace(":", "^col^").replace("*", "^ast^").replace("-", "^min^").replace("_", "-");
}
public static boolean isWaypointWorldInternal(WaypointWorld waypointWorld) {
WaypointWorldRootContainer lhs = waypointWorld.getContainer().getRootContainer();
WaypointWorldRootContainer rhs = XaeroMinimapSession.getCurrentSession().getWaypointsManager().getAutoWorld().getContainer().getRootContainer();
return lhs == rhs;
}
}

View File

@ -0,0 +1,35 @@
package io.github.vftdan.xaeromapaddon.worldmap.waypointactions;
import io.github.vftdan.xaeromapaddon.worldmap.WaypointRightClickOptionFactory;
import net.minecraft.client.gui.screen.Screen;
import xaero.map.gui.GuiMap;
import xaero.map.mods.gui.Waypoint;
import xaero.map.gui.IRightClickableElement;
import xaero.map.gui.dropdown.rightclick.RightClickOption;
public interface WaypointAction extends WaypointRightClickOptionFactory {
@Override
default RightClickOption create(Waypoint waypoint, IRightClickableElement target, int index) {
return new WaypointActionRightClickOption(this, waypoint, target, index);
}
void performAction(Screen screen, Waypoint waypoint);
String translationKey();
public static class WaypointActionRightClickOption extends RightClickOption {
WaypointAction action;
Waypoint waypoint;
public WaypointActionRightClickOption(WaypointAction action, Waypoint waypoint, IRightClickableElement target, int index) {
super(action.translationKey(), index, target);
this.action = action;
this.waypoint = waypoint;
}
@Override
public void onAction(Screen screen) {
action.performAction(screen, waypoint);
}
}
}