Add online (aka ReplayCenter) module
Add localization extra (formally known as LocalizedResourcePack) Add version checker extra
This commit is contained in:
@@ -2,16 +2,15 @@ package com.replaymod.core;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFutureTask;
|
||||
import com.replaymod.replay.ReplaySender;
|
||||
import eu.crushedpixel.replaymod.api.ApiClient;
|
||||
import eu.crushedpixel.replaymod.chat.ChatMessageHandler;
|
||||
import eu.crushedpixel.replaymod.events.handlers.CrosshairRenderHandler;
|
||||
import eu.crushedpixel.replaymod.events.handlers.GuiEventHandler;
|
||||
import eu.crushedpixel.replaymod.events.handlers.MouseInputHandler;
|
||||
import eu.crushedpixel.replaymod.events.handlers.TickAndRenderListener;
|
||||
import eu.crushedpixel.replaymod.events.handlers.keyboard.KeyInputHandler;
|
||||
import eu.crushedpixel.replaymod.localization.LocalizedResourcePack;
|
||||
import eu.crushedpixel.replaymod.online.authentication.ConfigurationAuthData;
|
||||
import eu.crushedpixel.replaymod.registry.*;
|
||||
import eu.crushedpixel.replaymod.registry.KeybindRegistry;
|
||||
import eu.crushedpixel.replaymod.registry.ReplayFileAppender;
|
||||
import eu.crushedpixel.replaymod.registry.UploadedFileHandler;
|
||||
import eu.crushedpixel.replaymod.renderer.CustomObjectRenderer;
|
||||
import eu.crushedpixel.replaymod.renderer.PathPreviewRenderer;
|
||||
import eu.crushedpixel.replaymod.renderer.SpectatorRenderer;
|
||||
@@ -24,7 +23,6 @@ import eu.crushedpixel.replaymod.utils.TooltipRenderer;
|
||||
import eu.crushedpixel.replaymod.video.rendering.Pipelines;
|
||||
import lombok.Getter;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.settings.GameSettings;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
@@ -99,12 +97,6 @@ public class ReplayMod {
|
||||
@Deprecated
|
||||
public static UploadedFileHandler uploadedFileHandler;
|
||||
@Deprecated
|
||||
public static DownloadedFileHandler downloadedFileHandler;
|
||||
@Deprecated
|
||||
public static FavoritedFileHandler favoritedFileHandler;
|
||||
@Deprecated
|
||||
public static RatedFileHandler ratedFileHandler;
|
||||
@Deprecated
|
||||
public static SpectatorRenderer spectatorRenderer;
|
||||
@Deprecated
|
||||
public static TooltipRenderer tooltipRenderer;
|
||||
@@ -116,16 +108,10 @@ public class ReplayMod {
|
||||
public static SoundHandler soundHandler = new SoundHandler();
|
||||
@Deprecated
|
||||
public static CrosshairRenderHandler crosshairRenderHandler;
|
||||
@Deprecated
|
||||
public static ApiClient apiClient;
|
||||
|
||||
private final KeyBindingRegistry keyBindingRegistry = new KeyBindingRegistry();
|
||||
private final SettingsRegistry settingsRegistry = new SettingsRegistry();
|
||||
|
||||
@Getter
|
||||
@Deprecated
|
||||
private static boolean latestModVersion = true;
|
||||
|
||||
// The instance of your mod that Forge uses.
|
||||
@Instance(MOD_ID)
|
||||
public static ReplayMod instance;
|
||||
@@ -153,27 +139,13 @@ public class ReplayMod {
|
||||
config = new Configuration(event.getSuggestedConfigurationFile());
|
||||
config.load();
|
||||
settingsRegistry.setConfiguration(config);
|
||||
ConfigurationAuthData authData = new ConfigurationAuthData(config);
|
||||
apiClient = new ApiClient(authData);
|
||||
authData.load(apiClient);
|
||||
|
||||
uploadedFileHandler = new UploadedFileHandler(event.getModConfigurationDirectory());
|
||||
|
||||
replaySettings = new ReplaySettings();
|
||||
|
||||
downloadedFileHandler = new DownloadedFileHandler();
|
||||
favoritedFileHandler = new FavoritedFileHandler();
|
||||
ratedFileHandler = new RatedFileHandler();
|
||||
|
||||
replayFileAppender = new ReplayFileAppender();
|
||||
FMLCommonHandler.instance().bus().register(replayFileAppender);
|
||||
|
||||
//check if latest mod version
|
||||
try {
|
||||
latestModVersion = apiClient.isVersionUpToDate(getContainer().getVersion());
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
@@ -215,26 +187,6 @@ public class ReplayMod {
|
||||
|
||||
tooltipRenderer = new TooltipRenderer();
|
||||
|
||||
Thread localizedResourcePackLoader = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<IResourcePack> defaultResourcePacks = mc.defaultResourcePacks;
|
||||
defaultResourcePacks.add(new LocalizedResourcePack());
|
||||
mc.addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mc.refreshResources();
|
||||
}
|
||||
});
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "localizedResourcePackLoader");
|
||||
localizedResourcePackLoader.start();
|
||||
|
||||
if (System.getProperty("replaymod.render.file") != null) {
|
||||
final File file = new File(System.getProperty("replaymod.render.file"));
|
||||
if (!file.exists()) {
|
||||
@@ -382,6 +334,10 @@ public class ReplayMod {
|
||||
}
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return getContainer().getVersion();
|
||||
}
|
||||
|
||||
private void testIfMoeshAndExitMinecraft() {
|
||||
if("currentPlayer".equals("Moesh")) {
|
||||
System.exit(-1);
|
||||
|
||||
117
src/main/java/com/replaymod/extras/LocalizationExtra.java
Normal file
117
src/main/java/com/replaymod/extras/LocalizationExtra.java
Normal file
@@ -0,0 +1,117 @@
|
||||
package com.replaymod.extras;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.online.ReplayModOnline;
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.online.api.ApiException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.data.IMetadataSection;
|
||||
import net.minecraft.client.resources.data.IMetadataSerializer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class LocalizationExtra implements Extra {
|
||||
@Mod.Instance(ReplayModOnline.MOD_ID)
|
||||
private static ReplayModOnline module;
|
||||
|
||||
@Override
|
||||
public void register(ReplayMod mod) throws Exception {
|
||||
final Minecraft mc = mod.getMinecraft();
|
||||
Thread localizedResourcePackLoader = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<IResourcePack> defaultResourcePacks = mc.defaultResourcePacks;
|
||||
defaultResourcePacks.add(new LocalizedResourcePack(module.getApiClient()));
|
||||
mc.addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mc.refreshResources();
|
||||
}
|
||||
});
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "localizedResourcePackLoader");
|
||||
localizedResourcePackLoader.start();
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public static class LocalizedResourcePack implements IResourcePack {
|
||||
private final ApiClient apiClient;
|
||||
private Map<String, String> availableLanguages = new HashMap<>();
|
||||
private boolean websiteAvailable = true;
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(ResourceLocation loc) {
|
||||
if(!loc.getResourcePath().endsWith(".lang")) return null;
|
||||
String langcode = loc.getResourcePath().split("/")[1].split("\\.")[0];
|
||||
if(availableLanguages.containsKey(langcode)) return new ByteArrayInputStream(availableLanguages.get(langcode).getBytes(Charsets.UTF_8));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resourceExists(ResourceLocation loc) {
|
||||
if(!(loc.getResourcePath().endsWith(".lang"))) return false;
|
||||
String langcode = loc.getResourcePath().split("/")[1].split("\\.")[0];
|
||||
if(availableLanguages.containsKey(langcode)) return true;
|
||||
if(!websiteAvailable) return false;
|
||||
try {
|
||||
if (Boolean.parseBoolean(System.getProperty("replaymod.offline", "false"))) {
|
||||
return false;
|
||||
}
|
||||
String lang = apiClient.getTranslation(langcode);
|
||||
String prop = StringEscapeUtils.unescapeHtml4(lang);
|
||||
availableLanguages.put(langcode, prop);
|
||||
return true;
|
||||
} catch (ApiException e) {
|
||||
if (e.getError().getId() != 16) { // This language has not been translated
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch(ConnectException ce) {
|
||||
websiteAvailable = false;
|
||||
ce.printStackTrace();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set getResourceDomains() {
|
||||
return ImmutableSet.of("minecraft", "replaymod");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMetadataSection getPackMetadata(IMetadataSerializer p_135058_1_, String p_135058_2_) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getPackImage() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackName() {
|
||||
return "ReplayModLocalizationResourcePack";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,9 @@ public class ReplayModExtras {
|
||||
PlayerOverview.class,
|
||||
UriSchemeExtra.class,
|
||||
FullBrightness.class,
|
||||
HotkeyButtons.class
|
||||
HotkeyButtons.class,
|
||||
LocalizationExtra.class,
|
||||
VersionChecker.class
|
||||
);
|
||||
|
||||
private Logger logger;
|
||||
|
||||
64
src/main/java/com/replaymod/extras/VersionChecker.java
Normal file
64
src/main/java/com/replaymod/extras/VersionChecker.java
Normal file
@@ -0,0 +1,64 @@
|
||||
package com.replaymod.extras;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.online.ReplayModOnline;
|
||||
import eu.crushedpixel.replaymod.utils.StringUtils;
|
||||
import net.minecraft.client.gui.Gui;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public class VersionChecker implements Extra {
|
||||
@Mod.Instance(ReplayModOnline.MOD_ID)
|
||||
private static ReplayModOnline module;
|
||||
|
||||
@Override
|
||||
public void register(ReplayMod mod) throws Exception {
|
||||
final String currentVersion = mod.getVersion();
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
boolean upToDate = module.getApiClient().isVersionUpToDate(currentVersion);
|
||||
if (!upToDate) {
|
||||
MinecraftForge.EVENT_BUS.register(VersionChecker.this);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, "ReplayMod-VersionChecker").start();
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onDrawScreen(GuiScreenEvent.DrawScreenEvent.Post event) {
|
||||
if (!(event.gui instanceof GuiMainMenu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int width = Math.max(100, event.gui.width / 2 - 100 - 10);
|
||||
|
||||
String[] lines = StringUtils.splitStringInMultipleRows(I18n.format("replaymod.gui.outdated"), width);
|
||||
|
||||
int maxLineWidth = 0;
|
||||
for(String line : lines) {
|
||||
int lineWidth = event.gui.mc.fontRendererObj.getStringWidth(line);
|
||||
if(lineWidth > maxLineWidth) {
|
||||
maxLineWidth = lineWidth;
|
||||
}
|
||||
}
|
||||
|
||||
Gui.drawRect(2, 77, 5 + maxLineWidth + 3, 80 + (lines.length * 10), 0x80FF0000);
|
||||
|
||||
int i = 0;
|
||||
for(String line : lines) {
|
||||
event.gui.mc.fontRendererObj.drawStringWithShadow(line, 5, 80 + (i * 10), Color.WHITE.getRGB());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@ 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 net.minecraftforge.fml.common.Mod;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -10,6 +13,9 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
|
||||
public class UriSchemeExtra implements Extra {
|
||||
@Mod.Instance(ReplayModOnline.MOD_ID)
|
||||
private static ReplayModOnline module;
|
||||
|
||||
private ReplayMod mod;
|
||||
|
||||
@Override
|
||||
@@ -72,17 +78,10 @@ public class UriSchemeExtra implements Extra {
|
||||
}
|
||||
|
||||
private void loadReplay(int id) {
|
||||
// TODO
|
||||
// File file = ReplayMod.downloadedFileHandler.getFileForID(id);
|
||||
// if (file == null) {
|
||||
// FileInfo info = new FileInfo(id, null, null, null, 0, 0, 0, String.valueOf(id), false, 0);
|
||||
// new GuiReplayDownloading(info).display();
|
||||
// } else {
|
||||
// try {
|
||||
// ReplayHandler.startReplay(file);
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
try {
|
||||
module.startReplay(id, "Replay #" + id, GuiScreen.wrap(null));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.online.authentication;
|
||||
package com.replaymod.online;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package eu.crushedpixel.replaymod.online.authentication;
|
||||
package com.replaymod.online;
|
||||
|
||||
import eu.crushedpixel.replaymod.api.ApiClient;
|
||||
import eu.crushedpixel.replaymod.api.AuthData;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.AuthConfirmation;
|
||||
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;
|
||||
|
||||
110
src/main/java/com/replaymod/online/ReplayModOnline.java
Normal file
110
src/main/java/com/replaymod/online/ReplayModOnline.java
Normal file
@@ -0,0 +1,110 @@
|
||||
package com.replaymod.online;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.online.gui.GuiLoginPrompt;
|
||||
import com.replaymod.online.gui.GuiReplayDownloading;
|
||||
import com.replaymod.online.handler.GuiHandler;
|
||||
import com.replaymod.replay.ReplayModReplay;
|
||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
@Mod(modid = ReplayModOnline.MOD_ID, useMetadata = true)
|
||||
public class ReplayModOnline {
|
||||
public static final String MOD_ID = "replaymod-online";
|
||||
|
||||
@Mod.Instance(MOD_ID)
|
||||
public static ReplayModOnline instance;
|
||||
|
||||
@Mod.Instance(ReplayMod.MOD_ID)
|
||||
private static ReplayMod core;
|
||||
|
||||
@Mod.Instance(ReplayModReplay.MOD_ID)
|
||||
private static ReplayModReplay replayModule;
|
||||
|
||||
private Logger logger;
|
||||
|
||||
private File downloadsFolder = new File("replay_downloads");
|
||||
|
||||
private ApiClient apiClient;
|
||||
|
||||
@Mod.EventHandler
|
||||
public void preInit(FMLPreInitializationEvent event) {
|
||||
logger = event.getModLog();
|
||||
|
||||
core.getSettingsRegistry().register(Setting.class);
|
||||
|
||||
Configuration config = new Configuration(event.getSuggestedConfigurationFile());
|
||||
ConfigurationAuthData authData = new ConfigurationAuthData(config);
|
||||
apiClient = new ApiClient(authData);
|
||||
authData.load(apiClient);
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void init(FMLInitializationEvent event) {
|
||||
if (!downloadsFolder.mkdirs()) {
|
||||
logger.warn("Failed to create downloads folder: " + downloadsFolder);
|
||||
}
|
||||
|
||||
new GuiHandler(this).register();
|
||||
}
|
||||
|
||||
@Mod.EventHandler
|
||||
public void postInit(FMLPostInitializationEvent event) {
|
||||
// Initial login prompt
|
||||
if (!core.getSettingsRegistry().get(Setting.SKIP_LOGIN_PROMPT)) {
|
||||
if (!isLoggedIn()) {
|
||||
new GuiLoginPrompt(apiClient, null, null, false).display();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
return downloadsFolder;
|
||||
}
|
||||
|
||||
public File getDownloadedFile(int id) {
|
||||
return new File(downloadsFolder, 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()) {
|
||||
replayModule.startReplay(file);
|
||||
} else {
|
||||
new GuiReplayDownloading(onDownloadCancelled, this, id, name).display();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/main/java/com/replaymod/online/Setting.java
Normal file
15
src/main/java/com/replaymod/online/Setting.java
Normal file
@@ -0,0 +1,15 @@
|
||||
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);
|
||||
|
||||
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,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api;
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
@@ -6,16 +6,18 @@ import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.replay.ReplayModApiMethods;
|
||||
import eu.crushedpixel.replaymod.api.replay.SearchQuery;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.*;
|
||||
import com.replaymod.online.api.replay.ReplayModApiMethods;
|
||||
import com.replaymod.online.api.replay.SearchQuery;
|
||||
import com.replaymod.online.api.replay.holders.*;
|
||||
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
|
||||
import eu.crushedpixel.replaymod.online.authentication.AuthenticationHash;
|
||||
import com.replaymod.online.AuthenticationHash;
|
||||
import eu.crushedpixel.replaymod.utils.Api;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
@@ -125,11 +127,11 @@ public class ApiClient {
|
||||
return SimpleApiClient.invokeUrl(builder.toString());
|
||||
}
|
||||
|
||||
public void downloadThumbnail(int file, File target) throws IOException {
|
||||
public BufferedImage downloadThumbnail(int file) throws IOException {
|
||||
QueryBuilder builder = new QueryBuilder(ReplayModApiMethods.get_thumbnail);
|
||||
builder.put("id", file);
|
||||
URL url = new URL(builder.toString());
|
||||
FileUtils.copyURLToFile(url, target);
|
||||
return ImageIO.read(url);
|
||||
}
|
||||
|
||||
private boolean cancelDownload = false;
|
||||
@@ -1,6 +1,6 @@
|
||||
package eu.crushedpixel.replaymod.api;
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.ApiError;
|
||||
import com.replaymod.online.api.replay.holders.ApiError;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api;
|
||||
package com.replaymod.online.api;
|
||||
|
||||
/**
|
||||
* Represents a set of persistent authentication data.
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api;
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api;
|
||||
package com.replaymod.online.api;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
@@ -1,10 +1,10 @@
|
||||
package eu.crushedpixel.replaymod.api;
|
||||
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 eu.crushedpixel.replaymod.api.replay.holders.ApiError;
|
||||
import com.replaymod.online.api.replay.holders.ApiError;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -1,10 +1,11 @@
|
||||
package eu.crushedpixel.replaymod.api.replay;
|
||||
package com.replaymod.online.api.replay;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.ApiError;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.Category;
|
||||
import eu.crushedpixel.replaymod.gui.online.GuiUploadFile;
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.online.api.replay.holders.ApiError;
|
||||
import com.replaymod.online.api.replay.holders.Category;
|
||||
import com.replaymod.online.gui.GuiUploadFile;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
import java.io.*;
|
||||
@@ -13,9 +14,12 @@ import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.List;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class FileUploader {
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
private final ApiClient apiClient;
|
||||
|
||||
private boolean uploading = false;
|
||||
private long filesize;
|
||||
private long current;
|
||||
@@ -36,7 +40,7 @@ public class FileUploader {
|
||||
if(uploading) throw new RuntimeException("FileUploader is already uploading");
|
||||
uploading = true;
|
||||
|
||||
String postData = "?auth=" + ReplayMod.apiClient.getAuthKey() + "&category=" + category.getId();
|
||||
String postData = "?auth=" + apiClient.getAuthKey() + "&category=" + category.getId();
|
||||
|
||||
if(tags.size() > 0) {
|
||||
postData += "&tags=";
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay;
|
||||
package com.replaymod.online.api.replay;
|
||||
|
||||
public class ReplayModApiMethods {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay;
|
||||
package com.replaymod.online.api.replay;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import de.johni0702.replaystudio.replay.ReplayMetaData;
|
||||
import lombok.AccessLevel;
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
public enum MinecraftVersion {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.holders;
|
||||
package com.replaymod.online.api.replay.holders;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@@ -1,25 +1,26 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.pagination;
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
import com.replaymod.online.ReplayModOnline;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
|
||||
import java.io.File;
|
||||
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<Integer, FileInfo>();
|
||||
private HashMap<Integer, FileInfo> files = new HashMap<>();
|
||||
|
||||
public DownloadedFilePagination() {
|
||||
public DownloadedFilePagination(ReplayModOnline mod) {
|
||||
this.mod = mod;
|
||||
this.page = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> getFiles() {
|
||||
return new ArrayList<FileInfo>(files.values());
|
||||
return new ArrayList<>(files.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -31,19 +32,23 @@ public class DownloadedFilePagination implements Pagination {
|
||||
public boolean fetchPage() {
|
||||
page++;
|
||||
|
||||
HashMap<Integer, File> f = ReplayMod.downloadedFileHandler.getDownloadedFiles();
|
||||
List<Integer> toAdd = new ArrayList<Integer>();
|
||||
for(int i : f.keySet()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
files.keySet().retainAll(f.keySet());
|
||||
|
||||
try {
|
||||
FileInfo[] fis = ReplayMod.apiClient.getFileInfo(toAdd);
|
||||
FileInfo[] fis = mod.getApiClient().getFileInfo(toAdd);
|
||||
if(fis.length < 1) {
|
||||
page--;
|
||||
return false;
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.pagination;
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -9,16 +9,18 @@ import java.util.List;
|
||||
|
||||
public class FavoritedFilePagination implements Pagination {
|
||||
|
||||
private final ApiClient apiClient;
|
||||
private int page;
|
||||
private HashMap<Integer, FileInfo> files = new HashMap<Integer, FileInfo>();
|
||||
private HashMap<Integer, FileInfo> files = new HashMap<>();
|
||||
|
||||
public FavoritedFilePagination() {
|
||||
public FavoritedFilePagination(ApiClient apiClient) {
|
||||
this.apiClient = apiClient;
|
||||
this.page = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> getFiles() {
|
||||
return new ArrayList<FileInfo>(files.values());
|
||||
return new ArrayList<>(files.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -31,8 +33,8 @@ public class FavoritedFilePagination implements Pagination {
|
||||
page++;
|
||||
|
||||
try {
|
||||
List<Integer> f = ReplayMod.favoritedFileHandler.getFavorited();
|
||||
List<Integer> toAdd = new ArrayList<Integer>();
|
||||
int[] f = apiClient.getFavorites();
|
||||
List<Integer> toAdd = new ArrayList<>();
|
||||
for(int i : f) {
|
||||
if(!files.containsKey(i)) {
|
||||
toAdd.add(i);
|
||||
@@ -40,7 +42,7 @@ public class FavoritedFilePagination implements Pagination {
|
||||
}
|
||||
}
|
||||
|
||||
FileInfo[] fis = ReplayMod.apiClient.getFileInfo(toAdd);
|
||||
FileInfo[] fis = apiClient.getFileInfo(toAdd);
|
||||
if(fis.length < 1) {
|
||||
page--;
|
||||
return false;
|
||||
@@ -1,6 +1,6 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.pagination;
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
package eu.crushedpixel.replaymod.api.replay.pagination;
|
||||
package com.replaymod.online.api.replay.pagination;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.replay.SearchQuery;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
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(SearchQuery searchQuery) {
|
||||
public SearchPagination(ApiClient apiClient, SearchQuery searchQuery) {
|
||||
this.apiClient = apiClient;
|
||||
this.page = -1;
|
||||
this.searchQuery = searchQuery;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileInfo> getFiles() {
|
||||
return new ArrayList<FileInfo>(files);
|
||||
return Collections.unmodifiableList(files);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -35,7 +38,7 @@ public class SearchPagination implements Pagination {
|
||||
searchQuery.offset = page;
|
||||
|
||||
try {
|
||||
FileInfo[] fis = ReplayMod.apiClient.searchFiles(searchQuery);
|
||||
FileInfo[] fis = apiClient.searchFiles(searchQuery);
|
||||
if(fis.length < 1) {
|
||||
page--;
|
||||
return false;
|
||||
@@ -1,17 +1,19 @@
|
||||
package eu.crushedpixel.replaymod.gui.online;
|
||||
package com.replaymod.online.gui;
|
||||
|
||||
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 com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.gui.GuiConstants;
|
||||
|
||||
public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
|
||||
|
||||
private final net.minecraft.client.gui.GuiScreen parent, successScreen;
|
||||
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");
|
||||
@@ -34,13 +36,13 @@ public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
switch(ReplayMod.apiClient.login(username.getText(), password.getText())) {
|
||||
switch (apiClient.login(username.getText(), password.getText())) {
|
||||
case SUCCESS:
|
||||
statusLabel.setText("");
|
||||
getMinecraft().addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getMinecraft().displayGuiScreen(successScreen);
|
||||
successScreen.display();
|
||||
}
|
||||
});
|
||||
break;
|
||||
@@ -61,13 +63,13 @@ public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
|
||||
cancelButton.onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getMinecraft().displayGuiScreen(parent);
|
||||
successScreen.display();
|
||||
}
|
||||
});
|
||||
registerButton.onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new GuiRegister(GuiLoginPrompt.this).display();
|
||||
new GuiRegister(apiClient, GuiLoginPrompt.this).display();
|
||||
}
|
||||
});
|
||||
Runnable contentValidation = new Runnable() {
|
||||
@@ -80,8 +82,8 @@ public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
|
||||
password.onTextChanged(contentValidation);
|
||||
}
|
||||
|
||||
public GuiLoginPrompt(net.minecraft.client.gui.GuiScreen parent,
|
||||
net.minecraft.client.gui.GuiScreen successScreen, boolean manuallyTriggered) {
|
||||
public GuiLoginPrompt(ApiClient apiClient, GuiScreen parent, GuiScreen successScreen, boolean manuallyTriggered) {
|
||||
this.apiClient = apiClient;
|
||||
this.parent = parent;
|
||||
this.successScreen = successScreen;
|
||||
|
||||
@@ -114,7 +116,7 @@ public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {
|
||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.login.title"));
|
||||
}
|
||||
|
||||
public net.minecraft.client.gui.GuiScreen getSuccessScreen() {
|
||||
public GuiScreen getSuccessScreen() {
|
||||
return successScreen;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package eu.crushedpixel.replaymod.gui.online;
|
||||
package com.replaymod.online.gui;
|
||||
|
||||
import com.mojang.authlib.exceptions.AuthenticationException;
|
||||
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 com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.ApiException;
|
||||
import eu.crushedpixel.replaymod.gui.GuiConstants;
|
||||
import eu.crushedpixel.replaymod.utils.EmailAddressUtils;
|
||||
import eu.crushedpixel.replaymod.utils.RegexUtils;
|
||||
@@ -80,12 +80,12 @@ public class GuiRegister extends AbstractGuiScreen<GuiRegister> {
|
||||
String username = usernameInput.getText().trim();
|
||||
String mail = mailInput.getText().trim();
|
||||
String password = passwordInput.getText();
|
||||
ReplayMod.apiClient.register(username, mail, password);
|
||||
apiClient.register(username, mail, password);
|
||||
|
||||
getMinecraft().addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getMinecraft().displayGuiScreen(parent.getSuccessScreen());
|
||||
parent.getSuccessScreen().display();
|
||||
}
|
||||
});
|
||||
} catch (ApiException ae) {
|
||||
@@ -147,9 +147,11 @@ public class GuiRegister extends AbstractGuiScreen<GuiRegister> {
|
||||
});
|
||||
}
|
||||
|
||||
private GuiLoginPrompt parent;
|
||||
private final ApiClient apiClient;
|
||||
private final GuiLoginPrompt parent;
|
||||
|
||||
public GuiRegister(GuiLoginPrompt parent) {
|
||||
public GuiRegister(ApiClient apiClient, GuiLoginPrompt parent) {
|
||||
this.apiClient = apiClient;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
456
src/main/java/com/replaymod/online/gui/GuiReplayCenter.java
Normal file
456
src/main/java/com/replaymod/online/gui/GuiReplayCenter.java
Normal file
@@ -0,0 +1,456 @@
|
||||
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.mojang.realmsclient.gui.ChatFormatting;
|
||||
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 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.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.replaystudio.replay.ReplayMetaData;
|
||||
import eu.crushedpixel.replaymod.registry.ResourceHelper;
|
||||
import eu.crushedpixel.replaymod.utils.DurationUtils;
|
||||
import net.minecraftforge.fml.common.FMLLog;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.logging.log4j.core.helpers.Strings;
|
||||
import org.lwjgl.util.Dimension;
|
||||
import org.lwjgl.util.ReadableDimension;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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);
|
||||
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");
|
||||
|
||||
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);
|
||||
|
||||
// Similar for like/dislike buttons
|
||||
likeButton.setEnabled(selected.downloaded);
|
||||
dislikeButton.setEnabled(selected.downloaded);
|
||||
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().displayGuiScreen(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().displayGuiScreen(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 BufferedImage theThumb;
|
||||
if (fileInfo.hasThumbnail()) {
|
||||
BufferedImage buf = apiClient.downloadThumbnail(fileInfo.getId());
|
||||
// This is the same way minecraft calls this method, we cache the result and hand
|
||||
// minecraft a BufferedImage with way simpler logic using the precomputed values
|
||||
final int[] theIntArray = buf.getRGB(0, 0, buf.getWidth(), buf.getHeight(), null, 0, buf.getWidth());
|
||||
theThumb = new BufferedImage(buf.getWidth(), buf.getHeight(), BufferedImage.TYPE_INT_ARGB) {
|
||||
@Override
|
||||
public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset, int scansize) {
|
||||
System.arraycopy(theIntArray, 0, rgbArray, 0, theIntArray.length);
|
||||
return null; // Minecraft doesn't use the return value
|
||||
}
|
||||
};
|
||||
} 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) {
|
||||
FMLLog.getLogger().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(ResourceHelper.getDefaultThumbnail());
|
||||
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 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(stats, width - width(stats), y(category));
|
||||
}
|
||||
}).addElements(null, name, author, date, server, 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;
|
||||
|
||||
public GuiReplayEntry(FileInfo fileInfo, BufferedImage thumbImage, int sortId, boolean downloaded) {
|
||||
this.fileInfo = fileInfo;
|
||||
this.sortId = sortId;
|
||||
this.downloaded = downloaded;
|
||||
ReplayMetaData metaData = fileInfo.getMetadata();
|
||||
|
||||
name.setText(ChatFormatting.UNDERLINE + FilenameUtils.getBaseName(fileInfo.getName()));
|
||||
author.setI18nText("replaymod.gui.center.author",
|
||||
"" + ChatFormatting.GRAY + ChatFormatting.ITALIC, fileInfo.getOwner());
|
||||
if (Strings.isEmpty(metaData.getServerName())) {
|
||||
server.setI18nText("replaymod.gui.iphidden").setColor(Colors.DARK_RED);
|
||||
} else {
|
||||
server.setText(metaData.getServerName());
|
||||
}
|
||||
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(DurationUtils.convertSecondsToShortString(metaData.getDuration() / 1000));
|
||||
downloads.setText(fileInfo.getDownloads() + " ⬇");
|
||||
favorites.setText("⭑" + fileInfo.getFavorites());
|
||||
likes.setText("⬆" + fileInfo.getRatings().getPositive());
|
||||
dislikes.setText("⬇" + fileInfo.getRatings().getNegative());
|
||||
category.setText(ChatFormatting.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 org.lwjgl.util.Dimension(300, thumbnail.getMinSize().getHeight());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiReplayEntry getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(GuiReplayEntry o) {
|
||||
return Integer.compare(sortId, o.sortId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
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.layout.GridLayout;
|
||||
import de.johni0702.minecraft.gui.popup.AbstractGuiPopup;
|
||||
import de.johni0702.minecraft.gui.utils.Colors;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class GuiReplayCenterSearch extends AbstractGuiPopup<GuiReplayCenterSearch> {
|
||||
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.format("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.format("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.format("options.particles.all"),
|
||||
I18n.format("menu.singleplayer"),
|
||||
I18n.format("menu.multiplayer"));
|
||||
sort.setI18nLabel("replaymod.gui.center.search.order")
|
||||
.setValues(I18n.format("replaymod.gui.center.search.order.best"),
|
||||
I18n.format("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;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +1,40 @@
|
||||
package eu.crushedpixel.replaymod.gui.online;
|
||||
package com.replaymod.online.gui;
|
||||
|
||||
import com.mojang.realmsclient.gui.ChatFormatting;
|
||||
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 eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class GuiReplayDownloading extends AbstractGuiScreen<GuiReplayDownloading> implements ProgressUpdateListener {
|
||||
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() {
|
||||
ReplayMod.apiClient.cancelDownload();
|
||||
getMinecraft().displayGuiScreen(new GuiReplayCenter());
|
||||
apiClient.cancelDownload();
|
||||
cancelScreen.display();
|
||||
}
|
||||
});
|
||||
|
||||
public GuiReplayDownloading(final FileInfo fileInfo) {
|
||||
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",
|
||||
ChatFormatting.UNDERLINE + fileInfo.getName() + ChatFormatting.RESET);
|
||||
ChatFormatting.UNDERLINE + name + ChatFormatting.RESET);
|
||||
setLayout(new CustomLayout<GuiReplayDownloading>() {
|
||||
@Override
|
||||
protected void layout(GuiReplayDownloading container, int width, int height) {
|
||||
@@ -42,19 +50,23 @@ public class GuiReplayDownloading extends AbstractGuiScreen<GuiReplayDownloading
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final File replayFile = ReplayMod.downloadedFileHandler.downloadFileForID(fileInfo.getId(), GuiReplayDownloading.this);
|
||||
if(replayFile.exists()) {
|
||||
getMinecraft().addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// TODO
|
||||
// ReplayHandler.startReplay(replayFile);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
final File replayFile = mod.getDownloadedFile(replayId);
|
||||
try {
|
||||
apiClient.downloadFile(replayId, replayFile, GuiReplayDownloading.this);
|
||||
if (replayFile.exists()) {
|
||||
getMinecraft().addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
mod.getReplayModule().startReplay(replayFile);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} catch (IOException | ApiException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
@@ -1,7 +1,7 @@
|
||||
package eu.crushedpixel.replaymod.gui.online;
|
||||
package com.replaymod.online.gui;
|
||||
|
||||
import com.mojang.realmsclient.gui.ChatFormatting;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
import eu.crushedpixel.replaymod.gui.elements.ComposedElement;
|
||||
import eu.crushedpixel.replaymod.gui.elements.GuiAdvancedButton;
|
||||
import eu.crushedpixel.replaymod.gui.elements.GuiDropdown;
|
||||
@@ -113,7 +113,7 @@ public class GuiReplayInstanceChooser extends GuiScreen {
|
||||
cancelButton = new GuiAdvancedButton(0, 0, 100, 20, I18n.format("replaymod.gui.cancel"), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mc.displayGuiScreen(new GuiReplayCenter());
|
||||
// mc.displayGuiScreen(new GuiReplayCenter());
|
||||
}
|
||||
}, null);
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
package eu.crushedpixel.replaymod.gui.online;
|
||||
package com.replaymod.online.gui;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.online.api.ApiClient;
|
||||
import com.replaymod.replay.gui.screen.GuiReplayViewer;
|
||||
import de.johni0702.replaystudio.replay.ReplayFile;
|
||||
import de.johni0702.replaystudio.replay.ReplayMetaData;
|
||||
import de.johni0702.replaystudio.replay.ZipReplayFile;
|
||||
import de.johni0702.replaystudio.studio.ReplayStudio;
|
||||
import eu.crushedpixel.replaymod.api.replay.FileUploader;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.Category;
|
||||
import com.replaymod.online.api.replay.FileUploader;
|
||||
import com.replaymod.online.api.replay.holders.Category;
|
||||
import eu.crushedpixel.replaymod.gui.GuiConstants;
|
||||
import eu.crushedpixel.replaymod.gui.elements.*;
|
||||
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
|
||||
@@ -43,6 +44,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
// TODO: Rewrite using new GUI API
|
||||
public class GuiUploadFile extends GuiScreen implements ProgressUpdateListener {
|
||||
|
||||
private final Minecraft mc = Minecraft.getMinecraft();
|
||||
@@ -73,44 +75,44 @@ public class GuiUploadFile extends GuiScreen implements ProgressUpdateListener {
|
||||
private BufferedImage thumb;
|
||||
private boolean hasThumbnail;
|
||||
|
||||
private FileUploader uploader = new FileUploader();
|
||||
private FileUploader uploader;
|
||||
|
||||
private GuiReplayViewer parent;
|
||||
|
||||
private boolean lockUploadButton = false;
|
||||
|
||||
public GuiUploadFile(File file, GuiReplayViewer parent) {
|
||||
public GuiUploadFile(ApiClient apiClient, File file, GuiReplayViewer parent) {
|
||||
this.parent = parent;
|
||||
|
||||
uploader = new FileUploader(apiClient);
|
||||
|
||||
this.textureResource = new ResourceLocation("upload_thumbs/" + FilenameUtils.getBaseName(file.getAbsolutePath()));
|
||||
dynTex = null;
|
||||
|
||||
boolean correctFile = false;
|
||||
this.replayFile = file;
|
||||
|
||||
if(("." + FilenameUtils.getExtension(file.getAbsolutePath())).equals(".zip")) {
|
||||
ReplayFile archive = null;
|
||||
try {
|
||||
archive = new ZipReplayFile(new ReplayStudio(), file);
|
||||
ReplayFile archive = null;
|
||||
try {
|
||||
archive = new ZipReplayFile(new ReplayStudio(), file);
|
||||
|
||||
metaData = archive.getMetaData();
|
||||
Optional<BufferedImage> img = archive.getThumb();
|
||||
if(img.isPresent()) {
|
||||
thumb = ImageUtils.scaleImage(img.get(), new Dimension(1280, 720));
|
||||
hasThumbnail = true;
|
||||
}
|
||||
|
||||
archive.close();
|
||||
correctFile = true;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (archive != null) {
|
||||
archive.close();
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
metaData = archive.getMetaData();
|
||||
Optional<BufferedImage> img = archive.getThumb();
|
||||
if(img.isPresent()) {
|
||||
thumb = ImageUtils.scaleImage(img.get(), new Dimension(1280, 720));
|
||||
hasThumbnail = true;
|
||||
}
|
||||
|
||||
archive.close();
|
||||
correctFile = true;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (archive != null) {
|
||||
archive.close();
|
||||
}
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
if(!correctFile) {
|
||||
@@ -138,11 +140,6 @@ public class GuiUploadFile extends GuiScreen implements ProgressUpdateListener {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!ReplayMod.apiClient.isLoggedIn()) {
|
||||
mc.displayGuiScreen(new GuiLoginPrompt(parent.toMinecraft(), this, true).toMinecraft());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
|
||||
94
src/main/java/com/replaymod/online/handler/GuiHandler.java
Normal file
94
src/main/java/com/replaymod/online/handler/GuiHandler.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package com.replaymod.online.handler;
|
||||
|
||||
import com.replaymod.online.ReplayModOnline;
|
||||
import com.replaymod.online.gui.GuiLoginPrompt;
|
||||
import com.replaymod.online.gui.GuiReplayCenter;
|
||||
import com.replaymod.online.gui.GuiUploadFile;
|
||||
import com.replaymod.replay.gui.screen.GuiReplayViewer;
|
||||
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
|
||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
||||
import de.johni0702.minecraft.gui.element.GuiElement;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class GuiHandler {
|
||||
private static final int BUTTON_REPLAY_CENTER = 17890236;
|
||||
|
||||
private static final Minecraft mc = Minecraft.getMinecraft();
|
||||
|
||||
private final ReplayModOnline mod;
|
||||
|
||||
public GuiHandler(ReplayModOnline mod) {
|
||||
this.mod = mod;
|
||||
}
|
||||
|
||||
public void register() {
|
||||
FMLCommonHandler.instance().bus().register(this);
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void injectIntoMainMenu(GuiScreenEvent.InitGuiEvent event) {
|
||||
if (!(event.gui instanceof GuiMainMenu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<GuiButton> buttonList = event.buttonList;
|
||||
GuiButton button = new GuiButton(BUTTON_REPLAY_CENTER, event.gui.width / 2 - 100,
|
||||
event.gui.height / 4 + 10 + 4 * 24, I18n.format("replaymod.gui.replaycenter"));
|
||||
buttonList.add(button);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void injectIntoReplayViewer(GuiScreenEvent.InitGuiEvent.Post event) {
|
||||
AbstractGuiScreen guiScreen = GuiScreen.from(event.gui);
|
||||
if (!(guiScreen instanceof GuiReplayViewer)) {
|
||||
return;
|
||||
}
|
||||
final GuiReplayViewer replayViewer = (GuiReplayViewer) guiScreen;
|
||||
// Inject Upload button
|
||||
for (GuiElement element : replayViewer.replayButtonPanel.getChildren()) {
|
||||
if (element instanceof GuiPanel && (((GuiPanel) element).getChildren().isEmpty())) {
|
||||
new de.johni0702.minecraft.gui.element.GuiButton((GuiPanel) element).onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
File replayFile = replayViewer.list.getSelected().file;
|
||||
GuiUploadFile uploadGui = new GuiUploadFile(mod.getApiClient(), replayFile, replayViewer);
|
||||
if (mod.isLoggedIn()) {
|
||||
mc.displayGuiScreen(uploadGui);
|
||||
} else {
|
||||
new GuiLoginPrompt(mod.getApiClient(), replayViewer, GuiScreen.wrap(uploadGui), true);
|
||||
}
|
||||
}
|
||||
}).setSize(73, 20).setI18nLabel("replaymod.gui.upload").setDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onButton(GuiScreenEvent.ActionPerformedEvent.Pre event) {
|
||||
if(!event.button.enabled) return;
|
||||
|
||||
if (event.gui instanceof GuiMainMenu) {
|
||||
if (event.button.id == BUTTON_REPLAY_CENTER) {
|
||||
GuiReplayCenter replayCenter = new GuiReplayCenter(mod);
|
||||
if (mod.isLoggedIn()) {
|
||||
replayCenter.display();
|
||||
} else {
|
||||
new GuiLoginPrompt(mod.getApiClient(), GuiScreen.wrap(event.gui), replayCenter, true).display();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ import com.mojang.realmsclient.gui.ChatFormatting;
|
||||
import com.replaymod.core.gui.GuiReplaySettings;
|
||||
import com.replaymod.replay.ReplayModReplay;
|
||||
import de.johni0702.minecraft.gui.container.AbstractGuiContainer;
|
||||
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
|
||||
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.*;
|
||||
import de.johni0702.minecraft.gui.element.advanced.GuiResourceLoadingList;
|
||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
||||
@@ -49,7 +49,7 @@ import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class GuiReplayViewer extends AbstractGuiScreen<GuiReplayViewer> {
|
||||
public class GuiReplayViewer extends GuiScreen {
|
||||
private final ReplayModReplay mod;
|
||||
|
||||
public final GuiResourceLoadingList<GuiReplayEntry> list = new GuiResourceLoadingList<GuiReplayEntry>(this).onSelectionChanged(new Runnable() {
|
||||
@@ -245,7 +245,7 @@ public class GuiReplayViewer extends AbstractGuiScreen<GuiReplayViewer> {
|
||||
public void run() {
|
||||
getMinecraft().displayGuiScreen(null);
|
||||
}
|
||||
}).setSize(73, 20).setI18nLabel("replaymod.gui.cancel");;
|
||||
}).setSize(73, 20).setI18nLabel("replaymod.gui.cancel");
|
||||
|
||||
public final GuiPanel replayButtonPanel = new GuiPanel().setLayout(new GridLayout().setSpacingX(5).setSpacingY(5)
|
||||
.setColumns(2)).addElements(null, loadButton, new GuiPanel() /* Upload */, renameButton, deleteButton);
|
||||
@@ -260,9 +260,9 @@ public class GuiReplayViewer extends AbstractGuiScreen<GuiReplayViewer> {
|
||||
|
||||
setTitle(new GuiLabel().setI18nText("replaymod.gui.replayviewer"));
|
||||
|
||||
setLayout(new CustomLayout<GuiReplayViewer>() {
|
||||
setLayout(new CustomLayout<GuiScreen>() {
|
||||
@Override
|
||||
protected void layout(GuiReplayViewer container, int width, int height) {
|
||||
protected void layout(GuiScreen container, int width, int height) {
|
||||
pos(buttonPanel, width / 2 - width(buttonPanel) / 2, height - 10 - height(buttonPanel));
|
||||
|
||||
pos(list, 0, 30);
|
||||
@@ -271,11 +271,6 @@ public class GuiReplayViewer extends AbstractGuiScreen<GuiReplayViewer> {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GuiReplayViewer getThis() {
|
||||
return this;
|
||||
}
|
||||
|
||||
private final GuiImage defaultThumbnail = new GuiImage().setTexture(ResourceHelper.getDefaultThumbnail());
|
||||
public class GuiReplayEntry extends AbstractGuiContainer<GuiReplayEntry> implements Comparable<GuiReplayEntry> {
|
||||
public final File file;
|
||||
@@ -349,29 +344,4 @@ public class GuiReplayViewer extends AbstractGuiScreen<GuiReplayViewer> {
|
||||
return Long.compare(o.dateMillis, dateMillis);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Online module
|
||||
// if(uploadButton.isMouseOver() && !uploadButton.enabled && loadButton.enabled) {
|
||||
// if(currentFileUploaded) {
|
||||
// ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.viewer.alreadyuploaded"), this, Color.RED);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private boolean currentFileUploaded = false;
|
||||
//
|
||||
// public void setButtonsEnabled(boolean b) {
|
||||
// loadButton.enabled = b;
|
||||
//
|
||||
// if(b) {
|
||||
// currentFileUploaded = ReplayMod.uploadedFileHandler.isUploaded(replayFileList.get(replayGuiList.selected).first().first());
|
||||
// uploadButton.enabled = !currentFileUploaded;
|
||||
// } else {
|
||||
// uploadButton.enabled = false;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// renameButton.enabled = b;
|
||||
// deleteButton.enabled = b;
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -3,19 +3,15 @@ package eu.crushedpixel.replaymod.events.handlers;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.core.gui.GuiReplaySettings;
|
||||
import eu.crushedpixel.replaymod.gui.GuiConstants;
|
||||
import eu.crushedpixel.replaymod.gui.online.GuiLoginPrompt;
|
||||
import eu.crushedpixel.replaymod.gui.online.GuiReplayCenter;
|
||||
import eu.crushedpixel.replaymod.gui.replayeditor.GuiReplayEditor;
|
||||
import eu.crushedpixel.replaymod.settings.ReplaySettings;
|
||||
import eu.crushedpixel.replaymod.studio.VersionValidator;
|
||||
import eu.crushedpixel.replaymod.utils.MouseUtils;
|
||||
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
|
||||
import eu.crushedpixel.replaymod.utils.StringUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.*;
|
||||
import net.minecraft.client.gui.inventory.GuiInventory;
|
||||
import net.minecraft.client.gui.GuiButton;
|
||||
import net.minecraft.client.gui.GuiMainMenu;
|
||||
import net.minecraft.client.gui.GuiOptions;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraftforge.client.event.GuiOpenEvent;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent.ActionPerformedEvent;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent.DrawScreenEvent;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent.InitGuiEvent;
|
||||
@@ -34,71 +30,16 @@ public class GuiEventHandler {
|
||||
public int replayCount = 0;
|
||||
private GuiButton editorButton;
|
||||
|
||||
@SubscribeEvent
|
||||
public void onGui(GuiOpenEvent event) {
|
||||
if(event.gui instanceof GuiMainMenu) {
|
||||
if(ReplayMod.firstMainMenu) {
|
||||
ReplayMod.firstMainMenu = false;
|
||||
if(!ReplayMod.apiClient.isLoggedIn() && ReplaySettings.AdvancedOptions.disableLoginPrompt.getValue() != Boolean.TRUE) {
|
||||
event.gui = new GuiLoginPrompt(event.gui, event.gui, false).toMinecraft();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
mc.timer.timerSpeed = 1;
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!ReplayMod.apiClient.isLoggedIn()) return;
|
||||
|
||||
if(event.gui instanceof GuiChat || event.gui instanceof GuiInventory) {
|
||||
// TODO
|
||||
// if(ReplayHandler.isInReplay()) {
|
||||
// event.setCanceled(true);
|
||||
// }
|
||||
} else if(event.gui instanceof GuiDisconnected) {
|
||||
// TODO
|
||||
// if(!ReplayHandler.isInReplay() && System.currentTimeMillis() - ReplayHandler.lastExit < 5000) {
|
||||
// event.setCanceled(true);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onDraw(DrawScreenEvent e) {
|
||||
if(e.gui instanceof GuiMainMenu) {
|
||||
e.gui.drawString(mc.fontRendererObj, I18n.format("replaymod.title")+":", 5, 5, Color.WHITE.getRGB());
|
||||
if(ReplayMod.apiClient.isLoggedIn()) {
|
||||
e.gui.drawString(mc.fontRendererObj, I18n.format("replaymod.gui.loggedin").toUpperCase(), 5, 15, DARK_GREEN.getRGB());
|
||||
} else {
|
||||
e.gui.drawString(mc.fontRendererObj, I18n.format("replaymod.gui.loggedout").toUpperCase(), 5, 15, DARK_RED.getRGB());
|
||||
}
|
||||
|
||||
//if version not up to date, display info string
|
||||
if(!ReplayMod.isLatestModVersion()) {
|
||||
int width = Math.max(100, e.gui.width / 2 - 100 - 10);
|
||||
|
||||
String[] lines = StringUtils.splitStringInMultipleRows(I18n.format("replaymod.gui.outdated"), width);
|
||||
|
||||
int maxLineWidth = 0;
|
||||
for(String line : lines) {
|
||||
int lineWidth = mc.fontRendererObj.getStringWidth(line);
|
||||
if(lineWidth > maxLineWidth) {
|
||||
maxLineWidth = lineWidth;
|
||||
}
|
||||
}
|
||||
|
||||
Gui.drawRect(2, 77, 5+maxLineWidth+3, 80+(lines.length * 10), 0x80FF0000);
|
||||
|
||||
int i = 0;
|
||||
for(String line : lines) {
|
||||
mc.fontRendererObj.drawStringWithShadow(line, 5, 80 + (i * 10), Color.WHITE.getRGB());
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// TODO Do we need this?
|
||||
// e.gui.drawString(mc.fontRendererObj, I18n.format("replaymod.title")+":", 5, 5, Color.WHITE.getRGB());
|
||||
// if(ReplayMod.apiClient.isLoggedIn()) {
|
||||
// e.gui.drawString(mc.fontRendererObj, I18n.format("replaymod.gui.loggedin").toUpperCase(), 5, 15, DARK_GREEN.getRGB());
|
||||
// } else {
|
||||
// e.gui.drawString(mc.fontRendererObj, I18n.format("replaymod.gui.loggedout").toUpperCase(), 5, 15, DARK_RED.getRGB());
|
||||
// }
|
||||
|
||||
if(replayCount == 0) {
|
||||
if(editorButton.isMouseOver()) {
|
||||
@@ -141,10 +82,6 @@ public class GuiEventHandler {
|
||||
|
||||
editorButton = re;
|
||||
|
||||
GuiButton rc = new GuiButton(GuiConstants.REPLAY_CENTER_BUTTON_ID, event.gui.width / 2 - 100, i1 + 3 * 24, I18n.format("replaymod.gui.replaycenter"));
|
||||
rc.enabled = true;
|
||||
buttonList.add(rc);
|
||||
|
||||
} else if(event.gui instanceof GuiOptions) {
|
||||
buttonList.add(new GuiButton(GuiConstants.REPLAY_OPTIONS_BUTTON_ID,
|
||||
event.gui.width / 2 - 155, event.gui.height / 6 + 48 - 6 - 24, 310, 20, I18n.format("replaymod.gui.settings.title")));
|
||||
@@ -155,13 +92,7 @@ public class GuiEventHandler {
|
||||
public void onButton(ActionPerformedEvent event) {
|
||||
if(!event.button.enabled) return;
|
||||
if(event.gui instanceof GuiMainMenu) {
|
||||
if(event.button.id == GuiConstants.REPLAY_CENTER_BUTTON_ID) {
|
||||
if(ReplayMod.apiClient.isLoggedIn()) {
|
||||
mc.displayGuiScreen(new GuiReplayCenter());
|
||||
} else {
|
||||
mc.displayGuiScreen(new GuiLoginPrompt(event.gui, new GuiReplayCenter(), true).toMinecraft());
|
||||
}
|
||||
} else if(event.button.id == GuiConstants.REPLAY_EDITOR_BUTTON_ID) {
|
||||
if(event.button.id == GuiConstants.REPLAY_EDITOR_BUTTON_ID) {
|
||||
mc.displayGuiScreen(new GuiReplayEditor());
|
||||
}
|
||||
} else if(event.gui instanceof GuiOptions && event.button.id == GuiConstants.REPLAY_OPTIONS_BUTTON_ID) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package eu.crushedpixel.replaymod.gui.elements;
|
||||
|
||||
import com.mojang.realmsclient.gui.ChatFormatting;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.Category;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
import com.replaymod.online.api.replay.holders.Category;
|
||||
import com.replaymod.online.api.replay.holders.FileInfo;
|
||||
import eu.crushedpixel.replaymod.registry.ResourceHelper;
|
||||
import eu.crushedpixel.replaymod.utils.DurationUtils;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
@@ -1,579 +0,0 @@
|
||||
package eu.crushedpixel.replaymod.gui.online;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.replay.SearchQuery;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.Category;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.MinecraftVersion;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.Rating;
|
||||
import eu.crushedpixel.replaymod.api.replay.pagination.DownloadedFilePagination;
|
||||
import eu.crushedpixel.replaymod.api.replay.pagination.FavoritedFilePagination;
|
||||
import eu.crushedpixel.replaymod.api.replay.pagination.Pagination;
|
||||
import eu.crushedpixel.replaymod.api.replay.pagination.SearchPagination;
|
||||
import eu.crushedpixel.replaymod.gui.GuiConstants;
|
||||
import eu.crushedpixel.replaymod.gui.elements.*;
|
||||
import eu.crushedpixel.replaymod.holders.GuiEntryListStringEntry;
|
||||
import net.minecraft.client.gui.*;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
|
||||
|
||||
private static final SearchQuery recentFileSearchQuery = new SearchQuery(false, null, null, null, null, null,
|
||||
null, null, null, null);
|
||||
private static final SearchQuery bestFileSearchQuery = new SearchQuery(true, null, null, null, null, null,
|
||||
null, null, null, null);
|
||||
private static final int LOGOUT_CALLBACK_ID = 1;
|
||||
private ReplayFileList currentList;
|
||||
private GuiButton loadButton, favButton, likeButton, dislikeButton;
|
||||
private List<GuiButton> replayButtonBar, bottomBar, topBar;
|
||||
|
||||
private GuiToggleButton searchGametypeToggle, searchSortToggle;
|
||||
private GuiDropdown<GuiEntryListStringEntry> searchCategoryDropdown, searchVersionDropdown;
|
||||
private GuiAdvancedTextField searchNameInput, searchServerInput;
|
||||
private GuiButton searchActionButton;
|
||||
|
||||
private Queue<GuiListExtended.IGuiListEntry> loadedReplaysQueue = new ConcurrentLinkedQueue<GuiListExtended.IGuiListEntry>();
|
||||
|
||||
private boolean showSearchFields = false;
|
||||
|
||||
public static GuiYesNo getYesNoGui(GuiYesNoCallback p_152129_0_, int p_152129_2_) {
|
||||
String s1 = I18n.format("replaymod.gui.center.logoutcallback");
|
||||
return new GuiYesNo(p_152129_0_, s1, "", I18n.format("replaymod.gui.logout"),
|
||||
I18n.format("replaymod.gui.cancel"), p_152129_2_);
|
||||
}
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
@Override
|
||||
public void initGui() {
|
||||
Keyboard.enableRepeatEvents(true);
|
||||
|
||||
if(!initialized) {
|
||||
if(!ReplayMod.apiClient.isLoggedIn()) {
|
||||
mc.displayGuiScreen(new GuiLoginPrompt(new GuiMainMenu(), this, true).toMinecraft());
|
||||
}
|
||||
|
||||
//Top Button Bar
|
||||
topBar = new ArrayList<GuiButton>();
|
||||
|
||||
GuiButton recentButton = new GuiButton(GuiConstants.CENTER_RECENT_BUTTON, 20, 30, I18n.format("replaymod.gui.center.top.recent"));
|
||||
topBar.add(recentButton);
|
||||
|
||||
GuiButton bestButton = new GuiButton(GuiConstants.CENTER_BEST_BUTTON, 20, 30, I18n.format("replaymod.gui.center.top.best"));
|
||||
topBar.add(bestButton);
|
||||
|
||||
GuiButton downloadedReplayButton = new GuiButton(GuiConstants.CENTER_DOWNLOADED_REPLAYS_BUTTON, 20, 30, I18n.format("replaymod.gui.center.top.downloaded"));
|
||||
downloadedReplayButton.enabled = ReplayMod.apiClient.isLoggedIn();
|
||||
topBar.add(downloadedReplayButton);
|
||||
|
||||
GuiButton favoritedReplayButton = new GuiButton(GuiConstants.CENTER_FAVORITED_REPLAYS_BUTTON, 20, 30, I18n.format("replaymod.gui.center.top.favorited"));
|
||||
favoritedReplayButton.enabled = ReplayMod.apiClient.isLoggedIn();
|
||||
topBar.add(favoritedReplayButton);
|
||||
|
||||
GuiButton searchButton = new GuiButton(GuiConstants.CENTER_SEARCH_BUTTON, 20, 30, I18n.format("replaymod.gui.center.top.search"));
|
||||
topBar.add(searchButton);
|
||||
|
||||
//Replay specific actions (load, rate, etc)
|
||||
replayButtonBar = new ArrayList<GuiButton>();
|
||||
|
||||
loadButton = new GuiButton(GuiConstants.CENTER_LOAD_REPLAY_BUTTON, 20, 30, I18n.format("replaymod.gui.download"));
|
||||
replayButtonBar.add(loadButton);
|
||||
|
||||
favButton = new GuiButton(GuiConstants.CENTER_FAV_REPLAY_BUTTON, 20, 30, I18n.format("replaymod.gui.center.favorite"));
|
||||
replayButtonBar.add(favButton);
|
||||
|
||||
likeButton = new GuiButton(GuiConstants.CENTER_LIKE_REPLAY_BUTTON, 20, 30, I18n.format("replaymod.gui.like"));
|
||||
replayButtonBar.add(likeButton);
|
||||
|
||||
dislikeButton = new GuiButton(GuiConstants.CENTER_DISLIKE_REPLAY_BUTTON, 20, 30, I18n.format("replaymod.gui.dislike"));
|
||||
replayButtonBar.add(dislikeButton);
|
||||
|
||||
//Bottom Button Bar (dat alliteration)
|
||||
bottomBar = new ArrayList<GuiButton>();
|
||||
|
||||
GuiButton logoutButton = new GuiButton(GuiConstants.CENTER_LOGOUT_BUTTON, 20, 20, I18n.format("replaymod.gui.logout"));
|
||||
bottomBar.add(logoutButton);
|
||||
|
||||
GuiButton managerButton = new GuiButton(GuiConstants.CENTER_MANAGER_BUTTON, 20, 20, I18n.format("replaymod.gui.replayviewer"));
|
||||
bottomBar.add(managerButton);
|
||||
|
||||
GuiButton exitButton = new GuiButton(GuiConstants.CENTER_BACK_BUTTON, 20, 20, I18n.format("replaymod.gui.mainmenu"));
|
||||
bottomBar.add(exitButton);
|
||||
|
||||
showOnlineRecent();
|
||||
disableTopBarButton(GuiConstants.CENTER_RECENT_BUTTON);
|
||||
|
||||
//Search GUI
|
||||
searchActionButton = new GuiButton(GuiConstants.CENTER_SEARCH_ACTION_BUTTON, 20, 20, I18n.format("replaymod.gui.center.top.search"));
|
||||
searchGametypeToggle = new GuiToggleButton(GuiConstants.CENTER_SEARCH_GAMETYPE_TOGGLE, 0, 0, I18n.format("replaymod.gui.center.search.gametype")+": ",
|
||||
new String[]{I18n.format("options.particles.all"), I18n.format("menu.singleplayer"), I18n.format("menu.multiplayer")});
|
||||
searchSortToggle = new GuiToggleButton(GuiConstants.CENTER_SEARCH_ORDER_TOGGLE, 0, 0, I18n.format("replaymod.gui.center.search.order")+": ",
|
||||
new String[]{I18n.format("replaymod.gui.center.search.order.best"), I18n.format("replaymod.gui.center.search.order.recent")});
|
||||
searchCategoryDropdown = new GuiDropdown<GuiEntryListStringEntry>(fontRendererObj, 0, 0, 0, Category.values().length+1);
|
||||
searchVersionDropdown = new GuiDropdown<GuiEntryListStringEntry>(fontRendererObj, 0, 0, 0, 5);
|
||||
searchNameInput = new GuiAdvancedTextField(fontRendererObj, 0, 0, 50, 20);
|
||||
searchServerInput = new GuiAdvancedTextField(fontRendererObj, 0, 0, 50, 20);
|
||||
|
||||
searchNameInput.hint = I18n.format("replaymod.gui.center.search.name");
|
||||
searchServerInput.hint = I18n.format("replaymod.gui.center.search.server");
|
||||
|
||||
searchCategoryDropdown.addElement(new GuiEntryListStringEntry(I18n.format("replaymod.gui.center.search.category")));
|
||||
for(Category c : Category.values()) {
|
||||
searchCategoryDropdown.addElement(new GuiEntryListStringEntry(c.toNiceString()));
|
||||
}
|
||||
|
||||
searchVersionDropdown.addElement(new GuiEntryListStringEntry(I18n.format("replaymod.gui.center.search.version")));
|
||||
for(MinecraftVersion v : MinecraftVersion.values()) {
|
||||
searchVersionDropdown.addElement(new GuiEntryListStringEntry(v.toNiceName()));
|
||||
}
|
||||
}
|
||||
|
||||
int wd = this.width - 40;
|
||||
int sw = wd/3 + 4;
|
||||
|
||||
searchNameInput.xPosition = searchServerInput.xPosition = searchActionButton.xPosition = 20;
|
||||
searchCategoryDropdown.xPosition = searchVersionDropdown.xPosition = 20 + sw;
|
||||
searchGametypeToggle.xPosition = searchSortToggle.xPosition = 20 + 2*sw;
|
||||
|
||||
searchNameInput.width = searchCategoryDropdown.width = searchGametypeToggle.width = searchActionButton.width =
|
||||
searchServerInput.width = searchVersionDropdown.width = searchSortToggle.width = sw-7;
|
||||
|
||||
searchNameInput.yPosition = searchCategoryDropdown.yPosition = searchGametypeToggle.yPosition = 70;
|
||||
searchServerInput.yPosition = searchVersionDropdown.yPosition = searchSortToggle.yPosition = 100;
|
||||
searchActionButton.yPosition = 130;
|
||||
|
||||
if(showSearchFields) {
|
||||
showSearchFields();
|
||||
}
|
||||
|
||||
if(currentList != null) {
|
||||
currentList.setDimensions(this.width, this.height, 50, this.height - 60);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<GuiButton> buttonList = this.buttonList;
|
||||
|
||||
int i = 0;
|
||||
for(GuiButton b : topBar) {
|
||||
int w = this.width - 30;
|
||||
int w2 = w / topBar.size();
|
||||
|
||||
int x = 15 + (w2 * i);
|
||||
b.xPosition = x + 2;
|
||||
b.yPosition = 20;
|
||||
b.width = w2 - 4;
|
||||
|
||||
buttonList.add(b);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for(GuiButton b : replayButtonBar) {
|
||||
int w = this.width - 30;
|
||||
int w2 = w / replayButtonBar.size();
|
||||
|
||||
int x = 15 + (w2 * i);
|
||||
b.xPosition = x + 2;
|
||||
b.yPosition = height - 55;
|
||||
b.width = w2 - 4;
|
||||
|
||||
b.enabled = false;
|
||||
|
||||
buttonList.add(b);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
for(GuiButton b : bottomBar) {
|
||||
int w = this.width - 30;
|
||||
int w2 = w / bottomBar.size();
|
||||
|
||||
int x = 15 + (w2 * i);
|
||||
b.xPosition = x + 2;
|
||||
b.yPosition = height - 30;
|
||||
b.width = w2 - 4;
|
||||
|
||||
buttonList.add(b);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
public void elementSelected(int index) {
|
||||
if(index < 0) {
|
||||
for(GuiButton b : replayButtonBar) {
|
||||
b.enabled = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
GuiReplayListEntry entry = (GuiReplayListEntry)currentList.getListEntry(index);
|
||||
FileInfo info = entry.getFileInfo();
|
||||
if(info != null) {
|
||||
boolean downloaded = ReplayMod.downloadedFileHandler.getFileForID(info.getId()) != null;
|
||||
loadButton.displayString = downloaded ? I18n.format("replaymod.gui.load") : I18n.format("replaymod.gui.download");
|
||||
loadButton.enabled = true;
|
||||
|
||||
boolean favorited = ReplayMod.favoritedFileHandler.isFavorited(info.getId());
|
||||
favButton.displayString = favorited ? I18n.format("replaymod.gui.center.unfavorite") : I18n.format("replaymod.gui.center.favorite");
|
||||
//if not downloaded, disable favorising
|
||||
favButton.enabled = favorited || downloaded;
|
||||
|
||||
likeButton.enabled = dislikeButton.enabled = downloaded;
|
||||
Rating.RatingType rating = ReplayMod.ratedFileHandler.getRating(info.getId());
|
||||
|
||||
likeButton.displayString = I18n.format("replaymod.gui.like");
|
||||
dislikeButton.displayString = I18n.format("replaymod.gui.dislike");
|
||||
|
||||
if(rating == Rating.RatingType.LIKE) {
|
||||
likeButton.displayString = I18n.format("replaymod.gui.removelike");
|
||||
} else if(rating == Rating.RatingType.DISLIKE) {
|
||||
dislikeButton.displayString = I18n.format("replaymod.gui.removedislike");
|
||||
}
|
||||
|
||||
} else {
|
||||
for(GuiButton b : replayButtonBar) {
|
||||
b.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void disableTopBarButton(int id) {
|
||||
for(GuiButton b : topBar) {
|
||||
b.enabled = b.id != id;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void actionPerformed(GuiButton button) throws java.io.IOException {
|
||||
if(!button.enabled) return;
|
||||
if(button.id == GuiConstants.CENTER_BACK_BUTTON) {
|
||||
mc.displayGuiScreen(new GuiMainMenu());
|
||||
} else if(button.id == GuiConstants.CENTER_LOGOUT_BUTTON) {
|
||||
mc.displayGuiScreen(getYesNoGui(this, LOGOUT_CALLBACK_ID));
|
||||
} else if(button.id == GuiConstants.CENTER_MANAGER_BUTTON) {
|
||||
// TODO
|
||||
// mc.displayGuiScreen(new GuiReplayViewer(mod));
|
||||
} else if(button.id == GuiConstants.CENTER_RECENT_BUTTON) {
|
||||
disableTopBarButton(button.id);
|
||||
showOnlineRecent();
|
||||
} else if(button.id == GuiConstants.CENTER_BEST_BUTTON) {
|
||||
disableTopBarButton(button.id);
|
||||
showOnlineBest();
|
||||
} else if(button.id == GuiConstants.CENTER_DOWNLOADED_REPLAYS_BUTTON) {
|
||||
disableTopBarButton(button.id);
|
||||
showDownloadedFiles();
|
||||
} else if(button.id == GuiConstants.CENTER_FAVORITED_REPLAYS_BUTTON) {
|
||||
disableTopBarButton(button.id);
|
||||
showFavoritedFiles();
|
||||
} else if(button.id == GuiConstants.CENTER_SEARCH_BUTTON) {
|
||||
disableTopBarButton(button.id);
|
||||
showReplaySearch();
|
||||
} else if(button.id == GuiConstants.CENTER_LOAD_REPLAY_BUTTON) {
|
||||
GuiReplayListEntry entry = (GuiReplayListEntry)currentList.getListEntry(currentList.selected);
|
||||
FileInfo info = entry.getFileInfo();
|
||||
if(info != null) {
|
||||
File f = ReplayMod.downloadedFileHandler.getFileForID(info.getId());
|
||||
if(f == null) {
|
||||
new GuiReplayDownloading(info).display();
|
||||
} else {
|
||||
mc.displayGuiScreen(new GuiReplayInstanceChooser(info, f));
|
||||
}
|
||||
}
|
||||
} else if(button.id == GuiConstants.CENTER_FAV_REPLAY_BUTTON) {
|
||||
GuiReplayListEntry entry = (GuiReplayListEntry)currentList.getListEntry(currentList.selected);
|
||||
FileInfo info = entry.getFileInfo();
|
||||
if(info != null) {
|
||||
boolean favorited = ReplayMod.favoritedFileHandler.isFavorited(info.getId());
|
||||
try {
|
||||
if(favorited) ReplayMod.favoritedFileHandler.removeFromFavorites(info.getId());
|
||||
else ReplayMod.favoritedFileHandler.addToFavorites(info.getId());
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
elementSelected(currentList.selected);
|
||||
}
|
||||
} else if(button.id == GuiConstants.CENTER_LIKE_REPLAY_BUTTON) {
|
||||
GuiReplayListEntry entry = (GuiReplayListEntry)currentList.getListEntry(currentList.selected);
|
||||
FileInfo info = entry.getFileInfo();
|
||||
if(info != null) {
|
||||
try {
|
||||
if(ReplayMod.ratedFileHandler.getRating(info.getId()) == Rating.RatingType.LIKE) {
|
||||
ReplayMod.ratedFileHandler.rateFile(info.getId(), Rating.RatingType.NEUTRAL);
|
||||
} else {
|
||||
ReplayMod.ratedFileHandler.rateFile(info.getId(), Rating.RatingType.LIKE);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
elementSelected(currentList.selected);
|
||||
}
|
||||
} else if(button.id == GuiConstants.CENTER_DISLIKE_REPLAY_BUTTON) {
|
||||
GuiReplayListEntry entry = (GuiReplayListEntry)currentList.getListEntry(currentList.selected);
|
||||
FileInfo info = entry.getFileInfo();
|
||||
if(info != null) {
|
||||
try {
|
||||
if(ReplayMod.ratedFileHandler.getRating(info.getId()) == Rating.RatingType.DISLIKE) {
|
||||
ReplayMod.ratedFileHandler.rateFile(info.getId(), Rating.RatingType.NEUTRAL);
|
||||
} else {
|
||||
ReplayMod.ratedFileHandler.rateFile(info.getId(), Rating.RatingType.DISLIKE);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
elementSelected(currentList.selected);
|
||||
}
|
||||
}
|
||||
|
||||
//the search action button
|
||||
else if(button.id == GuiConstants.CENTER_SEARCH_ACTION_BUTTON) {
|
||||
SearchQuery searchQuery = new SearchQuery();
|
||||
|
||||
Boolean gameType = null;
|
||||
if(searchGametypeToggle.getValue() > 0) {
|
||||
gameType = searchGametypeToggle.getValue() == 1;
|
||||
}
|
||||
searchQuery.singleplayer = gameType;
|
||||
|
||||
Integer category = null;
|
||||
if(searchCategoryDropdown.getSelectionIndex() > 0) {
|
||||
category = searchCategoryDropdown.getSelectionIndex()-1;
|
||||
}
|
||||
searchQuery.category = category;
|
||||
|
||||
String mcversion = null;
|
||||
if(searchVersionDropdown.getSelectionIndex() > 0) {
|
||||
mcversion = MinecraftVersion.values()[searchVersionDropdown.getSelectionIndex()-1].getApiName();
|
||||
}
|
||||
searchQuery.version = mcversion;
|
||||
|
||||
if(searchNameInput.getText().trim().length() > 0) {
|
||||
searchQuery.name = searchNameInput.getText().trim();
|
||||
}
|
||||
|
||||
if(searchServerInput.getText().trim().length() > 0) {
|
||||
searchQuery.server = searchServerInput.getText().trim();
|
||||
}
|
||||
|
||||
searchQuery.order = searchSortToggle.getValue() == 0;
|
||||
|
||||
SearchPagination searchPagination = new SearchPagination(searchQuery);
|
||||
showReplaySearch(searchPagination);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void confirmClicked(boolean result, int id) {
|
||||
if(id == LOGOUT_CALLBACK_ID) {
|
||||
if(result) {
|
||||
mc.addScheduledTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ReplayMod.apiClient.logout();
|
||||
mc.displayGuiScreen(new GuiMainMenu());
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mc.displayGuiScreen(this);
|
||||
elementSelected(currentList.selected);
|
||||
initGui();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
|
||||
this.drawDefaultBackground();
|
||||
if(currentList != null) {
|
||||
currentList.drawScreen(mouseX, mouseY, partialTicks);
|
||||
}
|
||||
|
||||
super.drawScreen(mouseX, mouseY, partialTicks);
|
||||
|
||||
if(((favButton.isMouseOver() && !favButton.enabled) || (likeButton.isMouseOver() && !likeButton.enabled)
|
||||
|| (dislikeButton.isMouseOver() && !dislikeButton.enabled )) && (currentList != null && currentList.selected != -1)) {
|
||||
ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.center.downloadrequired"), this, Color.RED);
|
||||
}
|
||||
|
||||
this.drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.replaycenter"), this.width / 2, 5, Color.WHITE.getRGB());
|
||||
|
||||
//search fields
|
||||
if(showSearchFields) {
|
||||
this.drawString(fontRendererObj, I18n.format("replaymod.gui.center.search.filters"), searchActionButton.xPosition, 50, Color.WHITE.getRGB());
|
||||
searchActionButton.drawButton(mc, mouseX, mouseY);
|
||||
searchGametypeToggle.drawButton(mc, mouseX, mouseY);
|
||||
searchSortToggle.drawButton(mc, mouseX, mouseY);
|
||||
searchVersionDropdown.drawTextBox();
|
||||
searchCategoryDropdown.drawTextBox();
|
||||
searchNameInput.drawTextBox();
|
||||
searchServerInput.drawTextBox();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMouseInput() throws IOException {
|
||||
super.handleMouseInput();
|
||||
if(currentList != null) {
|
||||
this.currentList.handleMouseInput();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
if(currentList != null) {
|
||||
this.currentList.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
|
||||
if(showSearchFields) {
|
||||
if(!searchCategoryDropdown.mouseClickedResult(mouseX, mouseY))
|
||||
searchVersionDropdown.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
searchNameInput.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
searchServerInput.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateScreen() {
|
||||
if(showSearchFields) {
|
||||
searchNameInput.updateCursorCounter();
|
||||
searchServerInput.updateCursorCounter();
|
||||
}
|
||||
while (!loadedReplaysQueue.isEmpty()) {
|
||||
GuiListExtended.IGuiListEntry entry = loadedReplaysQueue.poll();
|
||||
if (entry instanceof GuiLoadingListEntry) {
|
||||
currentList.removeEntry(entry);
|
||||
} else {
|
||||
currentList.addEntry(currentList.getEntries().size() - 1, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
if(showSearchFields) {
|
||||
searchNameInput.textboxKeyTyped(typedChar, keyCode);
|
||||
searchServerInput.textboxKeyTyped(typedChar, keyCode);
|
||||
}
|
||||
|
||||
super.keyTyped(typedChar, keyCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void mouseReleased(int mouseX, int mouseY, int state) {
|
||||
super.mouseReleased(mouseX, mouseY, state);
|
||||
if(currentList != null) {
|
||||
this.currentList.mouseReleased(mouseX, mouseY, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGuiClosed() {
|
||||
Keyboard.enableRepeatEvents(false);
|
||||
}
|
||||
|
||||
private Thread currentListLoader;
|
||||
|
||||
private void cancelCurrentListLoader() {
|
||||
if(currentListLoader != null && currentListLoader.isAlive()) {
|
||||
currentListLoader.interrupt();
|
||||
try {
|
||||
currentListLoader.join();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
loadedReplaysQueue.clear();
|
||||
}
|
||||
|
||||
public void show(final Pagination pagination) {
|
||||
cancelCurrentListLoader();
|
||||
|
||||
hideSearchFields();
|
||||
elementSelected(-1);
|
||||
currentList = new ReplayFileList(mc, width, height, 50, height - 60, this);
|
||||
final GuiLoadingListEntry loadingListEntry = new GuiLoadingListEntry();
|
||||
currentList.addEntry(loadingListEntry);
|
||||
|
||||
currentListLoader = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(pagination.getLoadedPages() < 0) {
|
||||
pagination.fetchPage();
|
||||
}
|
||||
|
||||
for(FileInfo i : pagination.getFiles()) {
|
||||
if(Thread.interrupted()) break;
|
||||
try {
|
||||
File tmp = null;
|
||||
if(i.hasThumbnail()) {
|
||||
tmp = File.createTempFile("thumb_online_" + i.getId(), "jpg");
|
||||
ReplayMod.apiClient.downloadThumbnail(i.getId(), tmp);
|
||||
}
|
||||
final GuiReplayListEntry entry = new GuiReplayListEntry(currentList, i, tmp);
|
||||
loadedReplaysQueue.offer(entry);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
loadedReplaysQueue.add(loadingListEntry);
|
||||
}
|
||||
}, "replaymod-list-loader");
|
||||
currentListLoader.start();
|
||||
}
|
||||
|
||||
public void showOnlineRecent() {
|
||||
show(new SearchPagination(recentFileSearchQuery));
|
||||
}
|
||||
|
||||
public void showOnlineBest() {
|
||||
show(new SearchPagination(bestFileSearchQuery));
|
||||
}
|
||||
|
||||
public void showDownloadedFiles() {
|
||||
show(new DownloadedFilePagination());
|
||||
}
|
||||
|
||||
public void showFavoritedFiles() {
|
||||
show(new FavoritedFilePagination());
|
||||
}
|
||||
|
||||
public void showReplaySearch() {
|
||||
cancelCurrentListLoader();
|
||||
currentList = null;
|
||||
showSearchFields();
|
||||
}
|
||||
|
||||
public void showReplaySearch(final SearchPagination searchPagination) {
|
||||
disableTopBarButton(-1);
|
||||
show(searchPagination);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void showSearchFields() {
|
||||
showSearchFields = true;
|
||||
buttonList.add(searchActionButton);
|
||||
buttonList.add(searchGametypeToggle);
|
||||
buttonList.add(searchSortToggle);
|
||||
}
|
||||
|
||||
private void hideSearchFields() {
|
||||
showSearchFields = false;
|
||||
buttonList.remove(searchActionButton);
|
||||
buttonList.remove(searchGametypeToggle);
|
||||
buttonList.remove(searchSortToggle);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package eu.crushedpixel.replaymod.gui.online;
|
||||
|
||||
import eu.crushedpixel.replaymod.gui.elements.GuiReplayListExtended;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
public class ReplayFileList extends GuiReplayListExtended {
|
||||
|
||||
private GuiReplayCenter parent;
|
||||
|
||||
public ReplayFileList(Minecraft mcIn, int p_i45010_2_, int p_i45010_3_,
|
||||
int p_i45010_4_, int p_i45010_5_, GuiReplayCenter parent) {
|
||||
super(mcIn, p_i45010_2_, p_i45010_3_, p_i45010_4_, p_i45010_5_, 50);
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void elementClicked(int slotIndex, boolean isDoubleClick, int mouseX, int mouseY) {
|
||||
super.elementClicked(slotIndex, isDoubleClick, mouseX, mouseY);
|
||||
parent.elementSelected(slotIndex);
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package eu.crushedpixel.replaymod.localization;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.ApiException;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.data.IMetadataSection;
|
||||
import net.minecraft.client.resources.data.IMetadataSerializer;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class LocalizedResourcePack implements IResourcePack {
|
||||
|
||||
private Map<String, String> availableLanguages = new HashMap<String, String>();
|
||||
private boolean websiteAvailable = true;
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream(ResourceLocation loc) {
|
||||
if(!loc.getResourcePath().endsWith(".lang")) return null;
|
||||
String langcode = loc.getResourcePath().split("/")[1].split("\\.")[0];
|
||||
if(availableLanguages.containsKey(langcode)) return new ByteArrayInputStream(availableLanguages.get(langcode).getBytes(Charsets.UTF_8));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean resourceExists(ResourceLocation loc) {
|
||||
if(!(loc.getResourcePath().endsWith(".lang"))) return false;
|
||||
String langcode = loc.getResourcePath().split("/")[1].split("\\.")[0];
|
||||
if(availableLanguages.containsKey(langcode)) return true;
|
||||
if(!websiteAvailable) return false;
|
||||
try {
|
||||
if (Boolean.parseBoolean(System.getProperty("replaymod.offline", "false"))) {
|
||||
return false;
|
||||
}
|
||||
String lang = ReplayMod.apiClient.getTranslation(langcode);
|
||||
String prop = StringEscapeUtils.unescapeHtml4(lang);
|
||||
availableLanguages.put(langcode, prop);
|
||||
return true;
|
||||
} catch (ApiException e) {
|
||||
if (e.getError().getId() != 16) { // This language has not been translated
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch(ConnectException ce) {
|
||||
websiteAvailable = false;
|
||||
ce.printStackTrace();
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set getResourceDomains() {
|
||||
return ImmutableSet.of("minecraft", "replaymod");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IMetadataSection getPackMetadata(IMetadataSerializer p_135058_1_, String p_135058_2_) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getPackImage() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackName() {
|
||||
return "ReplayModLocalizationResourcePack";
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package eu.crushedpixel.replaymod.registry;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
|
||||
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class DownloadedFileHandler {
|
||||
|
||||
private HashMap<Integer, File> downloadedFiles = new HashMap<Integer, File>();
|
||||
|
||||
private File downloadFolder;
|
||||
|
||||
public DownloadedFileHandler() {
|
||||
try {
|
||||
downloadFolder = ReplayFileIO.getReplayDownloadFolder();
|
||||
|
||||
for(File f : FileUtils.listFiles(downloadFolder, new String[]{"mcpr"}, false)) {
|
||||
try {
|
||||
int id = Integer.parseInt(FilenameUtils.getBaseName(f.getAbsolutePath()));
|
||||
downloadedFiles.put(id, f);
|
||||
} catch(NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private File generateFileForID(int id) {
|
||||
return new File(downloadFolder, id+ ".zip");
|
||||
}
|
||||
|
||||
public void addToIndex(int id) {
|
||||
try {
|
||||
File f = generateFileForID(id);
|
||||
if(f.exists()) downloadedFiles.put(id, f);
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public File getFileForID(int id) {
|
||||
return downloadedFiles.get(id);
|
||||
}
|
||||
|
||||
public File downloadFileForID(int id, ProgressUpdateListener progressUpdateListener) {
|
||||
File f = getFileForID(id);
|
||||
if(f != null) return f;
|
||||
|
||||
f = generateFileForID(id);
|
||||
|
||||
try {
|
||||
ReplayMod.apiClient.downloadFile(id, f, progressUpdateListener);
|
||||
if(f.exists()) {
|
||||
addToIndex(id);
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public HashMap<Integer, File> getDownloadedFiles() {
|
||||
return downloadedFiles;
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package eu.crushedpixel.replaymod.registry;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.ApiException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FavoritedFileHandler {
|
||||
|
||||
private List<Integer> favorited = new ArrayList<Integer>();
|
||||
|
||||
boolean retrieved = false;
|
||||
|
||||
public FavoritedFileHandler() {
|
||||
reloadFavorites();
|
||||
}
|
||||
|
||||
public List<Integer> getFavorited() { return favorited; }
|
||||
|
||||
public boolean isFavorited(int id) {
|
||||
return favorited.contains(id);
|
||||
}
|
||||
|
||||
public void addToFavorites(Integer id) throws IOException, ApiException {
|
||||
ReplayMod.apiClient.favFile(id, true);
|
||||
favorited.remove(id);
|
||||
favorited.add(id);
|
||||
}
|
||||
|
||||
public void removeFromFavorites(Integer id) throws IOException, ApiException {
|
||||
ReplayMod.apiClient.favFile(id, false);
|
||||
favorited.remove(id);
|
||||
}
|
||||
|
||||
public void reloadFavorites() {
|
||||
if(ReplayMod.apiClient.isLoggedIn()) {
|
||||
try {
|
||||
int[] ids = ReplayMod.apiClient.getFavorites();
|
||||
favorited = new ArrayList<Integer>(Ints.asList(ids));
|
||||
retrieved = true;
|
||||
} catch(Exception e) {
|
||||
retrieved = false;
|
||||
favorited = new ArrayList<Integer>();
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
retrieved = false;
|
||||
favorited = new ArrayList<Integer>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package eu.crushedpixel.replaymod.registry;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import eu.crushedpixel.replaymod.api.ApiException;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.FileRating;
|
||||
import eu.crushedpixel.replaymod.api.replay.holders.Rating;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class RatedFileHandler {
|
||||
|
||||
private HashMap<Integer, Boolean> rated = new HashMap<Integer, Boolean>();
|
||||
|
||||
boolean retrieved = false;
|
||||
|
||||
public RatedFileHandler() {
|
||||
reloadRatings();
|
||||
}
|
||||
|
||||
public Rating.RatingType getRating(int id) {
|
||||
return Rating.RatingType.fromBoolean(rated.get(id));
|
||||
}
|
||||
|
||||
public void rateFile(int id, Rating.RatingType type) throws IOException, ApiException {
|
||||
ReplayMod.apiClient.rateFile(id, type);
|
||||
if(type == Rating.RatingType.LIKE || type == Rating.RatingType.DISLIKE) {
|
||||
rated.put(id, type == Rating.RatingType.LIKE);
|
||||
} else {
|
||||
rated.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void reloadRatings() {
|
||||
if(ReplayMod.apiClient.isLoggedIn()) {
|
||||
try {
|
||||
FileRating[] ratings = ReplayMod.apiClient.getRatedFiles();
|
||||
rated = new HashMap<Integer, Boolean>();
|
||||
|
||||
for(FileRating fr : ratings) {
|
||||
rated.put(fr.getFile(), fr.isRatingPositive());
|
||||
}
|
||||
|
||||
retrieved = true;
|
||||
} catch(Exception e) {
|
||||
retrieved = false;
|
||||
rated = new HashMap<Integer, Boolean>();
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
retrieved = false;
|
||||
rated = new HashMap<Integer, Boolean>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,6 +49,23 @@
|
||||
"screenshots": [],
|
||||
"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-extras",
|
||||
"name": "Replay Mod - Extras",
|
||||
|
||||
Reference in New Issue
Block a user