Skip to content

Commit

Permalink
Better P2P: Sorting Improvements + Show Distance
Browse files Browse the repository at this point in the history
  • Loading branch information
IntegerLimit committed Dec 26, 2024
1 parent 7283ea2 commit d6207f0
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.nomiceu.nomilabs.integration.betterp2p;

import net.minecraft.util.math.Vec3d;

public interface AccessibleInfoList {

void labs$setPlayerPos(Vec3d pos);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.nomiceu.nomilabs.integration.betterp2p;

import net.minecraft.util.math.Vec3d;

public interface AccessibleInfoWrapper {

void labs$calculateDistance(Vec3d playerPos);

double labs$getDistance();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package com.nomiceu.nomilabs.integration.betterp2p;

import java.util.Comparator;
import java.util.function.Function;

import com.projecturanus.betterp2p.client.gui.InfoWrapper;

public enum SortModes {

DEFAULT(SortModes::compDefault);

private final Function<InfoWrapper, Comparator<InfoWrapper>> compFromSelected;

/**
* Create a Sort Mode.
*
* @param compFromSelected Function that takes the selected p2p and returns a comparator.
* You do not need to handle the case where either one is the selected p2p.
* Note that item smaller = in front!
* Selected p2p may be null!
*/
SortModes(Function<InfoWrapper, Comparator<InfoWrapper>> compFromSelected) {
this.compFromSelected = compFromSelected;
}

public Comparator<InfoWrapper> getComp(InfoWrapper selected) {
var applyComp = compFromSelected.apply(selected);
return (a, b) -> {
if (selected != null) {
// Selected first
if (a.getLoc().equals(selected.getLoc())) return -1;
if (b.getLoc().equals(selected.getLoc())) return 1;
}

return applyComp.compare(a, b);
};
}

/* Sorters */
private static Comparator<InfoWrapper> compDefault(InfoWrapper selected) {
return (a, b) -> {
if (selected != null) {
// Same freq. as selected, priority over rest
// Checking for unbound is not needed, just have all unbound at front if selected is unbound
if (a.getFrequency() == selected.getFrequency()) {
if (b.getFrequency() != selected.getFrequency()) return -1;
return compareTypeThenDist(a, b);
}

if (b.getFrequency() == selected.getFrequency()) return 1;
}
if (a.getFrequency() != b.getFrequency()) return b.getFrequency() - a.getFrequency();

return compareTypeThenDist(a, b);
};
}

private static int compareTypeThenDist(InfoWrapper a, InfoWrapper b) {
if (a.getOutput() != b.getOutput()) return a.getOutput() ? 1 : -1; // Inputs First

return getDistance(a) > getDistance(b) ? 1 : -1; // Furthest Last
}

private static double getDistance(InfoWrapper info) {
return ((AccessibleInfoWrapper) (Object) (info)).labs$getDistance();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.nomiceu.nomilabs.mixin.betterp2p;

import net.minecraft.client.gui.GuiScreen;

import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
Expand All @@ -9,6 +11,7 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import com.nomiceu.nomilabs.integration.betterp2p.AccessibleGuiAdvancedMemoryCard;
import com.nomiceu.nomilabs.integration.betterp2p.AccessibleInfoList;
import com.nomiceu.nomilabs.integration.betterp2p.LabsClientCache;
import com.projecturanus.betterp2p.client.gui.GuiAdvancedMemoryCard;
import com.projecturanus.betterp2p.client.gui.InfoList;
Expand All @@ -19,10 +22,11 @@
import kotlin.Pair;

/**
* Allows accessing needed functions and fields. Also fills up LabsClientCache.
* Allows accessing needed functions and fields, and initializes playerPos field in InfoList. Also fills up
* LabsClientCache.
*/
@Mixin(value = GuiAdvancedMemoryCard.class, remap = false)
public abstract class GuiAdvancedMemoryCardMixin implements AccessibleGuiAdvancedMemoryCard {
public abstract class GuiAdvancedMemoryCardMixin extends GuiScreen implements AccessibleGuiAdvancedMemoryCard {

@Shadow
private BetterMemoryCardModes mode;
Expand Down Expand Up @@ -65,6 +69,11 @@ public abstract class GuiAdvancedMemoryCardMixin implements AccessibleGuiAdvance
typeSelector.setVisible(false);
}

@Inject(method = "initGui", at = @At("HEAD"))
private void setupInfoListPlayerPos(CallbackInfo ci) {
((AccessibleInfoList) (Object) infos).labs$setPlayerPos(mc.player.getPositionVector());
}

@Inject(method = "refreshOverlay", at = @At("HEAD"))
private void fillLabsCache(CallbackInfo ci) {
LabsClientCache.inputLoc.clear();
Expand Down
115 changes: 115 additions & 0 deletions src/main/java/com/nomiceu/nomilabs/mixin/betterp2p/InfoListMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.nomiceu.nomilabs.mixin.betterp2p;

import java.util.Collection;
import java.util.HashMap;
import java.util.stream.Collectors;

import javax.annotation.Nullable;

import net.minecraft.util.math.Vec3d;

import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import com.google.common.collect.ImmutableList;
import com.nomiceu.nomilabs.integration.betterp2p.AccessibleInfoList;
import com.nomiceu.nomilabs.integration.betterp2p.AccessibleInfoWrapper;
import com.nomiceu.nomilabs.integration.betterp2p.SortModes;
import com.projecturanus.betterp2p.client.gui.InfoFilter;
import com.projecturanus.betterp2p.client.gui.InfoList;
import com.projecturanus.betterp2p.client.gui.InfoWrapper;
import com.projecturanus.betterp2p.client.gui.widget.WidgetScrollBar;
import com.projecturanus.betterp2p.network.data.P2PLocation;

/**
* Handles updating infos' distance to player, and allows for custom sorting.
*/
@Mixin(value = InfoList.class, remap = false)
public abstract class InfoListMixin implements AccessibleInfoList {

@Shadow
@Final
private HashMap<P2PLocation, InfoWrapper> masterMap;

@Shadow
@Final
private InfoFilter filter;

@Shadow
@Nullable
public abstract InfoWrapper getSelectedInfo();

@Shadow
protected abstract String getSearchStr();

@Unique
private Vec3d labs$playerPos;

@Unique
@Override
public void labs$setPlayerPos(Vec3d pos) {
labs$playerPos = pos;
calcDistFor(masterMap.values());
}

@Inject(method = "rebuild", at = @At("HEAD"))
private void calcDistanceInRebuild(Collection<InfoWrapper> updateList, WidgetScrollBar scrollbar, int numEntries,
CallbackInfo ci) {
calcDistFor(updateList);
}

@Inject(method = "update", at = @At("HEAD"))
private void calcDistanceInUpdate(Collection<InfoWrapper> updateList, WidgetScrollBar scrollbar, int numEntries,
CallbackInfo ci) {
calcDistFor(updateList);
}

@Unique
private void calcDistFor(Iterable<InfoWrapper> infos) {
for (InfoWrapper info : infos) {
((AccessibleInfoWrapper) (Object) info).labs$calculateDistance(labs$playerPos);
}
}

@Inject(method = "resort", at = @At("HEAD"), cancellable = true)
private void customSortLogic(CallbackInfo ci) {
labs$getThis().getSorted().sort(SortModes.DEFAULT.getComp(getSelectedInfo()));
ci.cancel();
}

@Inject(method = "refilter",
at = @At(value = "HEAD"),
cancellable = true)
private void newFilterLogic(CallbackInfo ci) {
ci.cancel();

// Shortcut
String toSearch = getSearchStr().trim();
if (toSearch.isEmpty()) {
labs$getThis().setFiltered(ImmutableList.copyOf(labs$getThis().getSorted()));
return;
}

filter.updateFilter(toSearch.toLowerCase());
labs$getThis().setFiltered(labs$getThis().getSorted().stream()
.filter(info -> {
if (getSelectedInfo() != null && info.getLoc().equals(getSelectedInfo().getLoc())) return true;

for (var entry : filter.getActiveFilters().entrySet()) {
if (!entry.getKey().getFilter().invoke(info, entry.getValue())) return false;
}
return true;
}).sorted(SortModes.DEFAULT.getComp(getSelectedInfo()))
.collect(Collectors.toList()));
}

@Unique
private InfoList labs$getThis() {
return (InfoList) (Object) this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.nomiceu.nomilabs.mixin.betterp2p;

import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.TextFormatting;

import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import com.nomiceu.nomilabs.integration.betterp2p.AccessibleInfoWrapper;
import com.projecturanus.betterp2p.client.gui.InfoWrapper;
import com.projecturanus.betterp2p.network.data.P2PInfo;
import com.projecturanus.betterp2p.network.data.P2PLocation;

/**
* Allows saving of each P2P's distance to the player.
*/
@Mixin(value = InfoWrapper.class, remap = false)
public class InfoWrapperMixin implements AccessibleInfoWrapper {

@Shadow
@Final
private P2PLocation loc;

@Unique
private double labs$distanceToPlayer = 0.0;

@Unique
@Override
public double labs$getDistance() {
return labs$distanceToPlayer;
}

@Unique
@Override
public void labs$calculateDistance(Vec3d playerPos) {
// Change X, Y and Z Positions Based on Facing

// Add 0.5 (middle of block)
double x = loc.getPos().getX() + 0.5;
double y = loc.getPos().getY() + 0.5;
double z = loc.getPos().getZ() + 0.5;

// Amt to add/subtract base on facing. Since P2P is 2 pixels wide (1/8 of block),
// this leaves 1/16 from the half (middle of P2P)
double mod = 0.4375;

switch (loc.getFacing()) {
case NORTH -> z -= mod;
case SOUTH -> z += mod;
case WEST -> x -= mod;
case EAST -> x += mod;
case UP -> y += mod;
case DOWN -> y -= mod;
}

double distance = Math.sqrt(playerPos.squareDistanceTo(x, y, z));

// Round to 1dp
labs$distanceToPlayer = Math.round(distance * 10) / 10.0;
}

@Inject(method = "<init>", at = @At(value = "TAIL"))
private void provideChannelInfo(P2PInfo info, CallbackInfo ci) {
var channels = labs$getThis().getChannels();
if (channels != null)
// Index 0-3: Default Info, 4+, Bound/Unbound, Offline/Online
labs$getThis().getHoverInfo().add(4, TextFormatting.LIGHT_PURPLE + channels);
}

@Unique
private InfoWrapper labs$getThis() {
return ((InfoWrapper) (Object) this);
}
}
Loading

2 comments on commit d6207f0

@ChromaPIE
Copy link

@ChromaPIE ChromaPIE commented on d6207f0 Dec 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some of the current changes to adv p2p made it malfunctioning.
distance always shows 0m, and performing binding wont refresh the list right away but instead you have to close the window then reenter it to see the change

also, there's a problem with searching. to reproduce: type something into the search box, close the window, re-open it, you'll get a completely blank list. emptying or typing something more in the input box refreshes the list.

@IntegerLimit
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the issues. The first one is definitely an issue with obfuscation, will be very easy to fix. I will take a look at the second and third issues.

Please sign in to comment.