Created
October 5, 2024 23:39
-
-
Save Densamisten/2b1bef5b20a77ac5f4faed47052e67f1 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
package exonihility.client.util.playersearch.screen; | |
import com.mojang.authlib.GameProfile; | |
import exonihility.client.util.playersearch.util.GuiEntityRenderer; | |
import exonihility.client.util.playersearch.util.PlayerApi; | |
import net.minecraft.client.MinecraftClient; | |
import net.minecraft.client.gui.DrawContext; | |
import net.minecraft.client.gui.screen.Screen; | |
import net.minecraft.client.gui.widget.ButtonWidget; | |
import net.minecraft.client.gui.widget.EditBoxWidget; | |
import net.minecraft.client.util.Clipboard; | |
import net.minecraft.client.util.SkinTextures; | |
import net.minecraft.entity.player.PlayerEntity; | |
import net.minecraft.text.Text; | |
import net.minecraft.util.Identifier; | |
import org.jetbrains.annotations.Nullable; | |
import org.lwjgl.glfw.GLFW; | |
import java.io.InputStream; | |
import java.net.URI; | |
import java.net.http.HttpClient; | |
import java.net.http.HttpRequest; | |
import java.net.http.HttpResponse; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.nio.file.Paths; | |
import java.nio.file.StandardCopyOption; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.UUID; | |
import java.util.concurrent.CompletableFuture; | |
public class PlayerScreen extends Screen { | |
protected final Screen parent; | |
protected GameProfile profile; | |
private boolean firstLoad = true; | |
private static final Clipboard clipboardManager = new Clipboard(); | |
private EditBoxWidget editBox; | |
private final PlayerEntity playerEntity; // Store the PlayerEntity | |
private ButtonWidget copyUuidButton; | |
private String previousText; | |
private String playerName = Text.translatable("gui.allyship.unknown").getString(); | |
private UUID playerUuid; | |
private List<Map<String, Object>> nameHistory; // Store name history | |
private Identifier skinIdentifier; | |
private Identifier capeIdentifier; | |
private String model; | |
private NameHistoryListWidget nameHistoryListWidget; | |
public PlayerScreen(Screen parent, @Nullable GameProfile profile, PlayerEntity playerEntity) { | |
super(Text.translatable("playerSearch.title")); | |
this.parent = parent; | |
this.profile = profile; | |
this.playerEntity = playerEntity; | |
} | |
@Override | |
protected void init() { | |
super.init(); | |
// Initialize the name history list widget | |
this.nameHistoryListWidget = new NameHistoryListWidget(this.client, this.width, this.height, 32, 20); | |
this.addSelectableChild(this.nameHistoryListWidget); | |
this.previousText = ""; | |
this.editBox = this.addDrawableChild(new EditBoxWidget(this.textRenderer, this.width / 84, this.height / 84, 300, 20, Text.translatable("gui.player_search.search_hint"), Text.literal(""))); | |
this.addDrawableChild(ButtonWidget.builder(Text.translatable("gui.allyship.button"), button -> { | |
String text = this.editBox.getText(); | |
if (text.equals(this.previousText)) return; // Fix string comparison | |
Map<String, Object> request; | |
if (!text.isEmpty()) { | |
this.previousText = text; | |
// UUID detection and profile retrieval | |
if (text.length() == 32 || text.length() == 36) { | |
request = PlayerApi.getProfileFromUUID(text); | |
} else { | |
request = PlayerApi.getProfileFromName(text); | |
} | |
// Handle the request result | |
if (request == null) { | |
this.skinIdentifier = null; | |
this.capeIdentifier = null; | |
this.playerName = Text.translatable("gui.allyship.unknown").getString(); | |
this.playerUuid = null; | |
this.nameHistory = null; | |
} else { | |
this.playerUuid = UUID.fromString(parseUuid(request.get("id").toString())); | |
this.playerName = request.get("name").toString(); | |
this.profile = new GameProfile(this.playerUuid, this.playerName); | |
loadSkin(this.profile); | |
fetchCapeData(this.playerName); // Fetch the cape data | |
} | |
} | |
}).dimensions(330, this.height / 84, textRenderer.getWidth("Search") + 10, 20).build()); | |
if (this.firstLoad && this.profile != null) { | |
this.playerUuid = this.profile.getId(); | |
this.playerName = this.profile.getName(); | |
this.editBox.setText(this.playerName); | |
this.previousText = this.playerName; | |
CompletableFuture.runAsync(() -> { | |
// Fetch the name history | |
this.nameHistory = PlayerApi.getNameHistory(this.playerUuid.toString()); | |
// Ensure we are updating the UI on the main thread | |
MinecraftClient.getInstance().execute(() -> { | |
if (this.nameHistoryListWidget != null) { | |
this.nameHistoryListWidget.clearEntries(); // Clear the widget list before adding new entries | |
// Add new entries from the name history | |
for (Map<String, Object> historyEntry : nameHistory) { | |
this.nameHistoryListWidget.addNameHistoryEntry(historyEntry); | |
} | |
} | |
}); | |
}); | |
loadSkin(this.profile); | |
fetchCapeData(this.playerName); | |
this.firstLoad = false; | |
} | |
// Button to download the player's skin | |
this.addDrawableChild(ButtonWidget.builder(Text.translatable("gui.player_search.download.button"), button -> { | |
if (this.playerUuid == null) return; | |
downloadFile("https://crafatar.com/skins/" + this.playerUuid, this.playerUuid + ".png", "Skin"); | |
}).dimensions(8, 136, textRenderer.getWidth("Grab Skin") + 8, 20).build()); | |
// Add "Download Cape" button | |
this.addDrawableChild(ButtonWidget.builder(Text.translatable("gui.allyship.cape"), button -> { | |
if (this.capeIdentifier != null) { | |
downloadFile(this.capeIdentifier.toString(), this.playerUuid + "_cape.png", "Cape"); | |
} else { | |
System.out.println("[PlayerScreen] No cape available for this player."); | |
} | |
}).dimensions(8, 160, textRenderer.getWidth("Download Cape") + 8, 20).build()); | |
} | |
private void loadSkin(GameProfile profile) { | |
// Load the player's skin and texture information using Minecraft's built-in skin provider | |
MinecraftClient.getInstance().getSkinProvider().fetchSkinTextures(profile).thenAccept(skinTextures -> { | |
this.skinIdentifier = skinTextures.texture(); // Skin texture (identifier) | |
this.model = skinTextures.model() == SkinTextures.Model.SLIM ? "slim" : "default"; | |
this.capeIdentifier = skinTextures.capeTexture(); | |
}); | |
} | |
// Fetch cape data using the cape API | |
private void fetchCapeData(String playerName) { | |
try { | |
String capeUrl = "https://api.capes.dev/load/" + playerName; | |
HttpClient client = HttpClient.newHttpClient(); | |
HttpRequest request = HttpRequest.newBuilder() | |
.uri(URI.create(capeUrl)) | |
.build(); | |
// Asynchronously fetch the cape data | |
client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) | |
.thenApply(HttpResponse::body) | |
.thenAccept(this::handleCapeResponse) | |
.exceptionally(ex -> { | |
ex.printStackTrace(); | |
System.out.println("[PlayerScreen] Failed to fetch cape data."); | |
return null; | |
}); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
// Handle cape response from the API | |
private void handleCapeResponse(String json) { | |
Map<String, Object> capeData = PlayerApi.parseJsonToMap(json); | |
Map<String, Object> optifineCape = (Map<String, Object>) capeData.get("optifine"); | |
if (optifineCape != null && Boolean.TRUE.equals(optifineCape.get("exists"))) { | |
String capeUrl = (String) optifineCape.get("capeUrl"); | |
this.capeIdentifier = Identifier.of(capeUrl); // Store cape URL for downloading | |
System.out.println("[PlayerScreen] Cape found at URL: " + capeUrl); | |
} else { | |
System.out.println("[PlayerScreen] No cape found for player."); | |
} | |
} | |
// Download file (skin or cape) from the provided URL | |
private void downloadFile(String url, String fileName, String fileType) { | |
try { | |
HttpClient client = HttpClient.newHttpClient(); | |
HttpRequest request = HttpRequest.newBuilder() | |
.uri(URI.create(url)) | |
.build(); | |
// Send request to download the file | |
client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()) | |
.thenAccept(response -> { | |
try (InputStream in = response.body()) { | |
Path dir = Paths.get(MinecraftClient.getInstance().runDirectory.getPath(), "downloads"); | |
if (!Files.exists(dir)) { | |
Files.createDirectories(dir); | |
} | |
Path filePath = dir.resolve(fileName); | |
Files.copy(in, filePath, StandardCopyOption.REPLACE_EXISTING); | |
System.out.println("[PlayerScreen] " + fileType + " downloaded successfully to: " + filePath); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
System.out.println("[PlayerScreen] Error saving the " + fileType + " file."); | |
} | |
}).exceptionally(ex -> { | |
ex.printStackTrace(); | |
System.out.println("[PlayerScreen] Error downloading the " + fileType + "."); | |
return null; | |
}); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
@Override | |
public void render(DrawContext context, int mouseX, int mouseY, float delta) { | |
super.render(context, mouseX, mouseY, delta); | |
int playerX = this.width / 12; | |
int playerY = this.height / 2; | |
int playerSize = this.height / 5; | |
// Draw background box around player render area | |
context.fill(playerX - this.width / 14, playerY - playerSize * 2, playerX + this.width / 14, playerY + 10, 0x80000000); | |
// Render player model | |
GuiEntityRenderer.drawEntity(context, playerX, playerY, playerSize, 0, playerX - mouseX, playerY - playerSize * 1.8 - mouseY, this.playerEntity); | |
// Add "Copy UUID" button in the top right | |
this.copyUuidButton = ButtonWidget.builder(Text.literal("Copy UUID"), button -> { | |
if (this.playerUuid != null) { | |
String uuid = playerUuid.toString(); | |
clipboardManager.setClipboard(GLFW.glfwGetCurrentContext(), uuid); | |
System.out.println("Copied UUID: " + uuid); | |
} else { | |
System.out.println("[PlayerScreen] No entity selected."); | |
} | |
}).dimensions(this.width / 14, 10, 20, 20).build(); | |
addDrawableChild(this.copyUuidButton); | |
this.nameHistoryListWidget.render(context, mouseX, mouseY, delta); | |
} | |
private static String parseUuid(String uuid) { | |
StringBuilder stringBuilder = new StringBuilder(uuid); | |
if (uuid.length() == 32) { | |
stringBuilder.insert(8, '-'); | |
stringBuilder.insert(13, '-'); | |
stringBuilder.insert(18, '-'); | |
stringBuilder.insert(23, '-'); | |
} | |
return stringBuilder.toString(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment