made list look nicer

This commit is contained in:
Sam van Remortel
2026-05-24 17:15:30 +02:00
parent c032ef1d28
commit 65e6b510d4
3 changed files with 130 additions and 22 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Massuus
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,6 +1,7 @@
package dev.massuus.vaultpartyui.client.screen;
import com.mojang.authlib.GameProfile;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import iskallia.vault.client.data.ClientPartyData;
import iskallia.vault.client.data.ClientPartyInviteState;
@@ -12,9 +13,12 @@ import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.multiplayer.ClientPacketListener;
import net.minecraft.client.multiplayer.PlayerInfo;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.resources.DefaultPlayerSkin;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import java.util.ArrayList;
@@ -33,6 +37,7 @@ public class PartyScreen extends Screen {
private static final int PANEL_PADDING = 10;
private static final int ONLINE_ROW_HEIGHT = 14;
private static final int VISIBLE_ONLINE_ROWS = 8;
private static final int HEAD_SIZE = 8;
private final Screen parentScreen;
@@ -130,11 +135,24 @@ public class PartyScreen extends Screen {
this.font.draw(poseStack, new TranslatableComponent("screen.vaultpartyui.target").getString(), this.targetBox.x, this.targetBox.y - 10, 0xA0A0A0);
}
// Credit
// Credit (clickable)
String credit = "Made by Massuus";
int creditX = this.width - this.font.width(credit) - 8;
int creditY = this.height - 18;
this.font.draw(poseStack, credit, creditX, creditY, 0xAAAAAA);
boolean creditHovered = mouseX >= creditX && mouseX <= creditX + this.font.width(credit) && mouseY >= creditY && mouseY <= creditY + this.font.lineHeight;
int creditColor = creditHovered ? 0xFFFFFF : 0xAAAAAA;
this.font.draw(poseStack, credit, creditX, creditY, creditColor);
// underline when hovered
if (creditHovered) {
int underlineY = creditY + this.font.lineHeight;
fill(poseStack, creditX, underlineY, creditX + this.font.width(credit), underlineY + 1, creditColor);
// tooltip
String tip = new TranslatableComponent("screen.vaultpartyui.credit_tooltip").getString();
int tipX = Math.min(this.width - 10 - this.font.width(tip), (int)mouseX + 8);
int tipY = creditY - this.font.lineHeight - 6;
fill(poseStack, tipX - 4, tipY - 2, tipX + this.font.width(tip) + 4, tipY + this.font.lineHeight + 2, 0xCC111111);
this.font.drawShadow(poseStack, tip, tipX, tipY, 0xFFFFFF);
}
}
@@ -364,7 +382,8 @@ public class PartyScreen extends Screen {
color = statusColor(cachedMember.status);
}
this.font.draw(poseStack, line.toString(), textX, textY, color);
drawPlayerHead(poseStack, memberId, textX, textY + 1);
this.font.draw(poseStack, line.toString(), textX + HEAD_SIZE + 4, textY, color);
textY += 14;
}
}
@@ -401,18 +420,24 @@ public class PartyScreen extends Screen {
// draw player name and per-row action (invite/remove)
this.fill(poseStack, panelX + 10, rowY - 2, panelX + panelWidth - 10, rowY + ONLINE_ROW_HEIGHT - 2, background);
this.font.draw(poseStack, player.name, panelX + 12, rowY, 0xFFFFFF);
drawPlayerHead(poseStack, player.id, panelX + 12, rowY + 1);
this.font.draw(poseStack, player.name, panelX + 12 + HEAD_SIZE + 4, rowY, 0xFFFFFF);
// skip drawing actions for self
if (!player.id.equals(getLocalPlayerId())) {
int actionX = panelX + panelWidth - 84;
if (this.currentParty == null) {
// Invite button
this.font.draw(poseStack, new TranslatableComponent("screen.vaultpartyui.invite").getString(), actionX, rowY, 0xA0E0A0);
} else if (isPartyLeader()) {
// Remove button
boolean targetIsInParty = isPlayerInCurrentParty(player.id);
if (isLocalPlayerInParty()) {
if (targetIsInParty) {
// Remove button for current members, leader only
if (isPartyLeader()) {
this.font.draw(poseStack, new TranslatableComponent("screen.vaultpartyui.remove").getString(), actionX, rowY, 0xE0A0A0);
}
} else {
// Invite button for non-members, visible to any party member
this.font.draw(poseStack, new TranslatableComponent("screen.vaultpartyui.invite").getString(), actionX, rowY, 0xA0E0A0);
}
}
}
rowY += ONLINE_ROW_HEIGHT;
@@ -446,15 +471,23 @@ public class PartyScreen extends Screen {
if (player.id.equals(getLocalPlayerId())) {
return false;
}
int actionX = panelX + ((this.width - 40 - PANEL_PADDING) / 2) - 84;
int actionY = listTop + (index - this.onlineScrollOffset) * ONLINE_ROW_HEIGHT + 4;
// Use the same action bounds and logic as the renderer. The renderer places the action at
// panelX + panelWidth - 84. Recompute panelWidth here for clarity.
int panelWidth = (this.width - 40 - PANEL_PADDING) / 2;
actionX = panelX + panelWidth - 84;
if (mouseX >= actionX && mouseX <= actionX + 70 && mouseY >= actionY && mouseY <= actionY + ONLINE_ROW_HEIGHT - 2) {
if (this.currentParty == null) {
sendPartyCommand("party invite " + player.name);
} else if (isPartyLeader()) {
boolean targetIsInParty = isPlayerInCurrentParty(player.id);
if (isLocalPlayerInParty()) {
if (targetIsInParty) {
if (isPartyLeader()) {
sendPartyCommand("party remove " + player.name);
}
} else {
sendPartyCommand("party invite " + player.name);
}
}
return true;
}
@@ -467,6 +500,34 @@ public class PartyScreen extends Screen {
return leader != null && leader.equals(getLocalPlayerId());
}
private boolean isLocalPlayerInParty() {
if (this.currentParty == null) return false;
UUID local = getLocalPlayerId();
if (local == null) return false;
UUID leader = this.currentParty.getLeader();
if (leader != null && leader.equals(local)) return true;
List<UUID> members = this.currentParty.getMembers();
if (members != null) {
for (UUID m : members) {
if (local.equals(m)) return true;
}
}
return false;
}
private boolean isPlayerInCurrentParty(UUID playerId) {
if (this.currentParty == null || playerId == null) return false;
UUID leader = this.currentParty.getLeader();
if (leader != null && leader.equals(playerId)) return true;
List<UUID> members = this.currentParty.getMembers();
if (members != null) {
for (UUID memberId : members) {
if (playerId.equals(memberId)) return true;
}
}
return false;
}
private UUID getLocalPlayerId() {
Minecraft minecraft = Minecraft.getInstance();
if (minecraft.player == null) return null;
@@ -491,14 +552,37 @@ public class PartyScreen extends Screen {
return String.format(Locale.ROOT, "%.1f", hp);
}
private void drawPlayerHead(PoseStack poseStack, UUID playerId, int x, int y) {
ResourceLocation skin = getPlayerSkin(playerId);
RenderSystem.setShader(GameRenderer::getPositionTexShader);
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
RenderSystem.setShaderTexture(0, skin);
// Base face + hat layer from the standard 64x64 skin texture.
blit(poseStack, x, y, 8.0F, 8.0F, HEAD_SIZE, HEAD_SIZE, 64, 64);
blit(poseStack, x, y, 40.0F, 8.0F, HEAD_SIZE, HEAD_SIZE, 64, 64);
}
private ResourceLocation getPlayerSkin(UUID playerId) {
UUID safeId = playerId == null ? new UUID(0L, 0L) : playerId;
Minecraft minecraft = Minecraft.getInstance();
ClientPacketListener connection = minecraft.getConnection();
if (connection != null) {
PlayerInfo playerInfo = connection.getPlayerInfo(safeId);
if (playerInfo != null) {
return playerInfo.getSkinLocation();
}
}
return DefaultPlayerSkin.getDefaultSkin(safeId);
}
private int statusColor(PartyMember.Status status) {
if (status == null) return 0xFFFFFF;
switch (status) {
case DEAD:
String s = status.name();
if (s.equalsIgnoreCase("DEAD") || s.contains("DEAD")) {
return 0xFF5555;
case DOWNED:
} else if (s.equalsIgnoreCase("DOWNED") || s.toLowerCase(Locale.ROOT).contains("down")) {
return 0xFFAA00;
default:
} else {
return 0xFFFFFF;
}
}

View File

@@ -23,5 +23,8 @@
"screen.vaultpartyui.members": "Members",
"screen.vaultpartyui.online": "Online players",
"screen.vaultpartyui.leader": "Leader",
"screen.vaultpartyui.invite": "Invite",
"screen.vaultpartyui.remove": "Remove",
"screen.vaultpartyui.self": "You"
,"screen.vaultpartyui.credit_tooltip": "Click to open the GitHub repo"
}