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
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import meteordevelopment.meteorclient.MeteorClient;
import meteordevelopment.meteorclient.commands.Command;
import meteordevelopment.meteorclient.mixin.MapTextureManagerAccessor;
import meteordevelopment.meteorclient.utils.misc.FileDialogs;
import net.minecraft.client.multiplayer.ClientSuggestionProvider;
import net.minecraft.client.resources.MapTextureManager;
import net.minecraft.core.component.DataComponents;
Expand All @@ -21,10 +22,6 @@
import net.minecraft.world.item.MapItem;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
import org.jspecify.annotations.Nullable;
import org.lwjgl.sdl.SDLDialog;
import org.lwjgl.sdl.SDL_DialogFileFilter;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
Expand All @@ -35,14 +32,8 @@ public class SaveMapCommand extends Command {
private static final SimpleCommandExceptionType MAP_NOT_FOUND = new SimpleCommandExceptionType(Component.literal("You must be holding a filled map."));
private static final SimpleCommandExceptionType OOPS = new SimpleCommandExceptionType(Component.literal("Something went wrong."));

private final SDL_DialogFileFilter.Buffer filters;

public SaveMapCommand() {
super("save-map", "Saves a map to an image.", "sm");

MemoryStack stack = MemoryStack.stackPush();
filters = SDL_DialogFileFilter.malloc(1, stack);
filters.name(stack.UTF8("NBT Files")).pattern(stack.UTF8("nbt"));
}

@Override
Expand All @@ -64,14 +55,8 @@ private void saveMap(int scale) throws CommandSyntaxException {
MapItemSavedData state = getMapState();
if (map == null || state == null) throw MAP_NOT_FOUND.create();

SDLDialog.SDL_ShowSaveFileDialog((_, file, _) -> {
if (file == 0) return;

long filePointer = MemoryUtil.memGetAddress(file);
if (filePointer == 0) return;

String str = MemoryUtil.memUTF8(filePointer);
if (str.isBlank()) return;
FileDialogs.saveFile("png", selectedFile -> {
String str = selectedFile.getPath();
if (!str.endsWith(".png")) str += ".png";
File path = new File(str);

Expand All @@ -95,7 +80,7 @@ private void saveMap(int scale) throws CommandSyntaxException {
error("Error writing map texture");
MeteorClient.LOG.error(e.toString());
}
}, 0, 0, filters, "");
});
}

private @Nullable MapItemSavedData getMapState() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@
import meteordevelopment.meteorclient.settings.*;
import meteordevelopment.meteorclient.systems.hud.elements.keyboard.KeyboardHud;
import meteordevelopment.meteorclient.utils.Utils;
import meteordevelopment.meteorclient.utils.misc.FileDialogs;
import meteordevelopment.meteorclient.utils.render.DisplayItemUtils;
import meteordevelopment.meteorclient.utils.render.color.SettingColor;
import net.minecraft.client.resources.language.I18n;
import org.apache.commons.lang3.Strings;
import org.lwjgl.sdl.SDLDialog;
import org.lwjgl.system.MemoryUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -496,23 +494,18 @@ private void fileW(WTable table, FileSetting setting) {

WButton selectFile = list.add(theme.button("Select File")).widget();

WLabel fileName = list.add(theme.label((setting.get() != null && setting.get().exists()) ? setting.get().getName() : "No file selected.")).widget();
WLabel fileName = list.add(theme.label(fileName(setting))).widget();

selectFile.action = () -> SDLDialog.SDL_ShowOpenFileDialog((_, file, _) -> {
if (file == 0) return;

long filePointer = MemoryUtil.memGetAddress(file);
if (filePointer == 0) return;

String path = MemoryUtil.memUTF8(filePointer);
if (!path.isEmpty()) {
setting.set(new File(path));
fileName.set(setting.get().getName());
}
selectFile.action = () -> FileDialogs.openFile(setting.filter, file -> {
setting.set(file);
fileName.set(fileName(setting));
});

reset(table, setting, () -> fileName.set((setting.get() != null && setting.get().exists()) ? setting.get().getName() : "No file selected."));
}, 0L, 0, setting.filters, "", false);
reset(table, setting, () -> fileName.set(fileName(setting)));
}

private static String fileName(FileSetting setting) {
return setting.get() != null && setting.get().exists() ? setting.get().getName() : "No file selected.";
}

// Other
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,10 @@
import meteordevelopment.meteorclient.settings.Settings;
import meteordevelopment.meteorclient.systems.proxies.Proxies;
import meteordevelopment.meteorclient.systems.proxies.Proxy;
import meteordevelopment.meteorclient.utils.misc.FileDialogs;
import meteordevelopment.meteorclient.utils.misc.NbtUtils;
import meteordevelopment.meteorclient.utils.network.MeteorExecutor;
import org.lwjgl.sdl.SDLDialog;
import org.lwjgl.sdl.SDL_DialogFileFilter;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -59,23 +55,8 @@ public void initWidgets() {
newBtn.action = () -> mc.gui.setScreen(new EditProxyScreen(theme, null, this::reload));

// Import
MemoryStack stack = MemoryStack.stackPush();
SDL_DialogFileFilter.Buffer filters = SDL_DialogFileFilter.malloc(1, stack);
filters.name(stack.UTF8("Txt Files")).pattern(stack.UTF8("txt"));

WButton importBtn = l.add(theme.button("Import")).expandX().widget();
importBtn.action = () -> SDLDialog.SDL_ShowOpenFileDialog((_, fileptr, _) -> {
if (fileptr == 0) return;

long filePointer = MemoryUtil.memGetAddress(fileptr);
if (filePointer == 0) return;

String selectedFile = MemoryUtil.memUTF8(filePointer);
if (!selectedFile.isEmpty()){
File file = new File(selectedFile);
mc.gui.setScreen(new ProxiesImportScreen(theme, file));
}
}, 0L, 0, filters, "", false);
importBtn.action = () -> FileDialogs.openFile("txt", file -> mc.gui.setScreen(new ProxiesImportScreen(theme, file)));

l.add(refreshButton).expandX();
refreshButton.action = () -> Proxies.get().checkProxies(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,13 @@
import meteordevelopment.meteorclient.systems.profiles.Profile;
import meteordevelopment.meteorclient.systems.profiles.Profiles;
import meteordevelopment.meteorclient.utils.Utils;
import meteordevelopment.meteorclient.utils.misc.FileDialogs;
import meteordevelopment.meteorclient.utils.misc.NbtUtils;
import meteordevelopment.meteorclient.utils.render.prompts.OkPrompt;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import org.apache.commons.io.FilenameUtils;
import org.lwjgl.sdl.SDLDialog;
import org.lwjgl.sdl.SDLError;
import org.lwjgl.sdl.SDL_DialogFileFilter;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;

import java.io.DataOutputStream;
import java.io.File;
Expand All @@ -47,14 +43,6 @@
import static meteordevelopment.meteorclient.MeteorClient.mc;

public class ProfilesTab extends Tab {
private static final SDL_DialogFileFilter.Buffer filters;

static {
MemoryStack stack = MemoryStack.stackPush();
filters = SDL_DialogFileFilter.malloc(1, stack);
filters.name(stack.UTF8("NBT Files")).pattern(stack.UTF8("nbt"));
}

public ProfilesTab() {
super("Profiles");
}
Expand Down Expand Up @@ -91,16 +79,8 @@ public void initWidgets() {
// Import
WButton importBtn = l.add(theme.button("Import")).expandX().widget();
importBtn.tooltip = "Import profile";
importBtn.action = () -> SDLDialog.SDL_ShowOpenFileDialog((_, file, _) -> {
importBtn.action = () -> FileDialogs.openFile("nbt", profileFile -> {
try {
if (file == 0) throw new IOException("Dialog Error: " + SDLError.SDL_GetError());

long filePointer = MemoryUtil.memGetAddress(file);
if (filePointer == 0) return;

String path = MemoryUtil.memUTF8(filePointer);
File profileFile = new File(path);

Profile profile = importProfile(profileFile);

if (profile != null)
Expand All @@ -115,7 +95,7 @@ public void initWidgets() {
.dontShowAgainCheckboxVisible(false)
.show();
}
}, 0L, 0, filters, "", false);
});
}

private void initTable(WTable table) {
Expand Down Expand Up @@ -295,16 +275,10 @@ public void initWidgets() {
add(theme.horizontalSeparator()).expandX();

WButton export = add(theme.button("Export profile")).expandX().widget();
export.action = () -> SDLDialog.SDL_ShowSaveFileDialog((_, file, _) -> {
if (file == 0) return;

long filePointer = MemoryUtil.memGetAddress(file);
if (filePointer == 0) return;

String path = MemoryUtil.memUTF8(filePointer);
exportProfile(path, profile, hud.checked, macros.checked, modules.checked, waypoints.checked);
export.action = () -> FileDialogs.saveFile("nbt", file -> {
exportProfile(file.getPath(), profile, hud.checked, macros.checked, modules.checked, waypoints.checked);
onClose();
}, 0, 0, filters, "");
});
}

private WCheckbox addBool(WContainer container, Setting<Boolean> setting) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,18 @@
package meteordevelopment.meteorclient.settings;

import net.minecraft.nbt.CompoundTag;
import org.lwjgl.sdl.SDL_DialogFileFilter;
import org.lwjgl.system.MemoryStack;

import java.io.File;
import java.util.function.Consumer;

public class FileSetting extends Setting<File> {
public final SDL_DialogFileFilter.Buffer filters;
/** SDL filter extensions, e.g. {@code "txt"}, {@code "txt;json"} or {@code "*"} */
public final String filter;

public FileSetting(String name, String description, File defaultValue, Consumer<File> onChanged, Consumer<Setting<File>> onModuleActivated, IVisible visible, SDL_DialogFileFilter.Buffer filters) {
public FileSetting(String name, String description, File defaultValue, Consumer<File> onChanged, Consumer<Setting<File>> onModuleActivated, IVisible visible, String filter) {
super(name, description, defaultValue, onChanged, onModuleActivated, visible);

this.filters = filters;
this.filter = filter;
}

@Override
Expand Down Expand Up @@ -51,26 +50,17 @@ protected File load(CompoundTag tag) {
}

public static class Builder extends SettingBuilder<FileSetting.Builder, File, FileSetting> {
private SDL_DialogFileFilter.Buffer filter;
private String filter = "*";

public Builder() {
super(null);
}

public FileSetting.Builder filter(SDL_DialogFileFilter.Buffer filter) {
public FileSetting.Builder filter(String filter) {
this.filter = filter;
return this;
}

public FileSetting.Builder filter(String... filters) {
MemoryStack stack = MemoryStack.stackPush();
filter = SDL_DialogFileFilter.malloc(filters.length, stack);
for (int i = 0; i < filters.length; i++) {
filter.get(i).name(stack.UTF8("Filter " + i)).pattern(stack.UTF8(filters[i]));
}
return this;
}

@Override
public FileSetting build() {
return new FileSetting(name, description, defaultValue, onChanged, onModuleActivated, visible, filter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class BookBot extends Module {
.name("file")
.description("Which file to use.")
.defaultValue(DEFAULT_FILE)
.filter("*.txt")
.filter("txt")
.visible(() -> mode.get() == Mode.File)
.build()
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.utils.misc;

import meteordevelopment.meteorclient.MeteorClient;
import org.lwjgl.sdl.SDLDialog;
import org.lwjgl.sdl.SDLError;
import org.lwjgl.sdl.SDL_DialogFileCallback;
import org.lwjgl.sdl.SDL_DialogFileFilter;
import org.lwjgl.system.MemoryUtil;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

import static meteordevelopment.meteorclient.MeteorClient.mc;
import static org.lwjgl.system.MemoryUtil.NULL;

/**
* Native file dialogs. The dialog is asynchronous and its callback runs on SDL's own thread, so the result is handed
* back on the client thread.
*/
public final class FileDialogs {
// SDL reads the filters until it is done with the dialog, so they are built once per extension list and kept.
private static final Map<String, SDL_DialogFileFilter.Buffer> filters = new HashMap<>();

// The upcall can not be freed while it is executing, so the previous dialog's callback is released when the next
// dialog opens. Dialogs are modal, so there is only ever one in flight.
private static SDL_DialogFileCallback callback;

private FileDialogs() {}

/**
* @param extensions SDL filter extensions, e.g. {@code "txt"}, {@code "txt;json"} or {@code "*"}
* @param onSelected called on the client thread with the picked file
*/
public static void openFile(String extensions, Consumer<? super File> onSelected) {
SDLDialog.SDL_ShowOpenFileDialog(callback(onSelected), NULL, NULL, get(extensions), (ByteBuffer) null, false);
}

/**
* @param extensions SDL filter extensions, e.g. {@code "png"}, {@code "txt;json"} or {@code "*"}
* @param onSelected called on the client thread with the picked file
*/
public static void saveFile(String extensions, Consumer<? super File> onSelected) {
SDLDialog.SDL_ShowSaveFileDialog(callback(onSelected), NULL, NULL, get(extensions), (ByteBuffer) null);
}

private static SDL_DialogFileCallback callback(Consumer<? super File> onSelected) {
if (callback != null) callback.free();

return callback = new SDL_DialogFileCallback() {
@Override
public void invoke(long userdata, long filelist, int filter) {
if (filelist == NULL) {
MeteorClient.LOG.error("File dialog error: {}", SDLError.SDL_GetError());
return;
}

long path = MemoryUtil.memGetAddress(filelist);
if (path == NULL) return; // Canceled

File file = new File(MemoryUtil.memUTF8(path));
mc.execute(() -> onSelected.accept(file));
}
};
}

private static SDL_DialogFileFilter.Buffer get(String extensions) {
return filters.computeIfAbsent(extensions, extensions1 -> {
String name = extensions1.equals("*") ? "All files" : "*." + extensions1.replace(";", ", *.");

return SDL_DialogFileFilter.calloc(1)
.name(MemoryUtil.memUTF8(name))
.pattern(MemoryUtil.memUTF8(extensions1));
});
}
}
Loading