Remove online features, they're no longer available
This commit is contained in:
@@ -10,7 +10,6 @@ import com.replaymod.core.mixin.MinecraftAccessor;
|
|||||||
import com.replaymod.core.versions.MCVer;
|
import com.replaymod.core.versions.MCVer;
|
||||||
import com.replaymod.editor.ReplayModEditor;
|
import com.replaymod.editor.ReplayModEditor;
|
||||||
import com.replaymod.extras.ReplayModExtras;
|
import com.replaymod.extras.ReplayModExtras;
|
||||||
import com.replaymod.online.ReplayModOnline;
|
|
||||||
import com.replaymod.recording.ReplayModRecording;
|
import com.replaymod.recording.ReplayModRecording;
|
||||||
import com.replaymod.render.ReplayModRender;
|
import com.replaymod.render.ReplayModRender;
|
||||||
import com.replaymod.replay.ReplayModReplay;
|
import com.replaymod.replay.ReplayModReplay;
|
||||||
@@ -198,7 +197,6 @@ public class ReplayMod implements
|
|||||||
modules.add(new ReplayModRecording(this));
|
modules.add(new ReplayModRecording(this));
|
||||||
ReplayModReplay replayModule = new ReplayModReplay(this);
|
ReplayModReplay replayModule = new ReplayModReplay(this);
|
||||||
modules.add(replayModule);
|
modules.add(replayModule);
|
||||||
modules.add(new ReplayModOnline(this, replayModule));
|
|
||||||
modules.add(new ReplayModRender(this));
|
modules.add(new ReplayModRender(this));
|
||||||
modules.add(new ReplayModSimplePathing(this));
|
modules.add(new ReplayModSimplePathing(this));
|
||||||
modules.add(new ReplayModEditor(this));
|
modules.add(new ReplayModEditor(this));
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import com.replaymod.core.Module;
|
|||||||
import com.replaymod.core.ReplayMod;
|
import com.replaymod.core.ReplayMod;
|
||||||
import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots;
|
import com.replaymod.extras.advancedscreenshots.AdvancedScreenshots;
|
||||||
import com.replaymod.extras.playeroverview.PlayerOverview;
|
import com.replaymod.extras.playeroverview.PlayerOverview;
|
||||||
import com.replaymod.extras.urischeme.UriSchemeExtra;
|
|
||||||
import com.replaymod.extras.youtube.YoutubeUpload;
|
import com.replaymod.extras.youtube.YoutubeUpload;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
@@ -22,7 +21,6 @@ public class ReplayModExtras implements Module {
|
|||||||
private static final List<Class<? extends Extra>> builtin = Arrays.asList(
|
private static final List<Class<? extends Extra>> builtin = Arrays.asList(
|
||||||
AdvancedScreenshots.class,
|
AdvancedScreenshots.class,
|
||||||
PlayerOverview.class,
|
PlayerOverview.class,
|
||||||
UriSchemeExtra.class,
|
|
||||||
YoutubeUpload.class,
|
YoutubeUpload.class,
|
||||||
FullBrightness.class,
|
FullBrightness.class,
|
||||||
HotkeyButtons.class,
|
HotkeyButtons.class,
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
package com.replaymod.extras.urischeme;
|
|
||||||
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.io.output.StringBuilderWriter;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
|
|
||||||
public class LinuxUriScheme extends UriScheme {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void install() throws URISyntaxException, IOException {
|
|
||||||
File file = new File("replaymod.desktop");
|
|
||||||
File iconFile = new File("replaymod-icon.jpg");
|
|
||||||
String path = findJarFile().getAbsolutePath().replace("\\", "\\\\").replace("\"", "\\\"");
|
|
||||||
String content =
|
|
||||||
"[Desktop Entry]\n" +
|
|
||||||
"Name=ReplayMod\n" +
|
|
||||||
"Exec=java -cp \"" + path + "\" " + UriScheme.class.getName() + " %u\n" +
|
|
||||||
"Icon=" + iconFile.getAbsolutePath().replace("\\", "\\\\").replace("\"", "\\\"") + "\n" +
|
|
||||||
"Type=Application\n" +
|
|
||||||
"Terminal=false\n" +
|
|
||||||
"NoDisplay=true\n" +
|
|
||||||
"MimeType=x-scheme-handler/replaymod;";
|
|
||||||
|
|
||||||
FileOutputStream out = new FileOutputStream(file);
|
|
||||||
try {
|
|
||||||
IOUtils.write(content, out);
|
|
||||||
} finally {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream in = LinuxUriScheme.class.getResourceAsStream("/assets/replaymod/logo.jpg");
|
|
||||||
try {
|
|
||||||
out = new FileOutputStream(iconFile);
|
|
||||||
try {
|
|
||||||
IOUtils.copy(in, out);
|
|
||||||
} finally {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] command = {"xdg-desktop-menu", "install", "--novendor", "replaymod.desktop"};
|
|
||||||
Process process = new ProcessBuilder().command(command).start();
|
|
||||||
try {
|
|
||||||
if (process.waitFor() != 0) {
|
|
||||||
StringBuilderWriter writer = new StringBuilderWriter();
|
|
||||||
IOUtils.copy(process.getInputStream(), writer);
|
|
||||||
IOUtils.copy(process.getErrorStream(), writer);
|
|
||||||
throw new IOException(writer.toString());
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileUtils.deleteQuietly(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.replaymod.extras.urischeme;
|
|
||||||
|
|
||||||
public class OSXUriScheme extends UriScheme {
|
|
||||||
@Override
|
|
||||||
public void install() throws Exception {
|
|
||||||
throw new UnsupportedOperationException("OSX URI scheme not yet implemented.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
package com.replaymod.extras.urischeme;
|
|
||||||
|
|
||||||
import net.minecraft.util.Util;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.security.CodeSource;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public abstract class UriScheme {
|
|
||||||
public static final String PROTOCOL = "replaymod://";
|
|
||||||
public static final int PROCESS_PORT = 11754;
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
try {
|
|
||||||
System.out.println("Args: " + Arrays.toString(args));
|
|
||||||
|
|
||||||
if (args.length == 1 && args[0].startsWith(PROTOCOL)) {
|
|
||||||
int id = Integer.parseInt(args[0].substring(PROTOCOL.length()));
|
|
||||||
try {
|
|
||||||
Socket socket = new Socket(InetAddress.getLocalHost(), PROCESS_PORT);
|
|
||||||
socket.getOutputStream().write(String.valueOf(id).getBytes());
|
|
||||||
socket.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
launchNewInstance(id);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
launchNewInstance(null);
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
JOptionPane.showMessageDialog(null, "Failed to start Minecraft launcher. Saving exception to replaymod-crash.txt");
|
|
||||||
try {
|
|
||||||
FileOutputStream out = new FileOutputStream("replaymod-crash.txt");
|
|
||||||
t.printStackTrace(new PrintStream(out));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void launchNewInstance(Integer replayId) throws IOException {
|
|
||||||
// Determine launcher.jar location
|
|
||||||
String osName = System.getProperty("os.name").toLowerCase();
|
|
||||||
String userHome = System.getProperty("user.home", ".");
|
|
||||||
File dir;
|
|
||||||
if (osName.contains("win")) {
|
|
||||||
String appData = System.getenv("APPDATA");
|
|
||||||
dir = new File(appData != null ? appData : userHome, ".minecraft/");
|
|
||||||
} else if (osName.contains("mac")) {
|
|
||||||
dir = new File(userHome, "Library/Application Support/minecraft");
|
|
||||||
} else if (osName.contains("linux") || osName.contains("unix")) {
|
|
||||||
dir = new File(userHome, ".minecraft/");
|
|
||||||
} else {
|
|
||||||
dir = new File(userHome, "minecraft/");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Launch process
|
|
||||||
ProcessBuilder processBuilder = new ProcessBuilder("java", "-jar", "launcher.jar").directory(dir);
|
|
||||||
if (replayId != null) {
|
|
||||||
processBuilder.environment().put("replaymod.uri.replayid", String.valueOf(replayId));
|
|
||||||
}
|
|
||||||
processBuilder.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UriScheme create() {
|
|
||||||
switch (Util.getOperatingSystem()) {
|
|
||||||
case LINUX:
|
|
||||||
return new LinuxUriScheme();
|
|
||||||
case WINDOWS:
|
|
||||||
return new WindowsUriScheme();
|
|
||||||
case OSX:
|
|
||||||
return new OSXUriScheme();
|
|
||||||
case SOLARIS:
|
|
||||||
case UNKNOWN:
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void install() throws Exception;
|
|
||||||
|
|
||||||
File findJarFile() throws IOException {
|
|
||||||
CodeSource codeSource = UriScheme.class.getProtectionDomain().getCodeSource();
|
|
||||||
if (codeSource != null) {
|
|
||||||
URL location = codeSource.getLocation();
|
|
||||||
if (location != null) {
|
|
||||||
try {
|
|
||||||
return new File(location.toURI());
|
|
||||||
} catch (URISyntaxException e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IOException("No jar file found. Is this a development environment?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
package com.replaymod.extras.urischeme;
|
|
||||||
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
import com.replaymod.extras.Extra;
|
|
||||||
import com.replaymod.online.ReplayModOnline;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
|
|
||||||
public class UriSchemeExtra implements Extra {
|
|
||||||
private ReplayModOnline module;
|
|
||||||
|
|
||||||
private ReplayMod mod;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void register(final ReplayMod mod) throws Exception {
|
|
||||||
this.mod = mod;
|
|
||||||
this.module = ReplayModOnline.instance;
|
|
||||||
|
|
||||||
UriScheme uriScheme = UriScheme.create();
|
|
||||||
if (uriScheme == null) {
|
|
||||||
throw new UnsupportedOperationException("OS not supported.");
|
|
||||||
}
|
|
||||||
uriScheme.install();
|
|
||||||
|
|
||||||
mod.runLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Start listening for future requests
|
|
||||||
startListener();
|
|
||||||
|
|
||||||
// Handle initial request
|
|
||||||
String replayId = System.getenv("replaymod.uri.replayid");
|
|
||||||
if (replayId != null) {
|
|
||||||
loadReplay(Integer.parseInt(replayId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startListener() {
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
ServerSocket serverSocket = null;
|
|
||||||
try {
|
|
||||||
serverSocket = new ServerSocket(UriScheme.PROCESS_PORT);
|
|
||||||
while (!Thread.interrupted()) {
|
|
||||||
Socket clientSocket = serverSocket.accept();
|
|
||||||
try {
|
|
||||||
InputStream inputStream = clientSocket.getInputStream();
|
|
||||||
String replayId = IOUtils.toString(inputStream);
|
|
||||||
final int id = Integer.parseInt(replayId);
|
|
||||||
mod.runLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
loadReplay(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(clientSocket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(serverSocket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, "UriSchemeHandler").start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadReplay(int id) {
|
|
||||||
try {
|
|
||||||
module.startReplay(id, "Replay #" + id, GuiScreen.wrap(null));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.replaymod.extras.urischeme;
|
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.io.output.StringBuilderWriter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class WindowsUriScheme extends UriScheme {
|
|
||||||
@Override
|
|
||||||
public void install() throws IOException, InterruptedException {
|
|
||||||
String path = findJarFile().getAbsolutePath().replace("\\", "\\\\").replace("\"", "\\\"");
|
|
||||||
regAdd("\\replaymod /f /ve /d \"URL:replaymod Protocol\"");
|
|
||||||
regAdd("\\replaymod /f /v \"URL Protocol\" /d \"\"");
|
|
||||||
regAdd("\\replaymod\\shell\\open\\command /f /ve /d \"java -cp \\\"" + path + "\\\" " + UriScheme.class.getName() + " \\\"%1\\\"\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void regAdd(String args) throws IOException, InterruptedException {
|
|
||||||
Process process = Runtime.getRuntime().exec("REG ADD HKCU\\Software\\Classes" + args);
|
|
||||||
if (process.waitFor() != 0) {
|
|
||||||
StringBuilderWriter writer = new StringBuilderWriter();
|
|
||||||
IOUtils.copy(process.getInputStream(), writer);
|
|
||||||
IOUtils.copy(process.getErrorStream(), writer);
|
|
||||||
throw new IOException(writer.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
package com.replaymod.online;
|
|
||||||
|
|
||||||
import com.replaymod.core.versions.MCVer;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
public class AuthenticationHash {
|
|
||||||
|
|
||||||
private static final Random random = new Random();
|
|
||||||
|
|
||||||
public AuthenticationHash() {
|
|
||||||
username = MCVer.getMinecraft().getSession().getUsername();
|
|
||||||
currentTime = System.currentTimeMillis();
|
|
||||||
randomLong = random.nextLong();
|
|
||||||
hash = getAuthenticationHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final String username;
|
|
||||||
public final long currentTime;
|
|
||||||
public final long randomLong;
|
|
||||||
public final String hash;
|
|
||||||
|
|
||||||
private String getAuthenticationHash() {
|
|
||||||
String md5 = username + currentTime + randomLong;
|
|
||||||
|
|
||||||
try {
|
|
||||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
|
||||||
byte[] array = md.digest(md5.getBytes());
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (byte b : array) {
|
|
||||||
sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3));
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
} catch (java.security.NoSuchAlgorithmException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
//#if MC<11400
|
|
||||||
//$$ package com.replaymod.online;
|
|
||||||
//$$
|
|
||||||
//$$ import com.replaymod.online.api.ApiClient;
|
|
||||||
//$$ import com.replaymod.online.api.AuthData;
|
|
||||||
//$$ import com.replaymod.online.api.replay.holders.AuthConfirmation;
|
|
||||||
//$$ import net.minecraftforge.common.config.Configuration;
|
|
||||||
//$$ import net.minecraftforge.common.config.Property;
|
|
||||||
//$$
|
|
||||||
//$$ /**
|
|
||||||
//$$ * Auth data stored in a {@link Configuration}.
|
|
||||||
//$$ */
|
|
||||||
//$$ public class ConfigurationAuthData implements AuthData {
|
|
||||||
//$$
|
|
||||||
//$$ private final Configuration config;
|
|
||||||
//$$ private String userName;
|
|
||||||
//$$ private String authKey;
|
|
||||||
//$$
|
|
||||||
//$$ public ConfigurationAuthData(Configuration config) {
|
|
||||||
//$$ this.config = config;
|
|
||||||
//$$ }
|
|
||||||
//$$
|
|
||||||
//$$ /**
|
|
||||||
//$$ * Loads the data from the configuration and checks for its validity.
|
|
||||||
//$$ * If the data is invalid, it is removed from the config.
|
|
||||||
//$$ * @param apiClient Api client used for validating the auth data
|
|
||||||
//$$ */
|
|
||||||
//$$ public void load(ApiClient apiClient) {
|
|
||||||
//$$ Property property = config.get("authkey", "authkey", (String) null);
|
|
||||||
//$$ if (property != null) {
|
|
||||||
//$$ String authKey = property.getString();
|
|
||||||
//$$ AuthConfirmation result = apiClient.checkAuthkey(authKey);
|
|
||||||
//$$ if (result != null) {
|
|
||||||
//$$ this.authKey = authKey;
|
|
||||||
//$$ this.userName = result.getUsername();
|
|
||||||
//$$ } else {
|
|
||||||
//$$ setData(null, null);
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//$$
|
|
||||||
//$$ @Override
|
|
||||||
//$$ public String getUserName() {
|
|
||||||
//$$ return userName;
|
|
||||||
//$$ }
|
|
||||||
//$$
|
|
||||||
//$$ @Override
|
|
||||||
//$$ public String getAuthKey() {
|
|
||||||
//$$ return authKey;
|
|
||||||
//$$ }
|
|
||||||
//$$
|
|
||||||
//$$ @Override
|
|
||||||
//$$ public void setData(String userName, String authKey) {
|
|
||||||
//$$ this.userName = userName;
|
|
||||||
//$$ this.authKey = authKey;
|
|
||||||
//$$
|
|
||||||
//$$ config.removeCategory(config.getCategory("authkey"));
|
|
||||||
//$$ if (authKey != null) {
|
|
||||||
//$$ // Note: .get() actually creates the entry with the default value if it doesn't exist
|
|
||||||
//$$ config.get("authkey", "authkey", authKey);
|
|
||||||
//$$ }
|
|
||||||
//$$ config.save();
|
|
||||||
//$$ }
|
|
||||||
//$$ }
|
|
||||||
//#endif
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
package com.replaymod.online;
|
|
||||||
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.AuthData;
|
|
||||||
import com.replaymod.online.api.replay.holders.AuthConfirmation;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.NoSuchFileException;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.StandardOpenOption;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Auth data stored in a plain text file.
|
|
||||||
*/
|
|
||||||
public class PlainFileAuthData implements AuthData {
|
|
||||||
private final Path path;
|
|
||||||
private String userName;
|
|
||||||
private String authKey;
|
|
||||||
|
|
||||||
public PlainFileAuthData(Path path) {
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the data from the JSON file and checks for its validity.
|
|
||||||
* If the data is invalid, the JSON file is removed.
|
|
||||||
* @param apiClient Api client used for validating the auth data
|
|
||||||
*/
|
|
||||||
public void load(ApiClient apiClient) throws IOException {
|
|
||||||
String authKey;
|
|
||||||
try {
|
|
||||||
authKey = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
|
|
||||||
} catch (NoSuchFileException | FileNotFoundException ignored) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
AuthConfirmation result = apiClient.checkAuthkey(authKey);
|
|
||||||
if (result != null) {
|
|
||||||
this.authKey = authKey;
|
|
||||||
this.userName = result.getUsername();
|
|
||||||
} else {
|
|
||||||
Files.deleteIfExists(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUserName() {
|
|
||||||
return userName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getAuthKey() {
|
|
||||||
return authKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setData(String userName, String authKey) {
|
|
||||||
this.userName = userName;
|
|
||||||
this.authKey = authKey;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Files.write(path, authKey.getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW);
|
|
||||||
} catch (IOException e) {
|
|
||||||
ReplayModOnline.LOGGER.error("Saving auth data:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
package com.replaymod.online;
|
|
||||||
|
|
||||||
import com.replaymod.core.Module;
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
import com.replaymod.core.versions.MCVer;
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.AuthData;
|
|
||||||
import com.replaymod.online.gui.GuiLoginPrompt;
|
|
||||||
import com.replaymod.online.gui.GuiReplayDownloading;
|
|
||||||
import com.replaymod.online.gui.GuiSaveModifiedReplay;
|
|
||||||
import com.replaymod.online.handler.GuiHandler;
|
|
||||||
import com.replaymod.replay.ReplayModReplay;
|
|
||||||
import com.replaymod.replay.events.ReplayClosedCallback;
|
|
||||||
import com.replaymod.replaystudio.replay.ReplayFile;
|
|
||||||
import com.replaymod.replaystudio.replay.ZipReplayFile;
|
|
||||||
import com.replaymod.replaystudio.studio.ReplayStudio;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.utils.EventRegistrations;
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
//#if MC<11400
|
|
||||||
//$$ import net.minecraftforge.common.config.Configuration;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import static com.replaymod.core.versions.MCVer.*;
|
|
||||||
|
|
||||||
public class ReplayModOnline extends EventRegistrations implements Module {
|
|
||||||
{ instance = this; }
|
|
||||||
public static ReplayModOnline instance;
|
|
||||||
|
|
||||||
private ReplayMod core;
|
|
||||||
|
|
||||||
private ReplayModReplay replayModule;
|
|
||||||
|
|
||||||
public static Logger LOGGER = LogManager.getLogger();
|
|
||||||
|
|
||||||
private ApiClient apiClient;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In case the currently opened replay gets modified, the resulting replay file is saved to this location.
|
|
||||||
* Usually a file within the normal replays folder with a unique name.
|
|
||||||
* When the replay is closed, the user is asked whether they want to give it a proper name.
|
|
||||||
*/
|
|
||||||
private File currentReplayOutputFile;
|
|
||||||
|
|
||||||
public ReplayModOnline(ReplayMod core, ReplayModReplay replayModule) {
|
|
||||||
this.core = core;
|
|
||||||
this.replayModule = replayModule;
|
|
||||||
|
|
||||||
core.getSettingsRegistry().register(Setting.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initClient() {
|
|
||||||
Path path = MCVer.getMinecraft().runDirectory.toPath().resolve("config/replaymod-online.token");
|
|
||||||
PlainFileAuthData authData = new PlainFileAuthData(path);
|
|
||||||
apiClient = new ApiClient(authData);
|
|
||||||
if (Files.notExists(path)) {
|
|
||||||
AuthData oldAuthData = loadOldAuthData();
|
|
||||||
if (oldAuthData != null) {
|
|
||||||
authData.setData(oldAuthData.getUserName(), oldAuthData.getAuthKey());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
authData.load(apiClient);
|
|
||||||
} catch (IOException e) {
|
|
||||||
ReplayModOnline.LOGGER.error("Loading auth data:", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!getDownloadsFolder().exists()){
|
|
||||||
if (!getDownloadsFolder().mkdirs()) {
|
|
||||||
LOGGER.warn("Failed to create downloads folder: " + getDownloadsFolder());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new GuiHandler(this).register();
|
|
||||||
register();
|
|
||||||
|
|
||||||
// Initial login prompt
|
|
||||||
if (!core.getSettingsRegistry().get(Setting.SKIP_LOGIN_PROMPT)) {
|
|
||||||
if (!isLoggedIn()) {
|
|
||||||
core.runPostStartup(() -> {
|
|
||||||
GuiScreen parent = GuiScreen.wrap(getMinecraft().currentScreen);
|
|
||||||
new GuiLoginPrompt(apiClient, parent, parent, false).display();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads old auth data from the legacy Configuration system and stores it in the new json file.
|
|
||||||
* Always returns null on 1.13+ where the Configuration system has been removed.
|
|
||||||
*/
|
|
||||||
private AuthData loadOldAuthData() {
|
|
||||||
//#if MC<11400
|
|
||||||
//$$ Path path = MCVer.getMinecraft().mcDataDir.toPath().resolve("config/replaymod-online.cfg");
|
|
||||||
//$$ Configuration config = new Configuration(path.toFile());
|
|
||||||
//$$ ConfigurationAuthData authData = new ConfigurationAuthData(config);
|
|
||||||
//$$ authData.load(new ApiClient(authData));
|
|
||||||
//$$ if (authData.getAuthKey() != null) {
|
|
||||||
//$$ return authData;
|
|
||||||
//$$ }
|
|
||||||
//#endif
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReplayMod getCore() {
|
|
||||||
return core;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReplayModReplay getReplayModule() {
|
|
||||||
return replayModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Logger getLogger() {
|
|
||||||
return LOGGER;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApiClient getApiClient() {
|
|
||||||
return apiClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLoggedIn() {
|
|
||||||
return apiClient.isLoggedIn();
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getDownloadsFolder() {
|
|
||||||
String path = core.getSettingsRegistry().get(Setting.DOWNLOAD_PATH);
|
|
||||||
return new File(path.startsWith("./") ? getMinecraft().runDirectory : null, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public File getDownloadedFile(int id) {
|
|
||||||
return new File(getDownloadsFolder(), id + ".mcpr");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasDownloaded(int id) {
|
|
||||||
return getDownloadedFile(id).exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startReplay(int id, String name, GuiScreen onDownloadCancelled) throws IOException {
|
|
||||||
File file = getDownloadedFile(id);
|
|
||||||
if (file.exists()) {
|
|
||||||
currentReplayOutputFile = new File(core.getReplayFolder(), System.currentTimeMillis() + ".mcpr");
|
|
||||||
ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), file, currentReplayOutputFile);
|
|
||||||
replayModule.startReplay(replayFile);
|
|
||||||
} else {
|
|
||||||
new GuiReplayDownloading(onDownloadCancelled, this, id, name).display();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ on(ReplayClosedCallback.EVENT, replayHandler -> onReplayClosed()); }
|
|
||||||
private void onReplayClosed() {
|
|
||||||
if (currentReplayOutputFile != null) {
|
|
||||||
if (currentReplayOutputFile.exists()) { // Replay was modified, ask user for new name
|
|
||||||
new GuiSaveModifiedReplay(currentReplayOutputFile).display();
|
|
||||||
}
|
|
||||||
currentReplayOutputFile = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package com.replaymod.online;
|
|
||||||
|
|
||||||
import com.replaymod.core.SettingsRegistry;
|
|
||||||
|
|
||||||
public final class Setting<T> extends SettingsRegistry.SettingKeys<T> {
|
|
||||||
public static final Setting<Boolean> SKIP_LOGIN_PROMPT = make("skipLoginPrompt", null, false);
|
|
||||||
public static final SettingsRegistry.SettingKey<String> DOWNLOAD_PATH =
|
|
||||||
new SettingsRegistry.SettingKeys<>("advanced", "downloadPath", null, "./replay_downloads/");
|
|
||||||
|
|
||||||
private static <T> Setting<T> make(String key, String displayName, T defaultValue) {
|
|
||||||
return new Setting<>(key, displayName, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Setting(String key, String displayString, T defaultValue) {
|
|
||||||
super("online", key, displayString == null ? null : "replaymod.gui.settings." + displayString, defaultValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
package com.replaymod.online.api;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
import com.replaymod.core.versions.MCVer;
|
|
||||||
import com.replaymod.online.AuthenticationHash;
|
|
||||||
import com.replaymod.online.api.replay.ReplayModApiMethods;
|
|
||||||
import com.replaymod.online.api.replay.SearchQuery;
|
|
||||||
import com.replaymod.online.api.replay.holders.*;
|
|
||||||
import de.johni0702.minecraft.gui.versions.Image;
|
|
||||||
import net.minecraft.client.MinecraftClient;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY;
|
|
||||||
|
|
||||||
public class ApiClient {
|
|
||||||
|
|
||||||
private static final MinecraftClient mc = MCVer.getMinecraft();
|
|
||||||
private static final Gson gson = new Gson();
|
|
||||||
private static final JsonParser jsonParser = new JsonParser();
|
|
||||||
|
|
||||||
private final AuthData authData;
|
|
||||||
|
|
||||||
public ApiClient(AuthData authData) {
|
|
||||||
this.authData = authData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLoggedIn() {
|
|
||||||
return authData.getUserName() != null && authData.getAuthKey() != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAuthKey() {
|
|
||||||
return authData.getAuthKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void register(String userName, String eMail, String password) throws AuthenticationException, IOException, ApiException {
|
|
||||||
AuthenticationHash authenticationHash = sessionserverJoin();
|
|
||||||
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.register);
|
|
||||||
builder.put("username", userName);
|
|
||||||
builder.put("email", eMail);
|
|
||||||
builder.put("password", password);
|
|
||||||
builder.put("uuid", mc.getSession().getProfile().getId().toString());
|
|
||||||
builder.put("mcusername", authenticationHash.username);
|
|
||||||
builder.put("timelong", authenticationHash.currentTime);
|
|
||||||
builder.put("randomlong", authenticationHash.randomLong);
|
|
||||||
AuthKey auth = invokeAndReturn(builder, AuthKey.class);
|
|
||||||
|
|
||||||
authData.setData(userName, auth.getAuth());
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthData.AuthResult login(String userName, String password) {
|
|
||||||
try {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.login);
|
|
||||||
builder.put("user", userName);
|
|
||||||
builder.put("pw", password);
|
|
||||||
builder.put("mod", true);
|
|
||||||
AuthKey result = invokeAndReturn(builder, AuthKey.class);
|
|
||||||
authData.setData(userName, result.getAuth());
|
|
||||||
return AuthData.AuthResult.SUCCESS;
|
|
||||||
} catch(ApiException e) {
|
|
||||||
return AuthData.AuthResult.INVALID_DATA;
|
|
||||||
} catch(Exception e) {
|
|
||||||
return AuthData.AuthResult.IO_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthData.AuthResult logout() {
|
|
||||||
try {
|
|
||||||
authData.setData(null, null);
|
|
||||||
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.logout);
|
|
||||||
builder.put("auth", authData.getAuthKey());
|
|
||||||
builder.put("mod", true);
|
|
||||||
invokeAndReturn(builder, Success.class);
|
|
||||||
return AuthData.AuthResult.SUCCESS;
|
|
||||||
} catch(ApiException e) {
|
|
||||||
return AuthData.AuthResult.INVALID_DATA;
|
|
||||||
} catch(Exception e) {
|
|
||||||
return AuthData.AuthResult.IO_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private AuthenticationHash sessionserverJoin() throws AuthenticationException {
|
|
||||||
AuthenticationHash hash = new AuthenticationHash();
|
|
||||||
|
|
||||||
mc.getSessionService().joinServer(
|
|
||||||
mc.getSession().getProfile(), mc.getSession().getAccessToken(), hash.hash);
|
|
||||||
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AuthConfirmation checkAuthkey(String auth) {
|
|
||||||
try {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.check_authkey);
|
|
||||||
builder.put("auth", auth);
|
|
||||||
return invokeAndReturn(builder, AuthConfirmation.class);
|
|
||||||
} catch(Exception e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileInfo[] getFileInfo(List<Integer> ids) throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.file_details);
|
|
||||||
builder.put("id", buildListString(ids));
|
|
||||||
return invokeAndReturn(builder, FileInfo[].class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileInfo[] searchFiles(SearchQuery query) throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.search);
|
|
||||||
return invokeAndReturn(builder.toString() + query.buildQuery(), SearchResult.class).getResults();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getTranslation(String languageCode) throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_language);
|
|
||||||
builder.put("language", languageCode);
|
|
||||||
return SimpleApiClient.invokeUrl(builder.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Image downloadThumbnail(int file) throws IOException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_thumbnail);
|
|
||||||
builder.put("id", file);
|
|
||||||
URL url = new URL(builder.toString());
|
|
||||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
|
||||||
connection.setSSLSocketFactory(SSL_SOCKET_FACTORY);
|
|
||||||
try (InputStream in = connection.getInputStream()) {
|
|
||||||
return Image.read(in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean cancelDownload = false;
|
|
||||||
|
|
||||||
public void downloadFile(int file, File target, Consumer<Float> listener) throws IOException, ApiException {
|
|
||||||
cancelDownload = false;
|
|
||||||
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.download_file);
|
|
||||||
builder.put("auth", authData.getAuthKey());
|
|
||||||
builder.put("id", file);
|
|
||||||
String url = builder.toString();
|
|
||||||
URL website = new URL(url);
|
|
||||||
HttpsURLConnection con = (HttpsURLConnection) website.openConnection();
|
|
||||||
con.setSSLSocketFactory(SSL_SOCKET_FACTORY);
|
|
||||||
|
|
||||||
int fileSize = con.getContentLength();
|
|
||||||
|
|
||||||
InputStream is = con.getInputStream();
|
|
||||||
|
|
||||||
if(con.getResponseCode() == 200) {
|
|
||||||
BufferedInputStream bin = new BufferedInputStream(is);
|
|
||||||
FileOutputStream fout = new FileOutputStream(target);
|
|
||||||
try {
|
|
||||||
final byte data[] = new byte[1024];
|
|
||||||
int count;
|
|
||||||
int read = 0;
|
|
||||||
while ((count = bin.read(data, 0, 1024)) != -1) {
|
|
||||||
if(cancelDownload) {
|
|
||||||
bin.close();
|
|
||||||
fout.close();
|
|
||||||
|
|
||||||
FileUtils.deleteQuietly(target);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fout.write(data, 0, count);
|
|
||||||
read += count;
|
|
||||||
listener.accept((float) read / fileSize);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
bin.close();
|
|
||||||
fout.close();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
JsonElement element = jsonParser.parse(IOUtils.toString(is));
|
|
||||||
try {
|
|
||||||
ApiError err = gson.fromJson(element, ApiError.class);
|
|
||||||
if(err.getDesc() != null) {
|
|
||||||
throw new ApiException(err);
|
|
||||||
}
|
|
||||||
} catch(JsonParseException e) {
|
|
||||||
throw new ApiException(IOUtils.toString(is));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelDownload() {
|
|
||||||
this.cancelDownload = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void rateFile(int file, Rating.RatingType rating) throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.rate_file);
|
|
||||||
builder.put("auth", authData.getAuthKey());
|
|
||||||
builder.put("id", file);
|
|
||||||
builder.put("rating", rating.getKey());
|
|
||||||
invokeAndReturn(builder, Success.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileRating[] getRatedFiles() throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_ratings);
|
|
||||||
builder.put("auth", authData.getAuthKey());
|
|
||||||
|
|
||||||
return invokeAndReturn(builder, RatedFiles.class).getRated();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void favFile(int file, boolean fav) throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.fav_file);
|
|
||||||
builder.put("auth", authData.getAuthKey());
|
|
||||||
builder.put("id", file);
|
|
||||||
builder.put("fav", fav);
|
|
||||||
invokeAndReturn(builder, Success.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getFavorites() throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_favorites);
|
|
||||||
builder.put("auth", authData.getAuthKey());
|
|
||||||
|
|
||||||
return invokeAndReturn(builder, Favorites.class).getFavorited();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeFile(int file) throws IOException, ApiException {
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.remove_file);
|
|
||||||
builder.put("auth", authData.getAuthKey());
|
|
||||||
builder.put("id", file);
|
|
||||||
invokeAndReturn(builder, Success.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVersionUpToDate(String versionIdentifier) throws IOException, ApiException {
|
|
||||||
//in a development environment, getContainer().getVersion() will return ${version}
|
|
||||||
if(versionIdentifier.equals("${version}")) return true;
|
|
||||||
|
|
||||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.up_to_date);
|
|
||||||
builder.put("version", versionIdentifier);
|
|
||||||
builder.put("minecraft", ReplayMod.getMinecraftVersion());
|
|
||||||
return invokeAndReturn(builder, Success.class).isSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T invokeAndReturn(QueryBuilder builder, Class<T> classOfT) throws IOException, ApiException {
|
|
||||||
return invokeAndReturn(builder.toString(), classOfT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T> T invokeAndReturn(String url, Class<T> classOfT) throws IOException, ApiException {
|
|
||||||
JsonElement ele = GsonApiClient.invokeJson(url);
|
|
||||||
return gson.fromJson(ele, classOfT);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
private String buildListString(List idList) {
|
|
||||||
if(idList == null) return null;
|
|
||||||
|
|
||||||
String ids = "";
|
|
||||||
Integer x = 0;
|
|
||||||
for(Object id : idList) {
|
|
||||||
x++;
|
|
||||||
ids += id.toString();
|
|
||||||
if(x != idList.size()) {
|
|
||||||
ids += ",";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ids;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
package com.replaymod.online.api;
|
|
||||||
|
|
||||||
import com.replaymod.online.api.replay.holders.ApiError;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@EqualsAndHashCode(callSuper = true)
|
|
||||||
public class ApiException extends Exception {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 349073390504232810L;
|
|
||||||
|
|
||||||
private ApiError error;
|
|
||||||
|
|
||||||
public ApiException(ApiError error) {
|
|
||||||
super(error.getTranslatedDesc());
|
|
||||||
this.error = error;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApiException(String error) {
|
|
||||||
super(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ApiError getError() {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package com.replaymod.online.api;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a set of persistent authentication data.
|
|
||||||
*/
|
|
||||||
public interface AuthData {
|
|
||||||
/**
|
|
||||||
* Returns the user name of the authenticated user.
|
|
||||||
* @return user name or {@code null} if not logged in
|
|
||||||
*/
|
|
||||||
String getUserName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the authentication key of the authenticated user.
|
|
||||||
* @return auth key or {@code null} if not logged in
|
|
||||||
*/
|
|
||||||
String getAuthKey();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Store the authentication data after login.
|
|
||||||
* @param userName The user name
|
|
||||||
* @param authKey The authentication key
|
|
||||||
*/
|
|
||||||
void setData(String userName, String authKey);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result of authentication operations.
|
|
||||||
*/
|
|
||||||
enum AuthResult {
|
|
||||||
/**
|
|
||||||
* The operation succeeded without errors.
|
|
||||||
*/
|
|
||||||
SUCCESS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The data provided got rejected due to it being invalid.
|
|
||||||
*/
|
|
||||||
INVALID_DATA,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Operation could not be performed due to connectivity problems.
|
|
||||||
*/
|
|
||||||
IO_ERROR,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.replaymod.online.api;
|
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import org.apache.commons.lang3.StringEscapeUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class GsonApiClient {
|
|
||||||
|
|
||||||
private static final JsonParser parser = new JsonParser();
|
|
||||||
|
|
||||||
public static JsonElement invoke(QueryBuilder query) throws IOException, ApiException {
|
|
||||||
String apiResult = SimpleApiClient.invoke(query);
|
|
||||||
return wrapWithJson(apiResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static JsonElement invokeJson(String url) throws IOException, ApiException {
|
|
||||||
String apiResult = StringEscapeUtils.unescapeHtml4(SimpleApiClient.invokeUrl(url).replace(""", "\\\""));
|
|
||||||
return wrapWithJson(apiResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JsonElement wrapWithJson(String apiResult) {
|
|
||||||
return parser.parse(apiResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
package com.replaymod.online.api;
|
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class QueryBuilder {
|
|
||||||
|
|
||||||
public String apiMethod;
|
|
||||||
public Map<String, String> paramMap;
|
|
||||||
|
|
||||||
public QueryBuilder(String apiMethod) {
|
|
||||||
this.apiMethod = apiMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void put(String key, Object value) {
|
|
||||||
if(key != null && value != null) {
|
|
||||||
if(paramMap == null) {
|
|
||||||
paramMap = new HashMap<String, String>();
|
|
||||||
}
|
|
||||||
paramMap.put(key, value.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void put(Map<String, Object> paraMap) {
|
|
||||||
if(paraMap == null) return;
|
|
||||||
for(String key : paraMap.keySet()) {
|
|
||||||
put(key, paraMap.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
|
||||||
if(apiMethod == null) throw new IllegalArgumentException("apiMethod may not be null");
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
// build base url
|
|
||||||
sb.append(apiMethod);
|
|
||||||
|
|
||||||
// process parameters
|
|
||||||
try {
|
|
||||||
if(paramMap != null) {
|
|
||||||
boolean first = true;
|
|
||||||
for(String paramName : paramMap.keySet()) {
|
|
||||||
if(first) sb.append("?");
|
|
||||||
if(!first) sb.append("&");
|
|
||||||
first = false;
|
|
||||||
sb.append(paramName);
|
|
||||||
sb.append("=");
|
|
||||||
String value = paramMap.get(paramName);
|
|
||||||
sb.append(URLEncoder.encode(value, "UTF-8"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
} catch(UnsupportedEncodingException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
package com.replaymod.online.api;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import com.replaymod.online.api.replay.holders.ApiError;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY;
|
|
||||||
|
|
||||||
public class SimpleApiClient {
|
|
||||||
|
|
||||||
private static final JsonParser jsonParser = new JsonParser();
|
|
||||||
private static final Gson gson = new Gson();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Json String from the given QueryBuilder
|
|
||||||
*
|
|
||||||
* @param query The QueryBuilder to use
|
|
||||||
* @return A Json String from the API
|
|
||||||
* @throws IOException
|
|
||||||
* @throws ApiException
|
|
||||||
*/
|
|
||||||
public static String invoke(QueryBuilder query) throws IOException, ApiException {
|
|
||||||
return invokeImpl(query.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Json String from the given URL
|
|
||||||
*
|
|
||||||
* @param url The URL to parse the Json from
|
|
||||||
* @return A Json String from the API
|
|
||||||
* @throws IOException
|
|
||||||
* @throws ApiException
|
|
||||||
*/
|
|
||||||
public static String invokeUrl(String url) throws IOException, ApiException {
|
|
||||||
return invokeImpl(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Json String from the API
|
|
||||||
*
|
|
||||||
* @param method The apiMethod to be called
|
|
||||||
* @param paramMap The parameters to apply
|
|
||||||
* @return A Json String from the API
|
|
||||||
* @throws IOException
|
|
||||||
* @throws ApiException
|
|
||||||
*/
|
|
||||||
public static String invoke(String method, Map<String, Object> paramMap) throws IOException, ApiException {
|
|
||||||
return invokeImpl(method, paramMap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a Json String from the API
|
|
||||||
*
|
|
||||||
* @param method The apiMethod to be called
|
|
||||||
* @return A Json String from the API
|
|
||||||
* @throws IOException
|
|
||||||
* @throws ApiException
|
|
||||||
*/
|
|
||||||
public static String invoke(String method) throws IOException, ApiException {
|
|
||||||
return invokeImpl(method, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String invokeImpl(String urlString) throws IOException, ApiException {
|
|
||||||
|
|
||||||
// read response
|
|
||||||
String responseContent = null;
|
|
||||||
InputStream is = null;
|
|
||||||
HttpsURLConnection httpUrlConnection = null;
|
|
||||||
try {
|
|
||||||
URL url = new URL(urlString);
|
|
||||||
httpUrlConnection = (HttpsURLConnection) url.openConnection();
|
|
||||||
httpUrlConnection.setSSLSocketFactory(SSL_SOCKET_FACTORY);
|
|
||||||
|
|
||||||
httpUrlConnection.setRequestMethod("GET");
|
|
||||||
|
|
||||||
// give it 15 seconds to respond
|
|
||||||
httpUrlConnection.setReadTimeout(15 * 1000);
|
|
||||||
httpUrlConnection.connect();
|
|
||||||
|
|
||||||
int responseCode = httpUrlConnection.getResponseCode();
|
|
||||||
|
|
||||||
if(responseCode != 200) {
|
|
||||||
is = httpUrlConnection.getErrorStream();
|
|
||||||
if(is != null) {
|
|
||||||
responseContent = IOUtils.toString(is, "UTF-8");
|
|
||||||
} else {
|
|
||||||
responseContent = "";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
JsonObject response = jsonParser.parse(responseContent).getAsJsonObject();
|
|
||||||
throw new ApiException(gson.fromJson(response, ApiError.class));
|
|
||||||
} catch(JsonParseException e) {
|
|
||||||
throw new ApiException(responseContent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
is = httpUrlConnection.getInputStream();
|
|
||||||
|
|
||||||
responseContent = IOUtils.toString(is, "UTF-8");
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
if(is != null) {
|
|
||||||
is.close();
|
|
||||||
}
|
|
||||||
if(httpUrlConnection != null) {
|
|
||||||
httpUrlConnection.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return responseContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String invokeImpl(String method, Map<String, Object> paramMap) throws IOException, ApiException {
|
|
||||||
QueryBuilder queryBuilder = new QueryBuilder(method);
|
|
||||||
queryBuilder.put(paramMap);
|
|
||||||
return invokeImpl(queryBuilder.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.ApiException;
|
|
||||||
import com.replaymod.online.api.replay.holders.ApiError;
|
|
||||||
import com.replaymod.online.api.replay.holders.Category;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import static com.replaymod.core.utils.Utils.SSL_SOCKET_FACTORY;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class FileUploader {
|
|
||||||
private static final Gson gson = new Gson();
|
|
||||||
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
|
|
||||||
private volatile boolean uploading = false;
|
|
||||||
private volatile boolean cancel;
|
|
||||||
private long filesize;
|
|
||||||
private long current;
|
|
||||||
|
|
||||||
public synchronized void uploadFile(File file, String filename, Set<String> tags, Category category,
|
|
||||||
String description, Consumer<Double> progress) throws Exception {
|
|
||||||
try {
|
|
||||||
uploading = true;
|
|
||||||
|
|
||||||
String postData = "?auth=" + apiClient.getAuthKey() + "&category=" + category.getId();
|
|
||||||
|
|
||||||
if(tags.size() > 0) {
|
|
||||||
postData += "&tags=" + StringUtils.join(tags.toArray(new String[tags.size()]), ",");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(description != null && description.length() > 0) {
|
|
||||||
postData += "&description=" + URLEncoder.encode(description, "UTF-8");
|
|
||||||
}
|
|
||||||
|
|
||||||
postData += "&name=" + URLEncoder.encode(filename, "UTF-8");
|
|
||||||
|
|
||||||
String url = ReplayModApiMethods.upload_file + postData;
|
|
||||||
HttpsURLConnection con = (HttpsURLConnection) new URL(url).openConnection();
|
|
||||||
con.setSSLSocketFactory(SSL_SOCKET_FACTORY);
|
|
||||||
con.setUseCaches(false);
|
|
||||||
con.setDoOutput(true);
|
|
||||||
con.setRequestMethod("POST");
|
|
||||||
con.setChunkedStreamingMode(1024);
|
|
||||||
con.setRequestProperty("Connection", "Keep-Alive");
|
|
||||||
con.setRequestProperty("Cache-Control", "no-cache");
|
|
||||||
String boundary = "*****";
|
|
||||||
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
|
|
||||||
|
|
||||||
DataOutputStream request = new DataOutputStream(con.getOutputStream());
|
|
||||||
|
|
||||||
String crlf = "\r\n";
|
|
||||||
String twoHyphens = "--";
|
|
||||||
request.writeBytes(twoHyphens + boundary + crlf);
|
|
||||||
String attachmentName = "file";
|
|
||||||
String attachmentFileName = "file.mcpr";
|
|
||||||
request.writeBytes("Content-Disposition: form-data; name=\"" + attachmentName + "\";filename=\"" + attachmentFileName + "\"" + crlf);
|
|
||||||
request.writeBytes(crlf);
|
|
||||||
|
|
||||||
byte[] buf = new byte[1024];
|
|
||||||
FileInputStream fis = new FileInputStream(file);
|
|
||||||
filesize = fis.getChannel().size();
|
|
||||||
current = 0;
|
|
||||||
int len;
|
|
||||||
while((len = fis.read(buf)) != -1) {
|
|
||||||
request.write(buf);
|
|
||||||
current += len;
|
|
||||||
|
|
||||||
progress.accept(getUploadProgress());
|
|
||||||
|
|
||||||
if(cancel) {
|
|
||||||
fis.close();
|
|
||||||
throw new CancelledException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fis.close();
|
|
||||||
|
|
||||||
request.writeBytes(crlf);
|
|
||||||
request.writeBytes(twoHyphens + boundary + twoHyphens + crlf);
|
|
||||||
|
|
||||||
request.flush();
|
|
||||||
request.close();
|
|
||||||
|
|
||||||
int responseCode = con.getResponseCode();
|
|
||||||
InputStream is = responseCode == 200 ? con.getInputStream() : con.getErrorStream();
|
|
||||||
if (is == null) {
|
|
||||||
throw new RuntimeException("Input stream was null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
String result = IOUtils.toString(is);
|
|
||||||
if (responseCode != 200) {
|
|
||||||
ApiError error = gson.fromJson(result, ApiError.class);
|
|
||||||
throw new ApiException(error);
|
|
||||||
}
|
|
||||||
con.disconnect();
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
uploading = false;
|
|
||||||
cancel = false;
|
|
||||||
current = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getUploadProgress() {
|
|
||||||
if(!uploading || filesize == 0) return 0;
|
|
||||||
return (double) current / filesize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancelUploading() {
|
|
||||||
cancel = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class CancelledException extends Exception {}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay;
|
|
||||||
|
|
||||||
public class ReplayModApiMethods {
|
|
||||||
|
|
||||||
public static final String REPLAYMOD_BASE_URL = "https://ReplayMod.com/api/";
|
|
||||||
|
|
||||||
public static final String register = REPLAYMOD_BASE_URL+"register";
|
|
||||||
public static final String check_authkey = REPLAYMOD_BASE_URL+"check_authkey";
|
|
||||||
public static final String login = REPLAYMOD_BASE_URL+"login";
|
|
||||||
public static final String logout = REPLAYMOD_BASE_URL+"logout";
|
|
||||||
public static final String file_details = REPLAYMOD_BASE_URL+"file_details";
|
|
||||||
public static final String upload_file = REPLAYMOD_BASE_URL+"upload_file";
|
|
||||||
public static final String download_file = REPLAYMOD_BASE_URL+"download_file";
|
|
||||||
public static final String get_thumbnail = REPLAYMOD_BASE_URL+"get_thumbnail";
|
|
||||||
public static final String remove_file = REPLAYMOD_BASE_URL+"remove_file";
|
|
||||||
public static final String rate_file = REPLAYMOD_BASE_URL+"rate_file";
|
|
||||||
public static final String get_ratings = REPLAYMOD_BASE_URL+"get_ratings";
|
|
||||||
public static final String fav_file = REPLAYMOD_BASE_URL+"fav_file";
|
|
||||||
public static final String get_favorites = REPLAYMOD_BASE_URL+"get_favorites";
|
|
||||||
public static final String check_auth = REPLAYMOD_BASE_URL+"check_auth";
|
|
||||||
public static final String get_language = REPLAYMOD_BASE_URL+"get_language";
|
|
||||||
public static final String search = REPLAYMOD_BASE_URL+"search";
|
|
||||||
public static final String up_to_date = REPLAYMOD_BASE_URL+"up_to_date";
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class SearchQuery {
|
|
||||||
|
|
||||||
public Boolean order, singleplayer;
|
|
||||||
public String player, tag, version, server, name, auth;
|
|
||||||
public Integer category, offset;
|
|
||||||
|
|
||||||
public String buildQuery() {
|
|
||||||
String query = "";
|
|
||||||
boolean first = true;
|
|
||||||
|
|
||||||
//Please don't slaughter me for this code,
|
|
||||||
//even if I deserve it, which I certainly do.
|
|
||||||
for(Field f : this.getClass().getDeclaredFields()) {
|
|
||||||
try {
|
|
||||||
Object value = f.get(this);
|
|
||||||
if(value == null) continue;
|
|
||||||
query += first ? "?" : "&";
|
|
||||||
first = false;
|
|
||||||
query += f.getName() + "=";
|
|
||||||
query += URLEncoder.encode(String.valueOf(value), "UTF-8");
|
|
||||||
} catch(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return buildQuery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import net.minecraft.client.resource.language.I18n;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class ApiError {
|
|
||||||
|
|
||||||
private int id;
|
|
||||||
private String desc;
|
|
||||||
private String key;
|
|
||||||
private String[] objects;
|
|
||||||
|
|
||||||
public String getTranslatedDesc() {
|
|
||||||
try {
|
|
||||||
return I18n.translate(key, (Object[]) objects);
|
|
||||||
} catch(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class AuthConfirmation {
|
|
||||||
private String username;
|
|
||||||
private int id;
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class AuthKey {
|
|
||||||
private String auth;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import net.minecraft.client.resource.language.I18n;
|
|
||||||
|
|
||||||
public enum Category {
|
|
||||||
|
|
||||||
SURVIVAL(0, "replaymod.category.survival"), MINIGAME(1, "replaymod.category.minigame"),
|
|
||||||
BUILD(2, "replaymod.category.build"), MISCELLANEOUS(3, "replaymod.category.misc");
|
|
||||||
|
|
||||||
private int id;
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
Category(int id, String name) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getId() {
|
|
||||||
return this.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Category fromId(int id) {
|
|
||||||
for(Category c : values()) {
|
|
||||||
if(c.id == id) return c;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toNiceString() {
|
|
||||||
return I18n.translate(this.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Category next() {
|
|
||||||
for(int i = 0; i < values().length; i++) {
|
|
||||||
if(values()[i] == this) {
|
|
||||||
if(i == values().length - 1) {
|
|
||||||
i = -1;
|
|
||||||
}
|
|
||||||
return values()[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String[] stringValues() {
|
|
||||||
String[] values = new String[Category.values().length];
|
|
||||||
int i = 0;
|
|
||||||
for (Category c : Category.values()) {
|
|
||||||
values[i++] = c.toNiceString();
|
|
||||||
}
|
|
||||||
return values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class Donated {
|
|
||||||
|
|
||||||
@Getter(AccessLevel.NONE)
|
|
||||||
private boolean donated = false;
|
|
||||||
|
|
||||||
public boolean hasDonated() {
|
|
||||||
return donated;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class Favorites {
|
|
||||||
private int[] favorited;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import com.replaymod.replaystudio.replay.ReplayMetaData;
|
|
||||||
import lombok.AccessLevel;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
public class FileInfo {
|
|
||||||
private int id;
|
|
||||||
private ReplayMetaData metadata;
|
|
||||||
private String owner;
|
|
||||||
private Rating ratings;
|
|
||||||
private int size;
|
|
||||||
private int category;
|
|
||||||
private int downloads;
|
|
||||||
private String name;
|
|
||||||
@Getter(AccessLevel.NONE)
|
|
||||||
private boolean thumbnail;
|
|
||||||
private int favorites;
|
|
||||||
|
|
||||||
public boolean hasThumbnail() {
|
|
||||||
return thumbnail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class FileRating {
|
|
||||||
private int file;
|
|
||||||
@SerializedName("rating") private boolean ratingPositive;
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
public enum MinecraftVersion {
|
|
||||||
|
|
||||||
MC_1_8("Minecraft 1.8", "1.8"),
|
|
||||||
MC_1_9_4("Minecraft 1.9.4", "1.9.4"),
|
|
||||||
MC_1_10_2("Minecraft 1.10.2", "1.10.2"),
|
|
||||||
MC_1_11("Minecraft 1.11", "1.11"),
|
|
||||||
MC_1_11_2("Minecraft 1.11.2", "1.11.2"),
|
|
||||||
MC_1_12("Minecraft 1.12", "1.12"),
|
|
||||||
MC_1_12_1("Minecraft 1.12.1", "1.12.1"),
|
|
||||||
MC_1_12_2("Minecraft 1.12.2", "1.12.2"),
|
|
||||||
MC_1_13_2("Minecraft 1.13.2", "1.13.2"),
|
|
||||||
MC_1_14_4("Minecraft 1.14.4", "1.14.4");
|
|
||||||
|
|
||||||
private String niceName, apiName;
|
|
||||||
|
|
||||||
MinecraftVersion(String niceName, String apiName) {
|
|
||||||
this.niceName = niceName;
|
|
||||||
this.apiName = apiName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toNiceName() {
|
|
||||||
return niceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getApiName() {
|
|
||||||
return apiName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class RatedFiles {
|
|
||||||
private FileRating[] rated;
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class Rating {
|
|
||||||
private int negative, positive;
|
|
||||||
|
|
||||||
public enum RatingType {
|
|
||||||
|
|
||||||
LIKE("like"), DISLIKE("dislike"), NEUTRAL("neutral");
|
|
||||||
|
|
||||||
private String key;
|
|
||||||
|
|
||||||
public String getKey() { return key; }
|
|
||||||
|
|
||||||
RatingType(String key) {
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RatingType fromBoolean(Boolean rating) {
|
|
||||||
return rating == null ? RatingType.NEUTRAL :
|
|
||||||
(rating ? RatingType.LIKE : RatingType.DISLIKE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class SearchResult {
|
|
||||||
private FileInfo[] results;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class Success {
|
|
||||||
private boolean success = false;
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.holders;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class UserFiles {
|
|
||||||
private String user;
|
|
||||||
private FileInfo[] files;
|
|
||||||
private int total_size;
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.pagination;
|
|
||||||
|
|
||||||
import com.replaymod.online.ReplayModOnline;
|
|
||||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class DownloadedFilePagination implements Pagination {
|
|
||||||
|
|
||||||
private final ReplayModOnline mod;
|
|
||||||
private int page;
|
|
||||||
private HashMap<Integer, FileInfo> files = new HashMap<>();
|
|
||||||
|
|
||||||
public DownloadedFilePagination(ReplayModOnline mod) {
|
|
||||||
this.mod = mod;
|
|
||||||
this.page = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FileInfo> getFiles() {
|
|
||||||
return new ArrayList<>(files.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLoadedPages() {
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fetchPage() {
|
|
||||||
page++;
|
|
||||||
|
|
||||||
List<Integer> toAdd = new ArrayList<>();
|
|
||||||
for(String fileName : mod.getDownloadsFolder().list()) {
|
|
||||||
int i;
|
|
||||||
try {
|
|
||||||
i = Integer.parseInt(fileName.substring(0, fileName.indexOf('.')));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(!files.containsKey(i)) {
|
|
||||||
toAdd.add(i);
|
|
||||||
if(toAdd.size() >= Pagination.PAGE_SIZE) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
FileInfo[] fis = mod.getApiClient().getFileInfo(toAdd);
|
|
||||||
if(fis.length < 1) {
|
|
||||||
page--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(FileInfo info : fis) {
|
|
||||||
files.put(info.getId(), info);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
page--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.pagination;
|
|
||||||
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class FavoritedFilePagination implements Pagination {
|
|
||||||
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
private int page;
|
|
||||||
private HashMap<Integer, FileInfo> files = new HashMap<>();
|
|
||||||
|
|
||||||
public FavoritedFilePagination(ApiClient apiClient) {
|
|
||||||
this.apiClient = apiClient;
|
|
||||||
this.page = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FileInfo> getFiles() {
|
|
||||||
return new ArrayList<>(files.values());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLoadedPages() {
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fetchPage() {
|
|
||||||
page++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
int[] f = apiClient.getFavorites();
|
|
||||||
List<Integer> toAdd = new ArrayList<>();
|
|
||||||
for(int i : f) {
|
|
||||||
if(!files.containsKey(i)) {
|
|
||||||
toAdd.add(i);
|
|
||||||
if(toAdd.size() >= Pagination.PAGE_SIZE) break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FileInfo[] fis = apiClient.getFileInfo(toAdd);
|
|
||||||
if(fis.length < 1) {
|
|
||||||
page--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(FileInfo info : fis) {
|
|
||||||
files.put(info.getId(), info);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
page--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.pagination;
|
|
||||||
|
|
||||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public interface Pagination {
|
|
||||||
List<FileInfo> getFiles();
|
|
||||||
|
|
||||||
int getLoadedPages();
|
|
||||||
|
|
||||||
boolean fetchPage();
|
|
||||||
|
|
||||||
int PAGE_SIZE = 30; //defined by the Website API
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
package com.replaymod.online.api.replay.pagination;
|
|
||||||
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.replay.SearchQuery;
|
|
||||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class SearchPagination implements Pagination {
|
|
||||||
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
private final SearchQuery searchQuery;
|
|
||||||
private int page;
|
|
||||||
private List<FileInfo> files = new ArrayList<FileInfo>();
|
|
||||||
|
|
||||||
public SearchPagination(ApiClient apiClient, SearchQuery searchQuery) {
|
|
||||||
this.apiClient = apiClient;
|
|
||||||
this.page = -1;
|
|
||||||
this.searchQuery = searchQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FileInfo> getFiles() {
|
|
||||||
return Collections.unmodifiableList(files);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getLoadedPages() {
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean fetchPage() {
|
|
||||||
page++;
|
|
||||||
searchQuery.offset = page;
|
|
||||||
|
|
||||||
try {
|
|
||||||
FileInfo[] fis = apiClient.searchFiles(searchQuery);
|
|
||||||
if(fis.length < 1) {
|
|
||||||
page--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
files.addAll(Arrays.asList(fis));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} catch(Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
page--;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
package com.replaymod.online.gui;
|
|
||||||
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiPasswordField;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiTextField;
|
|
||||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Consumer;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Utils;
|
|
||||||
|
|
||||||
public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
|
|
||||||
|
|
||||||
private final GuiScreen parent, successScreen;
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
|
|
||||||
private GuiLabel usernameLabel = new GuiLabel(this).setI18nText("replaymod.gui.username");
|
|
||||||
private GuiLabel passwordLabel = new GuiLabel(this).setI18nText("replaymod.gui.password");
|
|
||||||
private GuiLabel noAccountLabel = new GuiLabel(this).setI18nText("replaymod.gui.login.noacc");
|
|
||||||
private GuiLabel statusLabel = new GuiLabel(this);
|
|
||||||
private GuiButton loginButton = new GuiButton(this).setI18nLabel("replaymod.gui.login").setSize(150, 20).setEnabled(false);
|
|
||||||
public GuiButton cancelButton = new GuiButton(this).setI18nLabel("replaymod.gui.cancel").setSize(150, 20);
|
|
||||||
private GuiButton registerButton = new GuiButton(this).setI18nLabel("replaymod.gui.register").setSize(150, 20);
|
|
||||||
private GuiTextField username = new GuiTextField(this).setSize(145, 20).setMaxLength(16).setFocused(true);
|
|
||||||
private GuiPasswordField password = new GuiPasswordField(this).setSize(145, 20)
|
|
||||||
.setMaxLength(GuiRegister.MAX_PW_LENGTH);
|
|
||||||
|
|
||||||
{
|
|
||||||
Utils.link(username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Runnable doLogin = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!loginButton.isEnabled()) return;
|
|
||||||
statusLabel.setI18nText("replaymod.gui.login.logging");
|
|
||||||
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
switch (apiClient.login(username.getText(), password.getText())) {
|
|
||||||
case SUCCESS:
|
|
||||||
statusLabel.setText("");
|
|
||||||
ReplayMod.instance.runLater(successScreen::display);
|
|
||||||
break;
|
|
||||||
case INVALID_DATA:
|
|
||||||
statusLabel.setI18nText("replaymod.gui.login.incorrect");
|
|
||||||
break;
|
|
||||||
case IO_ERROR:
|
|
||||||
statusLabel.setI18nText("replaymod.gui.login.connectionerror");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, "replaymod-auth").start();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
username.onEnter(doLogin);
|
|
||||||
password.onEnter(doLogin);
|
|
||||||
loginButton.onClick(doLogin);
|
|
||||||
cancelButton.onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
parent.display();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
registerButton.onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
new GuiRegister(apiClient, GuiLoginPrompt.this).display();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Consumer<String> contentValidation = new Consumer<String>() {
|
|
||||||
@Override
|
|
||||||
public void consume(String obj) {
|
|
||||||
loginButton.setEnabled(!username.getText().isEmpty() && !password.getText().isEmpty());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
username.onTextChanged(contentValidation);
|
|
||||||
password.onTextChanged(contentValidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GuiLoginPrompt(ApiClient apiClient, GuiScreen parent, GuiScreen successScreen, boolean manuallyTriggered) {
|
|
||||||
this.apiClient = apiClient;
|
|
||||||
this.parent = parent;
|
|
||||||
this.successScreen = successScreen;
|
|
||||||
|
|
||||||
//if the login prompt was opened automatically (on mod startup), show a "skip" instead of "cancel" button
|
|
||||||
if(!manuallyTriggered) {
|
|
||||||
cancelButton.setI18nLabel("replaymod.gui.login.skip");
|
|
||||||
}
|
|
||||||
|
|
||||||
setLayout(new CustomLayout<GuiLoginPrompt>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiLoginPrompt container, int width, int height) {
|
|
||||||
pos(username, width / 2 - 45, 30);
|
|
||||||
pos(password, width / 2 - 45, 60);
|
|
||||||
pos(loginButton, width / 2 - 152, 110);
|
|
||||||
pos(cancelButton, width / 2 + 2, 110);
|
|
||||||
|
|
||||||
pos(usernameLabel, x(username) - 10 - usernameLabel.getMinSize().getWidth(), y(username) + 7);
|
|
||||||
pos(passwordLabel, x(password) - 10 - passwordLabel.getMinSize().getWidth(), y(password) + 7);
|
|
||||||
pos(statusLabel, width / 2 - statusLabel.getMinSize().getWidth() / 2, 92);
|
|
||||||
|
|
||||||
int labelWidth = noAccountLabel.getMinSize().getWidth();
|
|
||||||
int buttonWidth = registerButton.getMaxSize().getWidth();
|
|
||||||
int lineWidth = labelWidth + 5 + buttonWidth;
|
|
||||||
int lineStart = width / 2 - lineWidth / 2;
|
|
||||||
pos(noAccountLabel, lineStart, height - 22);
|
|
||||||
pos(registerButton, lineStart + labelWidth + 5, height - 30);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.login.title"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public GuiScreen getSuccessScreen() {
|
|
||||||
return successScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GuiLoginPrompt getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
package com.replaymod.online.gui;
|
|
||||||
|
|
||||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.ApiException;
|
|
||||||
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
|
||||||
import de.johni0702.minecraft.gui.element.*;
|
|
||||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Consumers;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Utils;
|
|
||||||
import com.replaymod.core.utils.Patterns;
|
|
||||||
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
|
|
||||||
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableColor;
|
|
||||||
import net.minecraft.client.font.TextRenderer;
|
|
||||||
|
|
||||||
public class GuiRegister extends AbstractGuiScreen<GuiRegister> {
|
|
||||||
public static final int MIN_PW_LENGTH = 5;
|
|
||||||
public static final int MAX_PW_LENGTH = 1024;
|
|
||||||
|
|
||||||
private final GuiPanel inputs;
|
|
||||||
private final GuiTextField usernameInput, mailInput;
|
|
||||||
private final GuiPasswordField passwordInput, passwordConfirmation;
|
|
||||||
private final GuiButton registerButton = new GuiButton(this).setI18nLabel("replaymod.gui.register").setSize(150, 20).setDisabled();
|
|
||||||
private final GuiButton cancelButton = new GuiButton(this).setI18nLabel("replaymod.gui.cancel").setSize(150, 20);
|
|
||||||
private final GuiLabel disclaimerLabel = new GuiLabel(this).setI18nText("replaymod.gui.register.disclaimer");
|
|
||||||
private final GuiLabel statusLabel = new GuiLabel(this).setColor(ReadableColor.RED);
|
|
||||||
|
|
||||||
{
|
|
||||||
inputs = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(10));
|
|
||||||
HorizontalLayout.Data data = new HorizontalLayout.Data(0.5);
|
|
||||||
inputs.addElements(new VerticalLayout.Data(1),
|
|
||||||
new GuiPanel().setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(10))
|
|
||||||
.addElements(data, new GuiLabel().setI18nText("replaymod.gui.username"))
|
|
||||||
.addElements(data, usernameInput = new GuiTextField().setMaxLength(16).setSize(145, 20)),
|
|
||||||
new GuiPanel().setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(10))
|
|
||||||
.addElements(data, new GuiLabel().setI18nText("replaymod.gui.mail"))
|
|
||||||
.addElements(data, mailInput = new GuiTextField().setSize(145, 20)),
|
|
||||||
new GuiPanel().setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(10))
|
|
||||||
.addElements(data, new GuiLabel().setI18nText("replaymod.gui.password"))
|
|
||||||
.addElements(data, passwordInput = new GuiPasswordField().setMaxLength(MAX_PW_LENGTH+1).setSize(145, 20)),
|
|
||||||
new GuiPanel().setLayout(new HorizontalLayout(HorizontalLayout.Alignment.RIGHT).setSpacing(10))
|
|
||||||
.addElements(data, new GuiLabel().setI18nText("replaymod.gui.register.confirmpw"))
|
|
||||||
.addElements(data, passwordConfirmation = new GuiPasswordField().setMaxLength(MAX_PW_LENGTH+1).setSize(145, 20))
|
|
||||||
);
|
|
||||||
Utils.link(usernameInput, mailInput, passwordInput, passwordConfirmation);
|
|
||||||
|
|
||||||
setLayout(new CustomLayout<GuiRegister>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiRegister container, int width, int height) {
|
|
||||||
pos(inputs, width / 2 - inputs.getMinSize().getWidth() / 2, 30);
|
|
||||||
pos(registerButton, width / 2 - 152, 170);
|
|
||||||
pos(cancelButton, width / 2 + 2, 170);
|
|
||||||
pos(statusLabel, width / 2 - statusLabel.getMinSize().getWidth() / 2, 152);
|
|
||||||
|
|
||||||
TextRenderer font = getMinecraft().textRenderer;
|
|
||||||
int lineCount = font.wrapStringToWidthAsList(disclaimerLabel.getText(), width - 10).size();
|
|
||||||
Dimension dim = new Dimension(width - 10, font.fontHeight * lineCount);
|
|
||||||
disclaimerLabel.setSize(dim);
|
|
||||||
pos(disclaimerLabel, 5, height - dim.getHeight() - 5);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.register.title"));
|
|
||||||
|
|
||||||
Runnable doRegister = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!registerButton.isEnabled()) return;
|
|
||||||
|
|
||||||
inputs.forEach(IGuiTextField.class).setDisabled();
|
|
||||||
statusLabel.setI18nText("replaymod.gui.login.logging");
|
|
||||||
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
String username = usernameInput.getText().trim();
|
|
||||||
String mail = mailInput.getText().trim();
|
|
||||||
String password = passwordInput.getText();
|
|
||||||
apiClient.register(username, mail, password);
|
|
||||||
|
|
||||||
ReplayMod.instance.runLater(parent.getSuccessScreen()::display);
|
|
||||||
} catch (ApiException ae) {
|
|
||||||
statusLabel.setText(ae.getLocalizedMessage());
|
|
||||||
} catch (AuthenticationException aue) {
|
|
||||||
aue.printStackTrace();
|
|
||||||
statusLabel.setI18nText("replaymod.gui.register.error.authfailed");
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
statusLabel.setI18nText("replaymod.gui.login.connectionerror");
|
|
||||||
} finally {
|
|
||||||
inputs.forEach(IGuiTextField.class).setEnabled();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, "replaymod-register").start();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inputs.forEach(IGuiTextField.class).onEnter(doRegister);
|
|
||||||
registerButton.onClick(doRegister);
|
|
||||||
|
|
||||||
Runnable contentValidation = new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String status = null;
|
|
||||||
if (usernameInput.getText().length() < 1) {
|
|
||||||
status = "replaymod.gui.register.error.shortusername";
|
|
||||||
} else if(!Patterns.ALPHANUMERIC_UNDERSCORE.matcher(usernameInput.getText().trim()).matches()) {
|
|
||||||
status = "replaymod.gui.register.error.invalidname";
|
|
||||||
} else if (passwordInput.getText().length() < MIN_PW_LENGTH) {
|
|
||||||
status = "replaymod.gui.register.error.shortpw";
|
|
||||||
} else if (passwordInput.getText().length() > MAX_PW_LENGTH) {
|
|
||||||
status = "replaymod.gui.register.error.longpw";
|
|
||||||
} else if (!com.replaymod.core.utils.Utils.isValidEmailAddress(mailInput.getText())) {
|
|
||||||
status = "replaymod.api.invalidmail";
|
|
||||||
} else if (!passwordConfirmation.getText().equals(passwordInput.getText())) {
|
|
||||||
status = "replaymod.gui.register.error.nomatch";
|
|
||||||
}
|
|
||||||
|
|
||||||
registerButton.setEnabled(status == null);
|
|
||||||
|
|
||||||
if (status != null
|
|
||||||
&& !usernameInput.getText().isEmpty()
|
|
||||||
&& !mailInput.getText().isEmpty()
|
|
||||||
&& !passwordInput.getText().isEmpty()
|
|
||||||
&& !passwordConfirmation.getText().isEmpty()) {
|
|
||||||
statusLabel.setI18nText(status);
|
|
||||||
} else {
|
|
||||||
statusLabel.setText("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
inputs.forEach(IGuiTextField.class).onTextChanged(Consumers.from(contentValidation));
|
|
||||||
|
|
||||||
cancelButton.onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
parent.display();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
private final GuiLoginPrompt parent;
|
|
||||||
|
|
||||||
public GuiRegister(ApiClient apiClient, GuiLoginPrompt parent) {
|
|
||||||
this.apiClient = apiClient;
|
|
||||||
this.parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GuiRegister getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,471 +0,0 @@
|
|||||||
package com.replaymod.online.gui;
|
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
|
||||||
import com.google.common.base.Supplier;
|
|
||||||
import com.google.common.primitives.Ints;
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
import com.google.common.util.concurrent.Futures;
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
import com.replaymod.core.utils.Utils;
|
|
||||||
import com.replaymod.online.ReplayModOnline;
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.ApiException;
|
|
||||||
import com.replaymod.online.api.replay.SearchQuery;
|
|
||||||
import com.replaymod.online.api.replay.holders.Category;
|
|
||||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
|
||||||
import com.replaymod.online.api.replay.holders.FileRating;
|
|
||||||
import com.replaymod.online.api.replay.holders.Rating;
|
|
||||||
import com.replaymod.online.api.replay.pagination.DownloadedFilePagination;
|
|
||||||
import com.replaymod.online.api.replay.pagination.FavoritedFilePagination;
|
|
||||||
import com.replaymod.online.api.replay.pagination.Pagination;
|
|
||||||
import com.replaymod.online.api.replay.pagination.SearchPagination;
|
|
||||||
import com.replaymod.replaystudio.replay.ReplayMetaData;
|
|
||||||
import com.replaymod.replaystudio.studio.ReplayStudio;
|
|
||||||
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiContainer;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiImage;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiTooltip;
|
|
||||||
import de.johni0702.minecraft.gui.element.IGuiButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.advanced.GuiResourceLoadingList;
|
|
||||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
|
||||||
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Colors;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Consumer;
|
|
||||||
import de.johni0702.minecraft.gui.utils.lwjgl.Dimension;
|
|
||||||
import de.johni0702.minecraft.gui.utils.lwjgl.ReadableDimension;
|
|
||||||
import de.johni0702.minecraft.gui.versions.Image;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import net.minecraft.util.Formatting;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static com.replaymod.online.ReplayModOnline.LOGGER;
|
|
||||||
|
|
||||||
public class GuiReplayCenter extends GuiScreen {
|
|
||||||
private final ReplayModOnline mod;
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
|
|
||||||
private GuiButton makeCategory(String name) {
|
|
||||||
return new GuiButton().setI18nLabel("replaymod.gui.center.top." + name).setSize(75, 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
public final GuiButton categoryRecent = makeCategory("recent").onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
show(new SearchPagination(apiClient,
|
|
||||||
new SearchQuery(false, null, null, null, null, null, null, null, null, null)));
|
|
||||||
categoryRecent.setDisabled();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public final GuiButton categoryBest = makeCategory("best").onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
show(new SearchPagination(apiClient,
|
|
||||||
new SearchQuery(true, null, null, null, null, null, null, null, null, null)));
|
|
||||||
categoryBest.setDisabled();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public final GuiButton categoryDownloaded = makeCategory("downloaded").onClick(new Runnable()
|
|
||||||
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
show(new DownloadedFilePagination(mod));
|
|
||||||
categoryDownloaded.setDisabled();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public final GuiButton categoryFavorited = makeCategory("favorited").onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
show(new FavoritedFilePagination(apiClient));
|
|
||||||
categoryFavorited.setDisabled();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public final GuiButton categorySearch = makeCategory("search").onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
searchPopup.open();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public final GuiPanel categories = new GuiPanel(this).setLayout(new HorizontalLayout().setSpacing(5))
|
|
||||||
.addElements(null, categoryRecent, categoryBest, categoryDownloaded, categoryFavorited, categorySearch);
|
|
||||||
|
|
||||||
public final GuiResourceLoadingList<GuiReplayEntry> list = new GuiResourceLoadingList<GuiReplayEntry>(this).onSelectionChanged(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
GuiReplayEntry selected = list.getSelected();
|
|
||||||
replayButtonPanel.forEach(IGuiButton.class).setEnabled(selected != null);
|
|
||||||
replayButtonPanel.forEach(IGuiButton.class).setTooltip(null);
|
|
||||||
if (selected != null) {
|
|
||||||
int replayId = selected.fileInfo.getId();
|
|
||||||
boolean favorited = favoritedReplays.contains(replayId);
|
|
||||||
boolean liked = likedReplays.contains(replayId);
|
|
||||||
boolean disliked = dislikedReplays.contains(replayId);
|
|
||||||
|
|
||||||
loadButton.setI18nLabel(selected.downloaded ? "replaymod.gui.load" : "replaymod.gui.download");
|
|
||||||
if (selected.incompatible) {
|
|
||||||
loadButton.setDisabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
favoriteButton.setI18nLabel("replaymod.gui.center." + (favorited ? "unfavorite" : "favorite"));
|
|
||||||
// Only allow button usage for either unfavorite or favorite after they've actually downloaded it
|
|
||||||
favoriteButton.setEnabled(favorited || selected.downloaded);
|
|
||||||
if (favoriteButton.isEnabled()) {
|
|
||||||
favoriteButton.setTooltip(null);
|
|
||||||
} else {
|
|
||||||
favoriteButton.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.center.downloadrequired"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similar for like/dislike buttons
|
|
||||||
likeButton.setEnabled(selected.downloaded);
|
|
||||||
dislikeButton.setEnabled(selected.downloaded);
|
|
||||||
if (likeButton.isEnabled()) {
|
|
||||||
likeButton.setTooltip(null);
|
|
||||||
dislikeButton.setTooltip(null);
|
|
||||||
} else {
|
|
||||||
likeButton.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.center.downloadrequired"));
|
|
||||||
dislikeButton.setTooltip(new GuiTooltip().setI18nText("replaymod.gui.center.downloadrequired"));
|
|
||||||
}
|
|
||||||
likeButton.setI18nLabel("replaymod.gui." + (liked ? "removelike" : "like"));
|
|
||||||
dislikeButton.setI18nLabel("replaymod.gui." + (disliked ? "removedislike" : "dislike"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).onLoad(new Consumer<Consumer<Supplier<GuiReplayEntry>>>() {
|
|
||||||
@Override
|
|
||||||
public void consume(Consumer<Supplier<GuiReplayEntry>> obj) {
|
|
||||||
// Do not load any replays until the user has selected the category they'd like to view
|
|
||||||
}
|
|
||||||
}).setDrawShadow(true).setDrawSlider(true);
|
|
||||||
|
|
||||||
public final GuiButton loadButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
FileInfo fileInfo = list.getSelected().fileInfo;
|
|
||||||
mod.startReplay(fileInfo.getId(), fileInfo.getName(), GuiReplayCenter.this);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).setSize(95, 20).setI18nLabel("replaymod.gui.download").setDisabled();
|
|
||||||
|
|
||||||
public final GuiButton favoriteButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
int replayId = list.getSelected().fileInfo.getId();
|
|
||||||
boolean favorited = favoritedReplays.contains(replayId);
|
|
||||||
apiClient.favFile(replayId, !favorited);
|
|
||||||
reloadFavorited();
|
|
||||||
list.onSelectionChanged();
|
|
||||||
} catch (IOException | ApiException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).setSize(95, 20).setI18nLabel("replaymod.gui.center.favorite").setDisabled();
|
|
||||||
|
|
||||||
public final GuiButton likeButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
int replayId = list.getSelected().fileInfo.getId();
|
|
||||||
boolean liked = likedReplays.contains(replayId);
|
|
||||||
apiClient.rateFile(replayId, liked ? Rating.RatingType.NEUTRAL : Rating.RatingType.LIKE);
|
|
||||||
reloadRated();
|
|
||||||
list.onSelectionChanged();
|
|
||||||
} catch (IOException | ApiException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).setSize(95, 20).setI18nLabel("replaymod.gui.like").setDisabled();
|
|
||||||
|
|
||||||
public final GuiButton dislikeButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
int replayId = list.getSelected().fileInfo.getId();
|
|
||||||
boolean disliked = dislikedReplays.contains(replayId);
|
|
||||||
apiClient.rateFile(replayId, disliked ? Rating.RatingType.NEUTRAL : Rating.RatingType.DISLIKE);
|
|
||||||
reloadRated();
|
|
||||||
list.onSelectionChanged();
|
|
||||||
} catch (IOException | ApiException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).setSize(95, 20).setI18nLabel("replaymod.gui.dislike").setDisabled();
|
|
||||||
|
|
||||||
public final GuiButton logoutButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Futures.addCallback(GuiYesNoPopup.open(GuiReplayCenter.this,
|
|
||||||
new GuiLabel().setI18nText("replaymod.gui.center.logoutcallback").setColor(Colors.BLACK))
|
|
||||||
.setYesI18nLabel("replaymod.gui.logout").setNoI18nLabel("replaymod.gui.cancel")
|
|
||||||
.getFuture(), new FutureCallback<Boolean>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Boolean result) {
|
|
||||||
if (result) {
|
|
||||||
apiClient.logout();
|
|
||||||
getMinecraft().openScreen(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}).setSize(195, 20).setI18nLabel("replaymod.gui.logout");
|
|
||||||
|
|
||||||
public final GuiButton mainMenuButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
getMinecraft().openScreen(null);
|
|
||||||
}
|
|
||||||
}).setSize(195, 20).setI18nLabel("replaymod.gui.mainmenu");
|
|
||||||
|
|
||||||
public final GuiReplayCenterSearch searchPopup;
|
|
||||||
|
|
||||||
public final GuiPanel replayButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
|
||||||
.addElements(null, loadButton, favoriteButton, likeButton, dislikeButton);
|
|
||||||
public final GuiPanel generalButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
|
||||||
.addElements(null, logoutButton, mainMenuButton);
|
|
||||||
public final GuiPanel buttonPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(5))
|
|
||||||
.addElements(null, replayButtonPanel, generalButtonPanel);
|
|
||||||
|
|
||||||
private volatile Set<Integer> favoritedReplays = Collections.emptySet();
|
|
||||||
private volatile Set<Integer> likedReplays = Collections.emptySet();
|
|
||||||
private volatile Set<Integer> dislikedReplays = Collections.emptySet();
|
|
||||||
|
|
||||||
public GuiReplayCenter(ReplayModOnline mod) {
|
|
||||||
this.mod = mod;
|
|
||||||
this.apiClient = mod.getApiClient();
|
|
||||||
this.searchPopup = new GuiReplayCenterSearch(this, apiClient);
|
|
||||||
|
|
||||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.replaycenter"));
|
|
||||||
|
|
||||||
setLayout(new CustomLayout<GuiScreen>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiScreen container, int width, int height) {
|
|
||||||
pos(buttonPanel, width / 2 - width(buttonPanel) / 2, height - 10 - height(buttonPanel));
|
|
||||||
|
|
||||||
pos(list, 0, 50);
|
|
||||||
size(list, width, y(buttonPanel) - 10 - y(list));
|
|
||||||
|
|
||||||
pos(categories, width / 2 - width(categories) / 2, y(list) - 7 - height(categories));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reloadFavorited() {
|
|
||||||
try {
|
|
||||||
favoritedReplays = new HashSet<>(Ints.asList(apiClient.getFavorites()));
|
|
||||||
} catch (IOException | ApiException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reloadRated() {
|
|
||||||
try {
|
|
||||||
Set<Integer> liked = new HashSet<>(), disliked = new HashSet<>();
|
|
||||||
for (FileRating rating : apiClient.getRatedFiles()) {
|
|
||||||
(rating.isRatingPositive() ? liked : disliked).add(rating.getFile());
|
|
||||||
}
|
|
||||||
this.likedReplays = liked;
|
|
||||||
this.dislikedReplays = disliked;
|
|
||||||
} catch (IOException | ApiException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void show(final Pagination pagination) {
|
|
||||||
list.setOffsetY(0);
|
|
||||||
list.onLoad(new Consumer<Consumer<Supplier<GuiReplayEntry>>>() {
|
|
||||||
@Override
|
|
||||||
public void consume(Consumer<Supplier<GuiReplayEntry>> obj) {
|
|
||||||
if (pagination.getLoadedPages() < 0) {
|
|
||||||
pagination.fetchPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
reloadFavorited();
|
|
||||||
reloadRated();
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (final FileInfo fileInfo : pagination.getFiles()) {
|
|
||||||
if (Thread.interrupted()) return;
|
|
||||||
try {
|
|
||||||
// Make sure that to int[] conversion doesn't have to occur in main thread
|
|
||||||
final Image theThumb;
|
|
||||||
if (fileInfo.hasThumbnail()) {
|
|
||||||
theThumb = apiClient.downloadThumbnail(fileInfo.getId());
|
|
||||||
} else {
|
|
||||||
theThumb = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int sortId = i++;
|
|
||||||
final boolean downloaded = mod.hasDownloaded(fileInfo.getId());
|
|
||||||
obj.consume(new Supplier<GuiReplayEntry>() {
|
|
||||||
@Override
|
|
||||||
public GuiReplayEntry get() {
|
|
||||||
return new GuiReplayEntry(fileInfo, theThumb, sortId, downloaded);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.error("Could not load Replay File {}", fileInfo.getId(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).load();
|
|
||||||
|
|
||||||
categories.forEach(IGuiButton.class).setEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GuiReplayCenter getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final GuiImage defaultThumbnail = new GuiImage().setTexture(Utils.DEFAULT_THUMBNAIL);
|
|
||||||
public class GuiReplayEntry extends AbstractGuiContainer<GuiReplayEntry> implements Comparable<GuiReplayEntry> {
|
|
||||||
public final FileInfo fileInfo;
|
|
||||||
public final GuiLabel name = new GuiLabel();
|
|
||||||
public final GuiLabel author = new GuiLabel();
|
|
||||||
public final GuiLabel date = new GuiLabel().setColor(Colors.LIGHT_GRAY);
|
|
||||||
public final GuiLabel server = new GuiLabel().setColor(Colors.LIGHT_GRAY);
|
|
||||||
public final GuiLabel version = new GuiLabel().setColor(Colors.RED);
|
|
||||||
public final GuiLabel category = new GuiLabel().setColor(Colors.GREY);
|
|
||||||
public final GuiPanel stats = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(3));
|
|
||||||
public final GuiLabel favorites = new GuiLabel(stats).setColor(Colors.ORANGE);
|
|
||||||
public final GuiLabel likes = new GuiLabel(stats).setColor(Colors.GREEN);
|
|
||||||
public final GuiLabel dislikes = new GuiLabel(stats).setColor(Colors.RED);
|
|
||||||
public final GuiPanel infoPanel = new GuiPanel(this).setLayout(new CustomLayout<GuiPanel>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiPanel container, int width, int height) {
|
|
||||||
pos(name, 0, 0);
|
|
||||||
pos(author, 0, height(name) + 2);
|
|
||||||
pos(server, 0, y(author) + height(author) + 3);
|
|
||||||
pos(category, 0, y(server) + height(server) + 3);
|
|
||||||
|
|
||||||
pos(date, width - width(date), y(author));
|
|
||||||
pos(version, width - width(version), y(server));
|
|
||||||
pos(stats, width - width(stats), y(category));
|
|
||||||
}
|
|
||||||
}).addElements(null, name, author, date, server, version, category, stats);
|
|
||||||
public final GuiImage thumbnail;
|
|
||||||
public final GuiLabel duration = new GuiLabel();
|
|
||||||
public final GuiPanel durationPanel = new GuiPanel().setBackgroundColor(Colors.HALF_TRANSPARENT)
|
|
||||||
.addElements(null, duration).setLayout(new CustomLayout<GuiPanel>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiPanel container, int width, int height) {
|
|
||||||
pos(duration, 2, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
|
||||||
ReadableDimension dimension = duration.calcMinSize();
|
|
||||||
return new Dimension(dimension.getWidth() + 2, dimension.getHeight() + 2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
public final GuiLabel downloads = new GuiLabel();
|
|
||||||
public final GuiPanel downloadsPanel = new GuiPanel().setBackgroundColor(Colors.HALF_TRANSPARENT)
|
|
||||||
.addElements(null, downloads).setLayout(new CustomLayout<GuiPanel>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiPanel container, int width, int height) {
|
|
||||||
pos(downloads, 2, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
|
||||||
ReadableDimension dimension = downloads.calcMinSize();
|
|
||||||
return new Dimension(dimension.getWidth() + 2, dimension.getHeight() + 2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
private final long dateMillis;
|
|
||||||
private final int sortId;
|
|
||||||
private final boolean downloaded;
|
|
||||||
private final boolean incompatible;
|
|
||||||
|
|
||||||
public GuiReplayEntry(FileInfo fileInfo, Image thumbImage, int sortId, boolean downloaded) {
|
|
||||||
this.fileInfo = fileInfo;
|
|
||||||
this.sortId = sortId;
|
|
||||||
this.downloaded = downloaded;
|
|
||||||
ReplayMetaData metaData = fileInfo.getMetadata();
|
|
||||||
|
|
||||||
name.setText(Formatting.UNDERLINE + Utils.fileNameToReplayName(fileInfo.getName()));
|
|
||||||
author.setI18nText("replaymod.gui.center.author",
|
|
||||||
"" + Formatting.GRAY + Formatting.ITALIC, fileInfo.getOwner());
|
|
||||||
if (StringUtils.isEmpty(metaData.getServerName())) {
|
|
||||||
server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED);
|
|
||||||
} else {
|
|
||||||
server.setText(metaData.getServerName());
|
|
||||||
}
|
|
||||||
incompatible = !ReplayMod.isCompatible(fileInfo.getMetadata().getFileFormatVersion(), -1); // TODO protocol version support on website
|
|
||||||
if (incompatible) {
|
|
||||||
version.setText("Minecraft " + fileInfo.getMetadata().getMcVersion());
|
|
||||||
}
|
|
||||||
dateMillis = metaData.getDate();
|
|
||||||
date.setText(new SimpleDateFormat().format(new Date(dateMillis)));
|
|
||||||
if (thumbImage == null) {
|
|
||||||
thumbnail = new GuiImage(defaultThumbnail);
|
|
||||||
addElements(null, thumbnail);
|
|
||||||
} else {
|
|
||||||
thumbnail = new GuiImage(this).setTexture(thumbImage);
|
|
||||||
}
|
|
||||||
thumbnail.setSize(45 * 16 / 9, 45);
|
|
||||||
duration.setText(Utils.convertSecondsToShortString(metaData.getDuration() / 1000));
|
|
||||||
downloads.setText(fileInfo.getDownloads() + " ⬇");
|
|
||||||
favorites.setText("⭑" + fileInfo.getFavorites());
|
|
||||||
likes.setText("⬆" + fileInfo.getRatings().getPositive());
|
|
||||||
dislikes.setText("⬇" + fileInfo.getRatings().getNegative());
|
|
||||||
category.setText(Formatting.ITALIC + Optional.fromNullable(Category.fromId(fileInfo.getCategory()))
|
|
||||||
.or(Category.MISCELLANEOUS).toNiceString());
|
|
||||||
addElements(null, durationPanel, downloadsPanel);
|
|
||||||
|
|
||||||
setLayout(new CustomLayout<GuiReplayEntry>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiReplayEntry container, int width, int height) {
|
|
||||||
pos(thumbnail, 0, 0);
|
|
||||||
x(durationPanel, width(thumbnail) - width(durationPanel));
|
|
||||||
y(durationPanel, height(thumbnail) - height(durationPanel));
|
|
||||||
x(downloadsPanel, width(thumbnail) - width(downloadsPanel));
|
|
||||||
y(downloadsPanel, height(thumbnail) - height(durationPanel) - height(downloadsPanel));
|
|
||||||
|
|
||||||
pos(infoPanel, width(thumbnail) + 5, 0);
|
|
||||||
size(infoPanel, width - width(thumbnail) - 5, height(thumbnail));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ReadableDimension calcMinSize(GuiContainer<?> container) {
|
|
||||||
return new Dimension(300, thumbnail.getMinSize().getHeight());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GuiReplayEntry getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(GuiReplayEntry o) {
|
|
||||||
return Integer.compare(sortId, o.sortId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
package com.replaymod.online.gui;
|
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.replay.SearchQuery;
|
|
||||||
import com.replaymod.online.api.replay.holders.Category;
|
|
||||||
import com.replaymod.online.api.replay.holders.MinecraftVersion;
|
|
||||||
import com.replaymod.online.api.replay.pagination.SearchPagination;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiTextField;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiToggleButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.advanced.GuiDropdownMenu;
|
|
||||||
import de.johni0702.minecraft.gui.function.Typeable;
|
|
||||||
import de.johni0702.minecraft.gui.layout.GridLayout;
|
|
||||||
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Colors;
|
|
||||||
import de.johni0702.minecraft.gui.utils.lwjgl.ReadablePoint;
|
|
||||||
import net.minecraft.client.resource.language.I18n;
|
|
||||||
|
|
||||||
//#if MC>=11400
|
|
||||||
import com.replaymod.core.versions.MCVer.Keyboard;
|
|
||||||
//#else
|
|
||||||
//$$ import org.lwjgl.input.Keyboard;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class GuiReplayCenterSearch extends AbstractGuiPopup<GuiReplayCenterSearch> implements Typeable {
|
|
||||||
private final GuiReplayCenter replayCenter;
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
public final GuiLabel title = new GuiLabel().setI18nText("replaymod.gui.center.search.filters").setColor(Colors.BLACK);
|
|
||||||
public final GuiTextField name = new GuiTextField().setSize(120, 20).setI18nHint("replaymod.gui.center.search.name");
|
|
||||||
public final GuiTextField server = new GuiTextField().setSize(120, 20).setI18nHint("replaymod.gui.center.search.server");
|
|
||||||
public final GuiDropdownMenu<String> category = new GuiDropdownMenu<String>().setSize(120, 20);
|
|
||||||
public final GuiDropdownMenu<String> version = new GuiDropdownMenu<String>().setSize(120, 20);
|
|
||||||
public final GuiToggleButton<String> gameType = new GuiToggleButton<String>().setSize(120, 20);
|
|
||||||
public final GuiToggleButton<String> sort = new GuiToggleButton<String>().setSize(120, 20);
|
|
||||||
public final GuiButton cancelButton = new GuiButton().setSize(120, 20).onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}).setI18nLabel("replaymod.gui.cancel");
|
|
||||||
public final GuiButton searchButton = new GuiButton().setSize(120, 20).onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
SearchQuery searchQuery = new SearchQuery();
|
|
||||||
searchQuery.singleplayer = new Boolean[]{null,true, false}[gameType.getSelected()];
|
|
||||||
searchQuery.category = category.getSelected() == 0 ? null : category.getSelected() - 1;
|
|
||||||
searchQuery.version = version.getSelected() == 0
|
|
||||||
? null : MinecraftVersion.values()[version.getSelected() - 1].getApiName();
|
|
||||||
searchQuery.name = Strings.emptyToNull(name.getText().trim());
|
|
||||||
searchQuery.server = Strings.emptyToNull(server.getText().trim());
|
|
||||||
searchQuery.order = sort.getSelected() == 0;
|
|
||||||
|
|
||||||
close();
|
|
||||||
replayCenter.show(new SearchPagination(apiClient, searchQuery));
|
|
||||||
}
|
|
||||||
}).setI18nLabel("replaymod.gui.center.top.search");
|
|
||||||
{
|
|
||||||
List<String> categories = new ArrayList<>();
|
|
||||||
categories.add(I18n.translate("replaymod.gui.center.search.category"));
|
|
||||||
for (Category c : Category.values()) {
|
|
||||||
categories.add(c.toNiceString());
|
|
||||||
}
|
|
||||||
category.setValues(categories.toArray(new String[categories.size()]));
|
|
||||||
|
|
||||||
List<String> versions = new ArrayList<>();
|
|
||||||
versions.add(I18n.translate("replaymod.gui.center.search.version"));
|
|
||||||
for (MinecraftVersion v : MinecraftVersion.values()) {
|
|
||||||
versions.add(v.toNiceName());
|
|
||||||
}
|
|
||||||
version.setValues(versions.toArray(new String[versions.size()]));
|
|
||||||
|
|
||||||
gameType.setI18nLabel("replaymod.gui.center.search.gametype")
|
|
||||||
.setValues(I18n.translate("options.particles.all"),
|
|
||||||
I18n.translate("menu.singleplayer"),
|
|
||||||
I18n.translate("menu.multiplayer"));
|
|
||||||
sort.setI18nLabel("replaymod.gui.center.search.order")
|
|
||||||
.setValues(I18n.translate("replaymod.gui.center.search.order.best"),
|
|
||||||
I18n.translate("replaymod.gui.center.search.order.recent"));
|
|
||||||
|
|
||||||
popup.setLayout(new GridLayout().setColumns(3).setSpacingX(5).setSpacingY(5));
|
|
||||||
popup.addElements(null,
|
|
||||||
title, new GuiLabel(), new GuiLabel(),
|
|
||||||
name, category, gameType,
|
|
||||||
server, version, sort,
|
|
||||||
new GuiLabel(), new GuiLabel(), new GuiLabel(),
|
|
||||||
new GuiLabel(), cancelButton, searchButton);
|
|
||||||
|
|
||||||
setBackgroundColor(Colors.DARK_TRANSPARENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GuiReplayCenterSearch(GuiReplayCenter replayCenter, ApiClient apiClient) {
|
|
||||||
super(replayCenter);
|
|
||||||
this.replayCenter = replayCenter;
|
|
||||||
this.apiClient = apiClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void open() {
|
|
||||||
super.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GuiReplayCenterSearch getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean typeKey(ReadablePoint mousePosition, int keyCode, char keyChar, boolean ctrlDown, boolean shiftDown) {
|
|
||||||
if (keyCode == Keyboard.KEY_ESCAPE) {
|
|
||||||
cancelButton.onClick();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package com.replaymod.online.gui;
|
|
||||||
|
|
||||||
import com.replaymod.core.ReplayMod;
|
|
||||||
import com.replaymod.online.ReplayModOnline;
|
|
||||||
import com.replaymod.online.api.ApiClient;
|
|
||||||
import com.replaymod.online.api.ApiException;
|
|
||||||
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
||||||
import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
|
|
||||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
|
||||||
import net.minecraft.util.Formatting;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class GuiReplayDownloading extends AbstractGuiScreen<GuiReplayDownloading> {
|
|
||||||
private final GuiScreen cancelScreen;
|
|
||||||
private final ApiClient apiClient;
|
|
||||||
|
|
||||||
private GuiProgressBar progressBar = new GuiProgressBar(this).setHeight(20);
|
|
||||||
private GuiButton cancelButton = new GuiButton(this).setI18nLabel("gui.cancel").setSize(150, 20).onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
apiClient.cancelDownload();
|
|
||||||
cancelScreen.display();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
public GuiReplayDownloading(GuiScreen cancelScreen, final ReplayModOnline mod,
|
|
||||||
final int replayId, String name) {
|
|
||||||
this.cancelScreen = cancelScreen;
|
|
||||||
this.apiClient = mod.getApiClient();
|
|
||||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.viewer.download.title"));
|
|
||||||
final GuiLabel subTitle = new GuiLabel(this).setI18nText("replaymod.gui.viewer.download.message",
|
|
||||||
Formatting.UNDERLINE + name + Formatting.RESET);
|
|
||||||
setLayout(new CustomLayout<GuiReplayDownloading>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiReplayDownloading container, int width, int height) {
|
|
||||||
width(progressBar, width - 20);
|
|
||||||
pos(progressBar, 10, height - 50);
|
|
||||||
|
|
||||||
pos(cancelButton, width - 5 - 150, height - 5 - 20);
|
|
||||||
|
|
||||||
pos(subTitle, width / 2 - subTitle.getMinSize().getWidth() / 2, 40);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
final File replayFile = mod.getDownloadedFile(replayId);
|
|
||||||
try {
|
|
||||||
apiClient.downloadFile(replayId, replayFile, progressBar::setProgress);
|
|
||||||
if (replayFile.exists()) {
|
|
||||||
ReplayMod.instance.runLater(() -> {
|
|
||||||
try {
|
|
||||||
mod.startReplay(replayId, null, null);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (IOException | ApiException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected GuiReplayDownloading getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
package com.replaymod.online.gui;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
import com.google.common.util.concurrent.Futures;
|
|
||||||
import com.replaymod.core.utils.Utils;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiTextField;
|
|
||||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.HorizontalLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
|
||||||
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Colors;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class GuiSaveModifiedReplay extends GuiScreen {
|
|
||||||
public final File file;
|
|
||||||
public final GuiLabel message = new GuiLabel().setI18nText("replaymod.gui.replaymodified.message");
|
|
||||||
public final GuiTextField name = new GuiTextField().setSize(300, 20).setI18nHint("replaymod.gui.viewer.rename.name");
|
|
||||||
public final GuiButton saveButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String resultName = name.getText().trim().replace("[^a-zA-Z0-9\\.\\- ]", "_");
|
|
||||||
final File resultFile = new File(file.getParentFile(), Utils.replayNameToFileName(resultName));
|
|
||||||
if (resultFile.exists()) {
|
|
||||||
Futures.addCallback(GuiYesNoPopup.open(GuiSaveModifiedReplay.this,
|
|
||||||
new GuiLabel().setI18nText("replaymod.gui.replaymodified.warning1", resultName).setColor(Colors.BLACK),
|
|
||||||
new GuiLabel().setI18nText("replaymod.gui.replaymodified.warning2").setColor(Colors.BLACK))
|
|
||||||
.setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no")
|
|
||||||
.getFuture(), new FutureCallback<Boolean>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(Boolean result) {
|
|
||||||
if (result) {
|
|
||||||
try {
|
|
||||||
FileUtils.forceDelete(resultFile);
|
|
||||||
FileUtils.moveFile(file, resultFile);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
getMinecraft().openScreen(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
FileUtils.moveFile(file, resultFile);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
getMinecraft().openScreen(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).setSize(147, 20).setI18nLabel("replaymod.gui.replaymodified.yes");
|
|
||||||
public final GuiButton deleteButton = new GuiButton().onClick(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
FileUtils.deleteQuietly(file);
|
|
||||||
getMinecraft().openScreen(null);
|
|
||||||
}
|
|
||||||
}).setSize(147, 20).setI18nLabel("replaymod.gui.replaymodified.no");
|
|
||||||
|
|
||||||
public final GuiPanel contentPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(5))
|
|
||||||
.addElements(new VerticalLayout.Data(0.5), message, name,
|
|
||||||
new GuiPanel().setSize(300, 20).setLayout(new HorizontalLayout().setSpacing(6))
|
|
||||||
.addElements(null, saveButton, deleteButton));
|
|
||||||
|
|
||||||
{
|
|
||||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.replaysaving.title"));
|
|
||||||
setLayout(new CustomLayout<GuiScreen>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiScreen container, int width, int height) {
|
|
||||||
pos(contentPanel, width / 2 - width(contentPanel) / 2, height / 2 - height(contentPanel) / 2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,319 +0,0 @@
|
|||||||
package com.replaymod.online.gui;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.FutureCallback;
|
|
||||||
import com.google.common.util.concurrent.Futures;
|
|
||||||
import com.replaymod.core.KeyBindingRegistry;
|
|
||||||
import com.replaymod.core.utils.Patterns;
|
|
||||||
import com.replaymod.core.utils.Utils;
|
|
||||||
import com.replaymod.online.ReplayModOnline;
|
|
||||||
import com.replaymod.online.api.ApiException;
|
|
||||||
import com.replaymod.online.api.replay.FileUploader;
|
|
||||||
import com.replaymod.online.api.replay.holders.Category;
|
|
||||||
import com.replaymod.replaystudio.replay.ReplayFile;
|
|
||||||
import com.replaymod.replaystudio.replay.ReplayMetaData;
|
|
||||||
import com.replaymod.replaystudio.replay.ZipReplayFile;
|
|
||||||
import com.replaymod.replaystudio.studio.ReplayStudio;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiContainer;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiCheckbox;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiImage;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiLabel;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiTextField;
|
|
||||||
import de.johni0702.minecraft.gui.element.GuiTooltip;
|
|
||||||
import de.johni0702.minecraft.gui.element.advanced.GuiDropdownMenu;
|
|
||||||
import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
|
|
||||||
import de.johni0702.minecraft.gui.element.advanced.GuiTextArea;
|
|
||||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.GridLayout;
|
|
||||||
import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
|
||||||
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
|
|
||||||
import de.johni0702.minecraft.gui.popup.GuiYesNoPopup;
|
|
||||||
import de.johni0702.minecraft.gui.utils.Colors;
|
|
||||||
import de.johni0702.minecraft.gui.versions.Image;
|
|
||||||
import net.minecraft.client.resource.language.I18n;
|
|
||||||
import net.minecraft.client.options.KeyBinding;
|
|
||||||
import net.minecraft.util.crash.CrashReport;
|
|
||||||
import net.minecraft.util.crash.CrashException;
|
|
||||||
import org.apache.commons.io.FileUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
//#if MC>=11400
|
|
||||||
//#else
|
|
||||||
//$$ import net.minecraft.client.settings.GameSettings;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static java.util.Arrays.stream;
|
|
||||||
|
|
||||||
public class GuiUploadReplay extends GuiScreen {
|
|
||||||
public final GuiScreen parent;
|
|
||||||
|
|
||||||
public final GuiTextField name = new GuiTextField().setHeight(20).setMaxLength(30)
|
|
||||||
.setI18nHint("replaymod.gui.upload.namehint");
|
|
||||||
public final GuiLabel durationLabel = new GuiLabel();
|
|
||||||
public final GuiCheckbox hideServerIP = new GuiCheckbox();
|
|
||||||
public final GuiDropdownMenu<Category> category = new GuiDropdownMenu<Category>().setHeight(20)
|
|
||||||
.setValues(Category.values()).setToString(v -> I18n.translate("replaymod.category") + ": " + v.toNiceString());
|
|
||||||
public final GuiTextField tags = new GuiTextField().setHeight(20).setMaxLength(30)
|
|
||||||
.setI18nHint("replaymod.gui.upload.tagshint");
|
|
||||||
|
|
||||||
public final GuiTextArea description = new GuiTextArea()
|
|
||||||
.setI18nHint("replaymod.gui.upload.descriptionhint")
|
|
||||||
.setMaxTextWidth(1000).setMaxTextHeight(100).setMaxCharCount(1000);
|
|
||||||
|
|
||||||
public final GuiButton startButton = new GuiButton().setI18nLabel("replaymod.gui.upload.start");
|
|
||||||
public final GuiButton backButton = new GuiButton().setI18nLabel("replaymod.gui.back");
|
|
||||||
|
|
||||||
public final GuiPanel inputPanel = new GuiPanel()
|
|
||||||
.setLayout(new VerticalLayout().setSpacing(5))
|
|
||||||
.addElements(null, name, durationLabel, hideServerIP, category, tags);
|
|
||||||
|
|
||||||
public final GuiImage thumbnail = new GuiImage();
|
|
||||||
public final GuiLabel thumbnailWarning = new GuiLabel().setColor(Colors.RED);
|
|
||||||
|
|
||||||
public final GuiPanel topPanel = new GuiPanel()
|
|
||||||
.setLayout(new GridLayout().setColumns(3).setSpacingX(5))
|
|
||||||
.setLayout(new CustomLayout<GuiPanel>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiPanel container, int width, int height) {
|
|
||||||
pos(inputPanel, 0, 0);
|
|
||||||
width(inputPanel, width / 2 - 4);
|
|
||||||
|
|
||||||
y(thumbnail, y(inputPanel) + height(inputPanel) + 10);
|
|
||||||
width(thumbnail, Math.min(width(inputPanel), (height - y(thumbnail)) * 16 / 9));
|
|
||||||
height(thumbnail, width(thumbnail) * 9 / 16);
|
|
||||||
x(thumbnail, (width / 2 - 4) / 2 - width(thumbnail) / 2);
|
|
||||||
|
|
||||||
pos(thumbnailWarning, x(thumbnail) + 5, y(thumbnail) + 5);
|
|
||||||
size(thumbnailWarning, width(thumbnail) - 10, height(thumbnail) - 10);
|
|
||||||
|
|
||||||
pos(description, width / 2 + 4, 0);
|
|
||||||
size(description, width - x(description), height);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.addElements(null, inputPanel, description, thumbnail, thumbnailWarning);
|
|
||||||
|
|
||||||
public final GuiPanel buttonPanel = new GuiPanel()
|
|
||||||
.setLayout(new GridLayout().setColumns(2).setSpacingX(6))
|
|
||||||
.addElements(null, startButton, backButton);
|
|
||||||
|
|
||||||
{
|
|
||||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.upload.title"));
|
|
||||||
setLayout(new CustomLayout<GuiScreen>() {
|
|
||||||
@Override
|
|
||||||
protected void layout(GuiScreen container, int width, int height) {
|
|
||||||
pos(topPanel, 5, 25);
|
|
||||||
pos(buttonPanel, 5, height - height(buttonPanel) - 5);
|
|
||||||
|
|
||||||
size(topPanel, width - 10, y(buttonPanel) - y(topPanel) - 10);
|
|
||||||
width(buttonPanel, width - 10);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
addElements(null, topPanel, buttonPanel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private final FileUploader uploader;
|
|
||||||
|
|
||||||
public GuiUploadReplay(GuiScreen parent, ReplayModOnline mod, File file) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.uploader = new FileUploader(mod.getApiClient());
|
|
||||||
|
|
||||||
ReplayMetaData metaData;
|
|
||||||
Optional<Image> optThumbnail;
|
|
||||||
|
|
||||||
// Read from replay file
|
|
||||||
try (ReplayFile replayFile = new ZipReplayFile(new ReplayStudio(), file)) {
|
|
||||||
metaData = replayFile.getMetaData();
|
|
||||||
// TODO add a getThumbBytes method to ReplayStudio
|
|
||||||
optThumbnail = Optional.ofNullable(replayFile.get("thumb").orNull()).flatMap(stream -> {
|
|
||||||
try (InputStream in = stream) {
|
|
||||||
int i = 7;
|
|
||||||
while (i > 0) {
|
|
||||||
i -= in.skip(i);
|
|
||||||
}
|
|
||||||
return Optional.of(Image.read(in));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new CrashException(CrashReport.create(e, "Read replay file " + file.getName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply to gui
|
|
||||||
name.setText(Utils.fileNameToReplayName(file.getName()));
|
|
||||||
int secs = metaData.getDuration() / 1000;
|
|
||||||
durationLabel.setI18nText("replaymod.gui.upload.duration", secs / 60, secs % 60);
|
|
||||||
hideServerIP.setEnabled(!metaData.isSingleplayer());
|
|
||||||
hideServerIP.setI18nLabel("replaymod.gui.upload.hideip2", metaData.getServerName());
|
|
||||||
|
|
||||||
if (optThumbnail.isPresent()) {
|
|
||||||
// Thumbnail is preset, just add the thumbnail to the panel
|
|
||||||
thumbnail.setTexture(optThumbnail.get());
|
|
||||||
} else {
|
|
||||||
// Get name of key used for thumbnail creation
|
|
||||||
KeyBindingRegistry registry = mod.getCore().getKeyBindingRegistry();
|
|
||||||
KeyBinding keyBinding = registry.getKeyBindings().get("replaymod.input.thumbnail");
|
|
||||||
//#if MC>=11400
|
|
||||||
String keyName = keyBinding == null ? "???" : keyBinding.getLocalizedName();
|
|
||||||
//#else
|
|
||||||
//$$ String keyName = keyBinding == null ? "???" : GameSettings.getKeyDisplayString(keyBinding.getKeyCode());
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
// No thumbnail, show default thumbnail and hint on how to create one
|
|
||||||
thumbnail.setTexture(Utils.DEFAULT_THUMBNAIL);
|
|
||||||
thumbnailWarning.setI18nText("replaymod.gui.upload.nothumbnail", keyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
backButton.onClick(parent::display);
|
|
||||||
|
|
||||||
startButton.onClick(() -> {
|
|
||||||
GuiProgressPopup popup = new GuiProgressPopup(this);
|
|
||||||
popup.open();
|
|
||||||
|
|
||||||
// Read values
|
|
||||||
String name = GuiUploadReplay.this.name.getText();
|
|
||||||
Category category = GuiUploadReplay.this.category.getSelectedValue();
|
|
||||||
String desc = StringUtils.join(description.getText(), '\n');
|
|
||||||
Set<String> tagSet = stream(tags.getText().split(",")).collect(Collectors.toSet());
|
|
||||||
tagSet.remove(""); // Remove the empty tag (if it exists)
|
|
||||||
|
|
||||||
// Start upload
|
|
||||||
new Thread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
// Check if we need to remove the server address
|
|
||||||
if (hideServerIP.isChecked()) {
|
|
||||||
File tmp = File.createTempFile("replay_hidden_ip", "mcpr");
|
|
||||||
|
|
||||||
// Overide the server name
|
|
||||||
try (ReplayFile replay = new ZipReplayFile(new ReplayStudio(), file)) {
|
|
||||||
ReplayMetaData newMetaData = new ReplayMetaData(metaData);
|
|
||||||
newMetaData.setServerName(null);
|
|
||||||
replay.writeMetaData(null, newMetaData);
|
|
||||||
replay.saveTo(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload modified file
|
|
||||||
uploader.uploadFile(tmp, name, tagSet, category, desc,
|
|
||||||
progress -> popup.progressBar.setProgress(progress.floatValue()));
|
|
||||||
|
|
||||||
FileUtils.deleteQuietly(tmp);
|
|
||||||
} else {
|
|
||||||
// Upload original file
|
|
||||||
uploader.uploadFile(file, name, tagSet, category, desc,
|
|
||||||
progress -> popup.progressBar.setProgress(progress.floatValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
mod.getCore().runLater(popup::close);
|
|
||||||
} catch (FileUploader.CancelledException ignored) {
|
|
||||||
// Cancelled
|
|
||||||
mod.getCore().runLater(popup::close);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Failure
|
|
||||||
e.printStackTrace();
|
|
||||||
|
|
||||||
String message;
|
|
||||||
if (e instanceof ApiException) {
|
|
||||||
message = e.getLocalizedMessage();
|
|
||||||
} else {
|
|
||||||
message = I18n.translate("replaymod.gui.unknownerror");
|
|
||||||
}
|
|
||||||
mod.getCore().runLater(() -> {
|
|
||||||
// Show error popup
|
|
||||||
GuiYesNoPopup errorPopup = GuiYesNoPopup.open(GuiUploadReplay.this,
|
|
||||||
new GuiLabel().setText(message).setColor(Colors.BLACK),
|
|
||||||
new GuiLabel().setI18nText("replaymod.gui.upload.tryagain").setColor(Colors.BLACK))
|
|
||||||
.setYesI18nLabel("gui.yes").setNoI18nLabel("gui.no");
|
|
||||||
Futures.addCallback(errorPopup.getFuture(), new FutureCallback<Boolean>() {
|
|
||||||
@Override
|
|
||||||
public void onSuccess(@Nullable Boolean result) {
|
|
||||||
popup.close();
|
|
||||||
if (result == Boolean.TRUE) {
|
|
||||||
startButton.onClick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
popup.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, "replaymod-file-uploader").start();
|
|
||||||
});
|
|
||||||
|
|
||||||
validateInputs();
|
|
||||||
name.onTextChanged(s -> validateInputs());
|
|
||||||
tags.onTextChanged(s -> validateInputs());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void validateInputs() {
|
|
||||||
if (name.getText().trim().length() < 5 || name.getText().trim().length() > 30) {
|
|
||||||
name.setTextColor(Colors.RED);
|
|
||||||
startButton.setDisabled().setTooltip(new GuiTooltip().setI18nText("replaymod.gui.upload.error.name.length"));
|
|
||||||
} else if (!Patterns.ALPHANUMERIC_SPACE_HYPHEN_UNDERSCORE.matcher(name.getText()).matches()) {
|
|
||||||
name.setTextColor(Colors.RED);
|
|
||||||
startButton.setDisabled().setTooltip(new GuiTooltip().setI18nText("replaymod.gui.upload.error.name"));
|
|
||||||
} else if (!Patterns.ALPHANUMERIC_COMMA.matcher(tags.getText()).matches()) {
|
|
||||||
tags.setTextColor(Colors.RED);
|
|
||||||
startButton.setDisabled().setTooltip(new GuiTooltip().setI18nText("replaymod.gui.upload.error.tags"));
|
|
||||||
} else {
|
|
||||||
name.setTextColor(Colors.WHITE);
|
|
||||||
tags.setTextColor(Colors.WHITE);
|
|
||||||
startButton.setEnabled().setTooltip(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GuiUploadReplay getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class GuiProgressPopup extends AbstractGuiPopup<GuiProgressPopup> {
|
|
||||||
public final GuiProgressBar progressBar = new GuiProgressBar().setSize(400, 20);
|
|
||||||
public final GuiButton cancelButton = new GuiButton().setSize(200, 20).setI18nLabel("replaymod.gui.cancel");
|
|
||||||
|
|
||||||
{
|
|
||||||
setBackgroundColor(Colors.DARK_TRANSPARENT);
|
|
||||||
popup.setLayout(new VerticalLayout().setSpacing(5));
|
|
||||||
popup.addElements(new VerticalLayout.Data(0.5), progressBar, cancelButton);
|
|
||||||
|
|
||||||
cancelButton.onClick(uploader::cancelUploading);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GuiProgressPopup(GuiContainer container) {
|
|
||||||
super(container);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void open() {
|
|
||||||
super.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() {
|
|
||||||
super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected GuiProgressPopup getThis() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
package com.replaymod.online.handler;
|
|
||||||
|
|
||||||
import de.johni0702.minecraft.gui.utils.EventRegistrations;
|
|
||||||
import com.replaymod.online.ReplayModOnline;
|
|
||||||
import com.replaymod.online.gui.GuiLoginPrompt;
|
|
||||||
import com.replaymod.online.gui.GuiReplayCenter;
|
|
||||||
import com.replaymod.online.gui.GuiUploadReplay;
|
|
||||||
import com.replaymod.replay.gui.screen.GuiReplayViewer;
|
|
||||||
import com.replaymod.replay.handler.GuiHandler.InjectedButton;
|
|
||||||
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
|
|
||||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
|
||||||
import net.minecraft.client.gui.screen.TitleScreen;
|
|
||||||
import net.minecraft.client.gui.widget.AbstractButtonWidget;
|
|
||||||
import net.minecraft.client.resource.language.I18n;
|
|
||||||
|
|
||||||
//#if FABRIC>=1
|
|
||||||
import de.johni0702.minecraft.gui.versions.callbacks.InitScreenCallback;
|
|
||||||
import net.minecraft.client.gui.screen.Screen;
|
|
||||||
import java.util.List;
|
|
||||||
//#else
|
|
||||||
//$$ import net.minecraftforge.client.event.GuiScreenEvent;
|
|
||||||
//$$ import net.minecraftforge.eventbus.api.SubscribeEvent;
|
|
||||||
//#endif
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
import static com.replaymod.core.versions.MCVer.*;
|
|
||||||
|
|
||||||
public class GuiHandler extends EventRegistrations {
|
|
||||||
private static final int BUTTON_REPLAY_CENTER = 17890236;
|
|
||||||
|
|
||||||
private final ReplayModOnline mod;
|
|
||||||
|
|
||||||
public GuiHandler(ReplayModOnline mod) {
|
|
||||||
this.mod = mod;
|
|
||||||
}
|
|
||||||
|
|
||||||
//#if FABRIC>=1
|
|
||||||
{ on(InitScreenCallback.EVENT, this::injectIntoMainMenu); }
|
|
||||||
public void injectIntoMainMenu(Screen guiScreen, List<AbstractButtonWidget> buttonList) {
|
|
||||||
//#else
|
|
||||||
//$$ @SubscribeEvent
|
|
||||||
//$$ public void injectIntoMainMenu(GuiScreenEvent.InitGuiEvent event) {
|
|
||||||
//$$ final net.minecraft.client.gui.screen.Screen guiScreen = getGui(event);
|
|
||||||
//#endif
|
|
||||||
if (!(guiScreen instanceof TitleScreen)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
InjectedButton button = new InjectedButton(
|
|
||||||
guiScreen,
|
|
||||||
BUTTON_REPLAY_CENTER,
|
|
||||||
guiScreen.width / 2 + 2,
|
|
||||||
guiScreen.height / 4 + 10 + 4 * 24,
|
|
||||||
98,
|
|
||||||
20,
|
|
||||||
I18n.translate("replaymod.gui.replaycenter"),
|
|
||||||
this::onButton
|
|
||||||
);
|
|
||||||
addButton(guiScreen, button);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#if FABRIC>=1
|
|
||||||
{ on(InitScreenCallback.EVENT, this::injectIntoReplayViewer); }
|
|
||||||
public void injectIntoReplayViewer(Screen vanillaGuiScreen, List<AbstractButtonWidget> buttonList) {
|
|
||||||
//#else
|
|
||||||
//$$ @SubscribeEvent
|
|
||||||
//$$ public void injectIntoReplayViewer(GuiScreenEvent.InitGuiEvent.Post event) {
|
|
||||||
//$$ net.minecraft.client.gui.screen.Screen vanillaGuiScreen = getGui(event);
|
|
||||||
//#endif
|
|
||||||
AbstractGuiScreen guiScreen = GuiScreen.from(vanillaGuiScreen);
|
|
||||||
if (!(guiScreen instanceof GuiReplayViewer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final GuiReplayViewer replayViewer = (GuiReplayViewer) guiScreen;
|
|
||||||
// Inject Upload button
|
|
||||||
if (!replayViewer.uploadButton.getChildren().isEmpty()) return;
|
|
||||||
replayViewer.replaySpecificButtons.add(new de.johni0702.minecraft.gui.element.GuiButton(replayViewer.uploadButton).onClick(() -> {
|
|
||||||
File replayFile = replayViewer.list.getSelected().file;
|
|
||||||
GuiUploadReplay uploadGui = new GuiUploadReplay(replayViewer, mod, replayFile);
|
|
||||||
if (mod.isLoggedIn()) {
|
|
||||||
uploadGui.display();
|
|
||||||
} else {
|
|
||||||
new GuiLoginPrompt(mod.getApiClient(), replayViewer, uploadGui, true);
|
|
||||||
}
|
|
||||||
}).setSize(73, 20).setI18nLabel("replaymod.gui.upload").setDisabled());
|
|
||||||
}
|
|
||||||
|
|
||||||
//#if MC>=11400
|
|
||||||
private void onButton(InjectedButton button) {
|
|
||||||
net.minecraft.client.gui.screen.Screen guiScreen = button.guiScreen;
|
|
||||||
//#else
|
|
||||||
//$$ @SubscribeEvent
|
|
||||||
//$$ public void onButton(GuiScreenEvent.ActionPerformedEvent.Pre event) {
|
|
||||||
//$$ net.minecraft.client.gui.GuiScreen guiScreen = getGui(event);
|
|
||||||
//$$ GuiButton button = getButton(event);
|
|
||||||
//#endif
|
|
||||||
if(!button.active) return;
|
|
||||||
|
|
||||||
if (guiScreen instanceof TitleScreen) {
|
|
||||||
if (button.id == BUTTON_REPLAY_CENTER) {
|
|
||||||
GuiReplayCenter replayCenter = new GuiReplayCenter(mod);
|
|
||||||
if (mod.isLoggedIn()) {
|
|
||||||
replayCenter.display();
|
|
||||||
} else {
|
|
||||||
new GuiLoginPrompt(mod.getApiClient(), GuiScreen.wrap(guiScreen), replayCenter, true).display();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -200,7 +200,7 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
public void run() {
|
public void run() {
|
||||||
new GuiReplaySettings(toMinecraft(), mod.getCore().getSettingsRegistry()).display();
|
new GuiReplaySettings(toMinecraft(), mod.getCore().getSettingsRegistry()).display();
|
||||||
}
|
}
|
||||||
}).setSize(73, 20).setI18nLabel("replaymod.gui.settings");
|
}).setSize(150, 20).setI18nLabel("replaymod.gui.settings");
|
||||||
|
|
||||||
public final GuiButton cancelButton = new GuiButton().onClick(new Runnable() {
|
public final GuiButton cancelButton = new GuiButton().onClick(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@@ -211,13 +211,12 @@ public class GuiReplayViewer extends GuiScreen {
|
|||||||
|
|
||||||
public final List<GuiButton> replaySpecificButtons = new ArrayList<>();
|
public final List<GuiButton> replaySpecificButtons = new ArrayList<>();
|
||||||
{ replaySpecificButtons.addAll(Arrays.asList(loadButton, renameButton, deleteButton)); }
|
{ replaySpecificButtons.addAll(Arrays.asList(loadButton, renameButton, deleteButton)); }
|
||||||
public final GuiPanel uploadButton = new GuiPanel();
|
|
||||||
public final GuiPanel editorButton = new GuiPanel();
|
public final GuiPanel editorButton = new GuiPanel();
|
||||||
|
|
||||||
public final GuiPanel upperButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
public final GuiPanel upperButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
||||||
.addElements(null, loadButton, editorButton, uploadButton);
|
.addElements(null, loadButton, settingsButton);
|
||||||
public final GuiPanel lowerButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
public final GuiPanel lowerButtonPanel = new GuiPanel().setLayout(new HorizontalLayout().setSpacing(5))
|
||||||
.addElements(null, renameButton, deleteButton, settingsButton, cancelButton);
|
.addElements(null, renameButton, deleteButton, editorButton, cancelButton);
|
||||||
public final GuiPanel buttonPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(5))
|
public final GuiPanel buttonPanel = new GuiPanel(this).setLayout(new VerticalLayout().setSpacing(5))
|
||||||
.addElements(null, upperButtonPanel, lowerButtonPanel);
|
.addElements(null, upperButtonPanel, lowerButtonPanel);
|
||||||
|
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ public class GuiHandler extends EventRegistrations {
|
|||||||
BUTTON_REPLAY_VIEWER,
|
BUTTON_REPLAY_VIEWER,
|
||||||
guiScreen.width / 2 - 100,
|
guiScreen.width / 2 - 100,
|
||||||
guiScreen.height / 4 + 10 + 4 * 24,
|
guiScreen.height / 4 + 10 + 4 * 24,
|
||||||
98,
|
200,
|
||||||
20,
|
20,
|
||||||
I18n.translate("replaymod.gui.replayviewer"),
|
I18n.translate("replaymod.gui.replayviewer"),
|
||||||
this::onButton
|
this::onButton
|
||||||
|
|||||||
@@ -49,23 +49,6 @@
|
|||||||
"screenshots": [],
|
"screenshots": [],
|
||||||
"dependencies": []
|
"dependencies": []
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"modid": "replaymod-online",
|
|
||||||
"name": "Replay Mod - Online",
|
|
||||||
"description": "Online Module of the ReplayMod - aka ReplayCenter",
|
|
||||||
"version": "${version}",
|
|
||||||
"mcversion": "${mcversion}",
|
|
||||||
"url": "https://replaymod.com",
|
|
||||||
"updateUrl": "https://replaymod.com/download",
|
|
||||||
"authorList": [
|
|
||||||
"CrushedPixel",
|
|
||||||
"johni0702"
|
|
||||||
],
|
|
||||||
"logoFile": "replaymod_logo.png",
|
|
||||||
"parent": "replaymod",
|
|
||||||
"screenshots": [],
|
|
||||||
"dependencies": ["required-after:replaymod-replay"]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"modid": "replaymod-simplepathing",
|
"modid": "replaymod-simplepathing",
|
||||||
"name": "Replay Mod - Simple Pathing",
|
"name": "Replay Mod - Simple Pathing",
|
||||||
|
|||||||
Reference in New Issue
Block a user