- Выберите загрузчик игры
- Vanilla
ss- прикреплен
Java:
package im.babka.ui.display.impl;
import com.mojang.blaze3d.matrix.MatrixStack;
import im.babka.events.EventDisplay;
import im.babka.events.EventUpdate;
import im.babka.functions.impl.render.HUD;
import im.babka.ui.display.ElementRenderer;
import im.babka.ui.display.ElementUpdater;
import im.babka.utils.drag.Dragging;
import im.babka.utils.render.ColorUtils;
import im.babka.utils.render.DisplayUtils;
import im.babka.utils.render.Scissor;
import im.babka.utils.render.font.Fonts;
import im.babka.command.friends.FriendStorage;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.AbstractGui;
import net.minecraft.client.network.play.NetworkPlayerInfo;
import net.minecraft.util.ResourceLocation;
import org.lwjgl.opengl.GL11;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import net.minecraft.client.resources.SkinManager;
@FieldDefaults(level = AccessLevel.PRIVATE)
@RequiredArgsConstructor
public class FriendListRenderer implements ElementRenderer, ElementUpdater {
final Dragging dragging;
final ResourceLocation logo = new ResourceLocation("babka/images/hud/friends.png");
private final List<String> friendsList = new ArrayList<>();
private final Map<String, ResourceLocation> skinCache = new HashMap<>();
private final Set<String> loadingSkins = new HashSet<>();
private final Map<String, Long> lastLoadAttempt = new HashMap<>();
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private static final float PADDING = 4.6f;
private static final float FONT_SIZE = 6f;
private static final float TITLE_FONT_SIZE = 7f;
private static final float SPACING = 8f;
private static final float ICON_SIZE = 10.6f;
private static final float HEAD_SIZE = 10.6f;
private static final float ROUNDING = 6f;
private static final float GLOW_OFFSET = 1.4f;
@Override
public void update(EventUpdate e) {
Minecraft mc = Minecraft.getInstance();
friendsList.clear();
friendsList.addAll(FriendStorage.getFriends());
long now = System.currentTimeMillis();
for (String friend : friendsList) {
if (skinCache.containsKey(friend)) continue;
NetworkPlayerInfo info = mc.getConnection().getPlayerInfo(friend);
if (info != null) {
ResourceLocation skin = info.getLocationSkin();
if (skin != null) {
skinCache.put(friend, skin);
continue;
}
}
if (loadingSkins.contains(friend)) continue;
if (lastLoadAttempt.getOrDefault(friend, 0L) > now - 60000) continue;
lastLoadAttempt.put(friend, now);
loadingSkins.add(friend);
loadSkin(friend);
}
}
private void loadSkin(String playerName) {
executor.execute(() -> {
UUID uuid = getUUID(playerName);
if (uuid == null) {
loadingSkins.remove(playerName);
return;
}
GameProfile profile = new GameProfile(uuid, playerName);
Minecraft mc = Minecraft.getInstance();
mc.execute(() -> {
mc.getSkinManager().loadProfileTextures(profile, (type, location, profileTexture) -> {
if (type == MinecraftProfileTexture.Type.SKIN) {
skinCache.put(playerName, location);
}
loadingSkins.remove(playerName);
}, true);
});
});
}
private UUID getUUID(String name) {
try {
URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + name);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
if (conn.getResponseCode() != 200) return null;
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder result = new StringBuilder();
String line;
while ((line = rd.readLine()) != null) {
result.append(line);
}
rd.close();
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(result.toString()).getAsJsonObject();
String id = obj.get("id").getAsString();
String uuidStr = id.replaceAll("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})", "$1-$2-$3-$4-$5");
return UUID.fromString(uuidStr);
} catch (Exception e) {
return null;
}
}
@Override
public void render(EventDisplay eventDisplay) {
MatrixStack ms = eventDisplay.getMatrixStack();
Minecraft mc = Minecraft.getInstance();
float x = dragging.getX();
float y = dragging.getY();
String title = "Friends";
float maxNameWidth = 0f;
int count = friendsList.size();
for (String friend : friendsList) {
float nameW = Fonts.sfMedium.getWidth(friend, FONT_SIZE);
maxNameWidth = Math.max(maxNameWidth, nameW);
}
float titleWidth = Fonts.sfMedium.getWidth(title, TITLE_FONT_SIZE);
float titleSectionWidth = PADDING + ICON_SIZE + SPACING + titleWidth + PADDING;
float contentWidth = PADDING + HEAD_SIZE + SPACING + maxNameWidth + PADDING;
float width = Math.max(titleSectionWidth, contentWidth) + 5.4f;
float titleSectionHeight = PADDING + ICON_SIZE + PADDING;
float height;
boolean hasFriends = count > 0;
if (hasFriends) {
height = titleSectionHeight + PADDING * 1.5f + count * (Math.max(FONT_SIZE, HEAD_SIZE) + PADDING * 1.2f);
} else {
height = titleSectionHeight;
}
dragging.setWidth(width);
dragging.setHeight(height);
int color = HUD.getColor(1);
int r = (color >> 16) & 0xFF;
int g = (color >> 8) & 0xFF;
int b = color & 0xFF;
int bg_r = (int) (r * 0.05f);
int bg_g = (int) (g * 0.05f);
int bg_b = (int) (b * 0.05f);
DisplayUtils.drawRoundedRect(x - GLOW_OFFSET, y - GLOW_OFFSET, width + GLOW_OFFSET * 2, height + GLOW_OFFSET * 2, ROUNDING + 0.6f,
ColorUtils.rgba(r, g, b, 100));
DisplayUtils.drawRoundedRect(x, y, width, height, ROUNDING,
ColorUtils.rgba(bg_r, bg_g, bg_b, 195));
float separatorY = y + titleSectionHeight - 1.4f;
float contentTop = separatorY + 0.8f;
float lowerHeight = height - (contentTop - y);
if (hasFriends) {
Scissor.push();
Scissor.setFromComponentCoordinates(x, contentTop, width, lowerHeight);
DisplayUtils.drawRoundedRect(x, contentTop - ROUNDING, width, lowerHeight + ROUNDING, ROUNDING,
ColorUtils.rgba(0, 0, 0, 195));
Scissor.pop();
}
Scissor.push();
Scissor.setFromComponentCoordinates(x, y, width, height);
float contentX = x + PADDING;
float contentY = y + PADDING;
DisplayUtils.drawImage(logo, (int) contentX, (int) contentY, ICON_SIZE, ICON_SIZE, -1);
float titleX = contentX + ICON_SIZE + SPACING;
float titleY = contentY + (ICON_SIZE - TITLE_FONT_SIZE) / 2f + 0.6f;
drawNeonText(ms, title, titleX, titleY, ColorUtils.rgb(r, g, b), TITLE_FONT_SIZE);
if (hasFriends) {
DisplayUtils.drawRectHorizontalW(x + PADDING, separatorY,
width - PADDING * 2, 0.8f,
ColorUtils.rgba(r, g, b, 200),
ColorUtils.rgba(r, g, b, 40));
}
float currentY = y + titleSectionHeight + PADDING * 0.8f;
for (String friend : friendsList) {
drawPlayerHead(friend, x + PADDING, currentY + 1.4f, HEAD_SIZE, HEAD_SIZE);
NetworkPlayerInfo info = mc.getConnection().getPlayerInfo(friend);
int nameColor = (info != null)
? ColorUtils.rgb(50, 255, 120)
: ColorUtils.rgb(255, 70, 100);
drawNeonText(ms, friend,
x + PADDING + HEAD_SIZE + SPACING,
currentY + (HEAD_SIZE - FONT_SIZE) / 2f + 0.6f,
nameColor, FONT_SIZE);
currentY += Math.max(FONT_SIZE, HEAD_SIZE) + PADDING * 1.2f;
}
Scissor.unset();
Scissor.pop();
}
private void drawNeonText(MatrixStack ms, String text, float x, float y, int color, float size) {
Fonts.sfMedium.drawText(ms, text, x + 0.4f, y + 0.4f, ColorUtils.rgba(0, 0, 0, 160), size);
Fonts.sfMedium.drawText(ms, text, x, y, color, size);
}
private void drawPlayerHead(String playerName, float x, float y, float width, float height) {
Minecraft mc = Minecraft.getInstance();
ResourceLocation skin = skinCache.get(playerName);
if (skin == null) {
NetworkPlayerInfo info = mc.getConnection().getPlayerInfo(playerName);
if (info != null) {
skin = info.getLocationSkin();
if (skin != null) {
skinCache.put(playerName, skin);
}
}
}
if (skin == null) return;
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_BLEND);
mc.getTextureManager().bindTexture(skin);
AbstractGui.drawScaledCustomSizeModalRect(
(int) x, (int) y,
8, 8, 8, 8,
(int) width, (int) height,
64, 64
);
GL11.glPopMatrix();
}
}