Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions src/main/java/top/fpsmaster/cosmetic/CosmeticManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
import top.fpsmaster.modules.client.api.model.CosmeticLoadoutView;
import top.fpsmaster.modules.client.api.model.OwnedItemView;
import top.fpsmaster.modules.logger.ClientLogger;
import top.fpsmaster.utils.system.FolderOpen;

import javax.imageio.ImageIO;
import java.awt.Desktop;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
Expand Down Expand Up @@ -120,10 +120,9 @@ public void reloadCustom() {
public void openCustomDirectory() {
reloadCustom();
try {
if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Desktop.Action.OPEN)) {
if (!FolderOpen.open(customDirectory().toFile())) {
throw new UnsupportedOperationException("Desktop folder opening is unavailable");
}
Desktop.getDesktop().open(customDirectory().toFile());
} catch (Exception exception) {
ClientLogger.warn("Failed to open custom cosmetics folder: " + exception.getMessage());
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/top/fpsmaster/ui/click/MainPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ public void initGui() {

@Override
public void render(int mouseX, int mouseY, float partialTicks) {
// SharedClickGui uses this same layout. Intersect every content clip with the
// panel so expanded settings cannot paint past the window (scissor is in
// framebuffer pixels; a huge extra-height rect is otherwise easy to get wrong).
float gw = guiWidth;
float gh = guiHeight;
float width = Math.min(490f, Math.max(300f, gw - 20f));
float height = Math.min(310f, Math.max(220f, gh - 24f));
float x = (gw - width) / 2f;
float y = (gh - height) / 2f;
EdgeUi.clipPanel(x + 1f, y + 1f, width - 2f, height - 2f);
if (gui.draw(EdgeUi.frame(), bridge)) {
mc.displayGuiScreen(null);
if (mc.currentScreen == null) mc.setIngameFocus();
Expand Down
17 changes: 14 additions & 3 deletions src/main/java/top/fpsmaster/ui/kit/EdgeCanvas.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,20 @@
final class EdgeCanvas implements Canvas {
private final Deque<float[]> clips = new ArrayDeque<float[]>();
private final Deque<Float> alpha = new ArrayDeque<Float>();
private static float[] panelClip;

EdgeCanvas() {
alpha.push(Float.valueOf(1f));
}

static void setPanelClip(float x, float y, float w, float h) {
panelClip = new float[] {x, y, w, h};
}

static void clearPanelClip() {
panelClip = null;
}

public void fillRect(float x, float y, float w, float h, int argb) {
Rects.fill(x, y, w, h, tint(argb));
}
Expand All @@ -43,9 +52,7 @@ public void fillRoundRect(float x, float y, float w, float h, float radius, int
}

public void strokeRoundRect(float x, float y, float w, float h, float radius, float strokeWidth, int argb) {
float s = Math.max(0.5f, strokeWidth);
fillRoundRect(x - s, y - s, w + s * 2f, h + s * 2f, radius + s, argb);
fillRoundRect(x, y, w, h, radius, Argb.of(255, 14, 14, 14));
Rects.roundedOutline(x, y, w, h, radius, strokeWidth, tint(argb));
}

public void fillCircle(float cx, float cy, float radius, int argb) {
Expand Down Expand Up @@ -102,6 +109,10 @@ public void pushClip(float x, float y, float w, float h) {
float[] next = parent == null
? new float[] {x, y, w, h}
: Scissor.intersect(parent[0], parent[1], parent[2], parent[3], x, y, w, h);
if (panelClip != null) {
next = Scissor.intersect(panelClip[0], panelClip[1], panelClip[2], panelClip[3],
next[0], next[1], next[2], next[3]);
}
clips.push(next);
applyClip(next);
}
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/top/fpsmaster/ui/kit/EdgeUi.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,18 @@ public static void beginOverlay(float guiWidth, float guiHeight) {

public static void end() {
fallback.endFrame();
EdgeCanvas.clearPanelClip();
current = null;
}

/**
* Extra GL clip intersected with every {@code pushClip}. Used so ClickGUI module
* settings cannot paint past the panel when an expanded card is taller than the window.
*/
public static void clipPanel(float x, float y, float w, float h) {
EdgeCanvas.setPanelClip(x, y, w, h);
}

public static UiFrame frame() {
if (current == null) {
throw new IllegalStateException("EdgeUi.begin() not called for this frame");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
import top.fpsmaster.modules.logger.ClientLogger;
import top.fpsmaster.prism.screen.BackgroundsBridge;
import top.fpsmaster.prism.screen.SharedBackgrounds;
import top.fpsmaster.prism.widget.Chrome;
import top.fpsmaster.prism.widget.UiFrame;
import top.fpsmaster.ui.kit.EdgeUi;
import top.fpsmaster.utils.io.FileUtils;
import top.fpsmaster.utils.render.draw.Images;
import top.fpsmaster.utils.render.draw.Rects;
import top.fpsmaster.utils.render.gui.Backgrounds;
import top.fpsmaster.utils.render.gui.ScaledGuiScreen;
import top.fpsmaster.utils.system.FolderOpen;

import javax.imageio.ImageIO;
import java.awt.Color;
Expand Down Expand Up @@ -51,7 +53,51 @@ public BackgroundSelector(GuiScreen parent) {
@Override
public void render(int mouseX, int mouseY, float partialTicks) {
Backgrounds.draw((int) guiWidth, (int) guiHeight, mouseX, mouseY, partialTicks, (int) zLevel);
if (backgrounds.draw(EdgeUi.frame(), bridge)) mc.displayGuiScreen(parent);
UiFrame ui = EdgeUi.frame();
if (backgrounds.draw(ui, bridge)) {
mc.displayGuiScreen(parent);
return;
}
drawOpenFolderButton(ui);
}

/**
* SharedBackgrounds only exposes "choose image". The homepage flow also has an
* "open folder" control so users can drop {@code background.png} into the client dir.
*/
private void drawOpenFolderButton(UiFrame ui) {
float gw = ui.host().width();
float gh = ui.host().height();
float pw = Math.min(250f, gw - 24f);
int rows = (BackgroundsBridge.OPTIONS.length + 1) / 2;
boolean classic = "classic".equals(FPSMaster.configManager.configure.background);
float editorH = classic ? 78f : 0f;
float content = 8f + rows * (48f + 5f) + 8f + editorH;
float ph = Math.min(30f + content + 10f, Math.min(gh * 0.78f, gh - 24f));
float px = (gw - pw) / 2f;
float py = (gh - ph) / 2f;
float headY = py + 8f;
String pick = FPSMaster.i18n.get("backgroundselector.pick");
String folder = FPSMaster.i18n.get("backgroundselector.openfolder");
float pickW = ui.font(13).measure(pick) + 16f;
float folderW = ui.font(13).measure(folder) + 16f;
float folderX = px + pw - 10f - pickW - 4f - folderW;
if (folderX < px + 28f) {
folderX = px + 28f;
}
if (Chrome.button(ui, folderX, headY, folderW, 15f, folder, Chrome.ButtonStyle.GHOST)) {
openBackgroundFolder();
}
}

private void openBackgroundFolder() {
File folder = FileUtils.dir;
if (folder == null && FileUtils.background != null) {
folder = FileUtils.background.getParentFile();
}
if (!FolderOpen.open(folder)) {
ClientLogger.warn("Failed to open background folder");
}
}

@Override
Expand Down Expand Up @@ -135,6 +181,8 @@ public void paintPreview(UiFrame ui, String id, float x, float y, float w, float
return;
}
if (id.startsWith("panorama_")) {
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glColor4f(1f, 1f, 1f, 1f);
Images.draw(new ResourceLocation("client/background/" + id + "/panorama_0.png"), x, y, w, h, -1);
return;
}
Expand Down
82 changes: 61 additions & 21 deletions src/main/java/top/fpsmaster/ui/screens/music/MusicScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
import org.lwjgl.input.Keyboard;
import top.fpsmaster.FPSMaster;
import top.fpsmaster.features.impl.interfaces.LyricsDisplay;
import top.fpsmaster.modules.config.ConfigProfileUtils;
import top.fpsmaster.modules.logger.ClientLogger;
import top.fpsmaster.modules.music.MusicManager;
import top.fpsmaster.modules.music.MusicTextures;
import top.fpsmaster.modules.config.ConfigProfileUtils;
import top.fpsmaster.music.Lyric;
import top.fpsmaster.music.LyricLine;
import top.fpsmaster.music.MusicSource;
Expand All @@ -16,15 +17,16 @@
import top.fpsmaster.music.Track;
import top.fpsmaster.prism.screen.MusicBridge;
import top.fpsmaster.prism.screen.SharedMusic;
import top.fpsmaster.prism.widget.Chrome;
import top.fpsmaster.prism.widget.UiFrame;
import top.fpsmaster.ui.kit.EdgeUi;
import top.fpsmaster.utils.io.FileUtils;
import top.fpsmaster.utils.render.draw.Images;
import top.fpsmaster.utils.render.gui.ScaledGuiScreen;
import top.fpsmaster.utils.system.FolderOpen;

import java.io.IOException;
import java.io.File;
import java.awt.FileDialog;
import java.awt.Frame;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -53,11 +55,41 @@ public MusicScreen(GuiScreen parent) {
} catch (IllegalArgumentException ignored) {
music.setPlaybackMode(MusicBridge.PlaybackMode.SEQUENTIAL);
}
try {
refreshLocalTracks(FileUtils.musicDirectory());
} catch (RuntimeException exception) {
ClientLogger.warn("Failed to scan local music folder: " + exception.getMessage());
}
}

@Override
public void render(int mouseX, int mouseY, float partialTicks) {
if (gui.draw(EdgeUi.frame(), bridge)) mc.displayGuiScreen(parent);
UiFrame ui = EdgeUi.frame();
if (gui.draw(ui, bridge)) {
mc.displayGuiScreen(parent);
return;
}
drawOpenFolderButton(ui);
}

private void drawOpenFolderButton(UiFrame ui) {
float gw = ui.host().width();
float gh = ui.host().height();
float pw = Math.min(480f, Math.max(320f, gw - 24f));
float ph = Math.min(290f, Math.max(200f, gh - 32f));
float px = (gw - pw) / 2f;
float py = (gh - ph) / 2f;
float size = 16f;
float closeX = px + pw - 7f - size;
float settingsX = closeX - 21f;
float folderX = settingsX - 21f;
float folderY = py + 7f;
String label = FPSMaster.i18n.get("music.local.openfolder");
float labelW = ui.font(12).measure(label) + 16f;
float buttonX = folderX - labelW + size;
if (Chrome.button(ui, buttonX, folderY, labelW, size, label, Chrome.ButtonStyle.GHOST)) {
openLocalMusicFolder();
}
}

@Override
Expand Down Expand Up @@ -130,22 +162,7 @@ public List<TrackRow> tracks() {
}

@Override public void importLocalMusic() {
Thread picker = new Thread(new Runnable() {
@Override public void run() {
FileDialog dialog = new FileDialog((Frame) null, "选择本地音乐", FileDialog.LOAD);
dialog.setMultipleMode(true);
dialog.setFilenameFilter((dir, name) -> isLocalAudio(name));
dialog.setVisible(true);
final File[] files = dialog.getFiles();
dialog.dispose();
if (files.length == 0) return;
mc.addScheduledTask(new Runnable() {
@Override public void run() { localTracks = toLocalTracks(files); }
});
}
}, "FPSMaster-Music-Picker");
picker.setDaemon(true);
picker.start();
openLocalMusicFolder();
}

@Override public void playLocal(int index) {
Expand Down Expand Up @@ -259,6 +276,29 @@ public List<LyricRow> lyricRows() {
}
}

private void openLocalMusicFolder() {
File folder;
try {
folder = FileUtils.musicDirectory();
} catch (IllegalStateException exception) {
ClientLogger.warn("Music folder is unavailable: " + exception.getMessage());
return;
}
if (!FolderOpen.open(folder)) {
ClientLogger.warn("Failed to open local music folder: " + folder.getAbsolutePath());
}
refreshLocalTracks(folder);
}

private void refreshLocalTracks(File folder) {
File[] files = folder.listFiles();
if (files == null) {
localTracks = new ArrayList<Track>();
return;
}
localTracks = toLocalTracks(files);
}

private static String format(long millis) {
long seconds = Math.max(0L, millis) / 1000L;
return String.format("%d:%02d", seconds / 60L, seconds % 60L);
Expand Down
14 changes: 5 additions & 9 deletions src/main/java/top/fpsmaster/ui/screens/replay/ReplayScreen.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
import top.fpsmaster.utils.render.draw.Rects;
import top.fpsmaster.utils.render.gui.Backgrounds;
import top.fpsmaster.utils.render.gui.ScaledGuiScreen;
import top.fpsmaster.utils.system.FolderOpen;

import java.awt.Color;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -529,10 +529,8 @@ private void openReplaysFolder() {
if (!directory.isDirectory() && !directory.mkdirs()) {
return;
}
try {
Desktop.getDesktop().open(directory);
} catch (IOException | RuntimeException exception) {
ClientLogger.warn("Could not open replays folder: " + exception);
if (!FolderOpen.open(directory)) {
ClientLogger.warn("Could not open replays folder: " + directory.getAbsolutePath());
}
}

Expand Down Expand Up @@ -725,10 +723,8 @@ private void openEditsFolder() {
if (!directory.isDirectory() && !directory.mkdirs()) {
return;
}
try {
Desktop.getDesktop().open(directory);
} catch (IOException | RuntimeException exception) {
ClientLogger.warn("Could not open edits folder: " + exception);
if (!FolderOpen.open(directory)) {
ClientLogger.warn("Could not open edits folder: " + directory.getAbsolutePath());
}
}

Expand Down
13 changes: 13 additions & 0 deletions src/main/java/top/fpsmaster/utils/io/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class FileUtils extends Utility {
public static File background;
public static boolean hasBackground = false;
public static File fonts;
public static File music;

private static boolean initialized;

Expand All @@ -35,11 +36,23 @@ public static synchronized void init(File dataDir) {
}
dir = ensureDir(new File(dataDir, "FPSMaster " + FPSMaster.EDITION));
fonts = ensureDir(new File(dir, "fonts"));
music = ensureDir(new File(dir, "music"));
background = new File(dir, "background.png");
hasBackground = background.exists();
initialized = true;
}

public static File musicDirectory() {
if (music != null && music.isDirectory()) {
return music;
}
if (dir == null) {
throw new IllegalStateException("FileUtils init requires a valid mcDataDir");
}
music = ensureDir(new File(dir, "music"));
return music;
}

private static File ensureDir(File file) {
if (!file.exists() && !file.mkdirs()) {
ClientLogger.error("FileUtils", "failed to create directory: " + file.getAbsolutePath());
Expand Down
Loading
Loading