-
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
155 additions
and
126 deletions.
There are no files selected for viewing
23 changes: 19 additions & 4 deletions
23
src/main/java/dev/tr7zw/exordium/access/TablistAccess.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,24 @@ | ||
package dev.tr7zw.exordium.access; | ||
|
||
import net.minecraft.world.scores.Objective; | ||
import net.minecraft.world.scores.Scoreboard; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.UUID; | ||
|
||
public interface TablistAccess extends VanillaBufferAccess.PlayerListOverlayAccess { | ||
void updateState(Scoreboard scoreboard, Objective objective); | ||
import net.minecraft.client.gui.Gui; | ||
import net.minecraft.client.gui.components.PlayerTabOverlay; | ||
import net.minecraft.client.multiplayer.PlayerInfo; | ||
import net.minecraft.network.chat.Component; | ||
|
||
public interface TablistAccess { | ||
|
||
Gui getGui(); | ||
|
||
Map<UUID, PlayerTabOverlay.HealthState> getHealthStates(); | ||
|
||
Component getHeader(); | ||
|
||
Component getFooter(); | ||
|
||
List<PlayerInfo> getPlayerInfos(); | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
src/main/java/dev/tr7zw/exordium/components/vanilla/PlayerListComponent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package dev.tr7zw.exordium.components.vanilla; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
import dev.tr7zw.exordium.access.TablistAccess; | ||
import dev.tr7zw.exordium.components.BufferComponent; | ||
import dev.tr7zw.util.NMSHelper; | ||
import lombok.Getter; | ||
import net.minecraft.client.Minecraft; | ||
import net.minecraft.client.gui.components.PlayerTabOverlay; | ||
import net.minecraft.client.multiplayer.PlayerInfo; | ||
import net.minecraft.network.chat.Component; | ||
import net.minecraft.resources.ResourceLocation; | ||
import net.minecraft.world.entity.player.Player; | ||
import net.minecraft.world.level.GameType; | ||
import net.minecraft.world.scores.Objective; | ||
import net.minecraft.world.scores.PlayerScoreEntry; | ||
import net.minecraft.world.scores.PlayerTeam; | ||
import net.minecraft.world.scores.Scoreboard; | ||
import net.minecraft.world.scores.criteria.ObjectiveCriteria; | ||
|
||
public class PlayerListComponent | ||
implements BufferComponent<dev.tr7zw.exordium.components.vanilla.PlayerListComponent.PlayerListContext> { | ||
|
||
private static final Minecraft minecraft = Minecraft.getInstance(); | ||
@Getter | ||
private static final ResourceLocation id = NMSHelper.getResourceLocation("minecraft", "crosshair"); | ||
|
||
private List<Integer> playerInfoHashes = new ArrayList<>(); | ||
private int headerHash = 0; | ||
private int footerHash = 0; | ||
private int scoreboardHash = 0; | ||
private int objectiveHash = 0; | ||
private Objective lastTrackedObjective; | ||
|
||
public record PlayerListContext(TablistAccess tablist, Scoreboard scoreboard, Objective objective) { | ||
} | ||
|
||
@Override | ||
public void captureState(PlayerListContext context) { | ||
playerInfoHashes = fastGetPlayerInfoListHashCode(context, context.tablist().getPlayerInfos()); | ||
headerHash = context.tablist().getHeader() == null ? 0 : context.tablist().getHeader().getString().hashCode(); | ||
footerHash = context.tablist().getFooter() == null ? 0 : context.tablist().getFooter().getString().hashCode(); | ||
} | ||
|
||
@Override | ||
public boolean hasChanged(int tickCount, PlayerListContext context) { | ||
boolean scoreboardOrObjectiveChange = scoreboardOrObjectiveChanged(context.scoreboard, context.objective); | ||
int newHeaderHash = context.tablist().getHeader() == null ? 0 | ||
: context.tablist().getHeader().getString().hashCode(); | ||
int newFooterHash = context.tablist().getFooter() == null ? 0 | ||
: context.tablist().getFooter().getString().hashCode(); | ||
boolean plaverInfoOutdated = !playerInfoHashes | ||
.equals(fastGetPlayerInfoListHashCode(context, context.tablist().getPlayerInfos())); | ||
return plaverInfoOutdated || headerHash != newHeaderHash || footerHash != newFooterHash | ||
|| scoreboardOrObjectiveChange; | ||
} | ||
|
||
public boolean scoreboardOrObjectiveChanged(Scoreboard scoreboard, Objective objective) { | ||
if (objective == null && lastTrackedObjective == null) | ||
return false; | ||
|
||
int scoreboardHashCode = 1; | ||
for (PlayerScoreEntry score : scoreboard.listPlayerScores(objective)) | ||
scoreboardHashCode = 31 * scoreboardHashCode + (score == null ? 0 : score.value()); | ||
|
||
int newObjectiveHashCode = objective == null ? 0 : objective.getName().hashCode(); | ||
if (scoreboardHashCode == scoreboardHash && newObjectiveHashCode == objectiveHash) | ||
return false; | ||
scoreboardHash = scoreboardHashCode; | ||
objectiveHash = newObjectiveHashCode; | ||
lastTrackedObjective = objective; | ||
return true; | ||
} | ||
|
||
public List<Integer> fastGetPlayerInfoListHashCode(PlayerListContext context, List<PlayerInfo> playerInfos) { | ||
ArrayList<Integer> hashCodes = new ArrayList<>(); | ||
for (PlayerInfo playerInfo : playerInfos) { | ||
if (playerInfo == null) | ||
continue; | ||
|
||
int playerHash = playerInfo.getProfile().getId().hashCode(); | ||
playerHash += playerInfo.getProfile().getName().hashCode(); | ||
if (playerInfo.getTabListDisplayName() != null) { | ||
playerHash += playerInfo.getTabListDisplayName().getString().hashCode(); | ||
playerHash += playerInfo.getTabListDisplayName().getStyle().hashCode(); | ||
} else { | ||
PlayerTeam playerTeam = playerInfo.getTeam(); | ||
if (playerTeam == null) | ||
continue; | ||
Component prefix = playerTeam.getPlayerPrefix(); | ||
Component suffix = playerTeam.getPlayerSuffix(); | ||
playerHash += Objects.hash(playerTeam.getColor(), prefix.getStyle(), prefix.getString(), | ||
suffix.getStyle(), suffix.getString()); | ||
} | ||
playerHash += playerInfo.getGameMode() == GameType.SPECTATOR ? 31 : 0; | ||
playerHash += playerInfo.getSkin().texture().hashCode(); | ||
playerHash += playerInfo.getLatency() * 63; | ||
|
||
if (lastTrackedObjective != null | ||
&& lastTrackedObjective.getRenderType() == ObjectiveCriteria.RenderType.HEARTS) { | ||
Player player = minecraft.level.getPlayerByUUID(playerInfo.getProfile().getId()); | ||
|
||
if (player != null) { | ||
PlayerTabOverlay.HealthState healthState = context.tablist().getHealthStates().computeIfAbsent( | ||
playerInfo.getProfile().getId(), | ||
(_uuid) -> new PlayerTabOverlay.HealthState(lastTrackedObjective.getScoreboard() | ||
.getOrCreatePlayerScore(player, lastTrackedObjective).get())); | ||
playerHash += healthState.isBlinking(context.tablist.getGui().getGuiTicks()) ? 63 : 127; | ||
} | ||
} | ||
hashCodes.add(playerHash); | ||
} | ||
return hashCodes; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
122 changes: 10 additions & 112 deletions
122
src/main/java/dev/tr7zw/exordium/mixin/PlayerTabOverlayMixin.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,140 +1,38 @@ | ||
package dev.tr7zw.exordium.mixin; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
import java.util.UUID; | ||
|
||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Shadow; | ||
|
||
import dev.tr7zw.exordium.ExordiumModBase; | ||
import dev.tr7zw.exordium.access.TablistAccess; | ||
import dev.tr7zw.exordium.render.BufferedComponent; | ||
import dev.tr7zw.exordium.render.LegacyBuffer; | ||
import net.minecraft.client.Minecraft; | ||
import lombok.Getter; | ||
import net.minecraft.client.gui.Gui; | ||
import net.minecraft.client.gui.components.PlayerTabOverlay; | ||
import net.minecraft.client.multiplayer.PlayerInfo; | ||
import net.minecraft.network.chat.Component; | ||
import net.minecraft.world.entity.player.Player; | ||
import net.minecraft.world.level.GameType; | ||
import net.minecraft.world.scores.Objective; | ||
import net.minecraft.world.scores.PlayerScoreEntry; | ||
import net.minecraft.world.scores.PlayerTeam; | ||
import net.minecraft.world.scores.Scoreboard; | ||
import net.minecraft.world.scores.criteria.ObjectiveCriteria; | ||
|
||
@Mixin(PlayerTabOverlay.class) | ||
public abstract class PlayerTabOverlayMixin implements TablistAccess { | ||
@Shadow | ||
private Minecraft minecraft; | ||
public class PlayerTabOverlayMixin implements TablistAccess { | ||
|
||
@Shadow | ||
@Getter | ||
private Gui gui; | ||
@Shadow | ||
@Getter | ||
private Map<UUID, PlayerTabOverlay.HealthState> healthStates; | ||
private ArrayList<Integer> playerInfoHashes = new ArrayList<>(); | ||
private int headerHash = 0; | ||
private int footerHash = 0; | ||
private int scoreboardHash = 0; | ||
private int objectiveHash = 0; | ||
@Shadow | ||
@Getter | ||
private Component header; | ||
@Shadow | ||
@Getter | ||
private Component footer; | ||
private Objective lastTrackedObjective; | ||
private boolean outdated; | ||
private LegacyBuffer playerlistBufferedComponent = new LegacyBuffer(true, | ||
() -> ExordiumModBase.instance.config.tablistSettings) { | ||
|
||
@Override | ||
public boolean shouldRenderNextCappedFrame() { | ||
return outdated; | ||
} | ||
|
||
@Override | ||
public void captureState() { | ||
playerInfoHashes = fastGetPlayerInfoListHashCode(getPlayerInfos()); | ||
headerHash = header == null ? 0 : header.getString().hashCode(); | ||
footerHash = footer == null ? 0 : footer.getString().hashCode(); | ||
} | ||
}; | ||
|
||
@Override | ||
public void updateState(Scoreboard scoreboard, Objective objective) { | ||
boolean scoreboardOrObjectiveChange = scoreboardOrObjectiveChanged(scoreboard, objective); | ||
int newHeaderHash = header == null ? 0 : header.getString().hashCode(); | ||
int newFooterHash = footer == null ? 0 : footer.getString().hashCode(); | ||
boolean plaverInfoOutdated = !playerInfoHashes.equals(fastGetPlayerInfoListHashCode(getPlayerInfos())); | ||
outdated = plaverInfoOutdated || headerHash != newHeaderHash || footerHash != newFooterHash | ||
|| scoreboardOrObjectiveChange; | ||
} | ||
|
||
public boolean scoreboardOrObjectiveChanged(Scoreboard scoreboard, Objective objective) { | ||
if (objective == null && lastTrackedObjective == null) | ||
return false; | ||
|
||
int scoreboardHashCode = 1; | ||
for (PlayerScoreEntry score : scoreboard.listPlayerScores(objective)) | ||
scoreboardHashCode = 31 * scoreboardHashCode + (score == null ? 0 : score.value()); | ||
|
||
int newObjectiveHashCode = objective == null ? 0 : objective.getName().hashCode(); | ||
if (scoreboardHashCode == scoreboardHash && newObjectiveHashCode == objectiveHash) | ||
return false; | ||
scoreboardHash = scoreboardHashCode; | ||
objectiveHash = newObjectiveHashCode; | ||
lastTrackedObjective = objective; | ||
return true; | ||
} | ||
|
||
public ArrayList<Integer> fastGetPlayerInfoListHashCode(List<PlayerInfo> playerInfos) { | ||
ArrayList<Integer> hashCodes = new ArrayList<>(); | ||
for (PlayerInfo playerInfo : playerInfos) { | ||
if (playerInfo == null) | ||
continue; | ||
|
||
int playerHash = playerInfo.getProfile().getId().hashCode(); | ||
playerHash += playerInfo.getProfile().getName().hashCode(); | ||
if (playerInfo.getTabListDisplayName() != null) { | ||
playerHash += playerInfo.getTabListDisplayName().getString().hashCode(); | ||
playerHash += playerInfo.getTabListDisplayName().getStyle().hashCode(); | ||
} else { | ||
PlayerTeam playerTeam = playerInfo.getTeam(); | ||
if (playerTeam == null) | ||
continue; | ||
Component prefix = playerTeam.getPlayerPrefix(); | ||
Component suffix = playerTeam.getPlayerSuffix(); | ||
playerHash += Objects.hash(playerTeam.getColor(), prefix.getStyle(), prefix.getString(), | ||
suffix.getStyle(), suffix.getString()); | ||
} | ||
playerHash += playerInfo.getGameMode() == GameType.SPECTATOR ? 31 : 0; | ||
playerHash += playerInfo.getSkin().texture().hashCode(); | ||
playerHash += playerInfo.getLatency() * 63; | ||
|
||
if (lastTrackedObjective != null | ||
&& lastTrackedObjective.getRenderType() == ObjectiveCriteria.RenderType.HEARTS) { | ||
Player player = minecraft.level.getPlayerByUUID(playerInfo.getProfile().getId()); | ||
|
||
if (player != null) { | ||
PlayerTabOverlay.HealthState healthState = this.healthStates.computeIfAbsent( | ||
playerInfo.getProfile().getId(), | ||
(_uuid) -> new PlayerTabOverlay.HealthState(lastTrackedObjective.getScoreboard() | ||
.getOrCreatePlayerScore(player, lastTrackedObjective).get())); | ||
playerHash += healthState.isBlinking(this.gui.getGuiTicks()) ? 63 : 127; | ||
} | ||
} | ||
hashCodes.add(playerHash); | ||
} | ||
return hashCodes; | ||
} | ||
|
||
@Shadow | ||
public abstract List<PlayerInfo> getPlayerInfos(); | ||
|
||
@Override | ||
public LegacyBuffer getPlayerListOverlayBuffer() { | ||
return playerlistBufferedComponent; | ||
} | ||
public List<PlayerInfo> getPlayerInfos() { | ||
return null; | ||
}; | ||
|
||
} |