Split mod into core, recording, replay, render[todo], paths[todo] and extras[wip] modules

Move everything to com.replaymod package
Add KeyBindingRegistry and SettingsRegistry
Recreate settings GUI with new GUI API and dynamically from SettingsRegistry
Use ReplayFile from ReplayStudio
ReplayHandler is now object oriented
Add GuiOverlay, GuiSlider and GuiTexturedButton to GUI API
Rewrite both overlays to use new GUI API
Fix size capping in vertical and horizontal layout
Allow CustomLayouts to have parents
Fix tooltip rendering when close to screen border
Allow changing of columns in GridLayout
This commit is contained in:
johni0702
2015-10-03 17:36:03 +02:00
parent 8bd051eb27
commit f925d56ca2
141 changed files with 6294 additions and 5582 deletions

View File

@@ -1,449 +0,0 @@
package eu.crushedpixel.replaymod;
import com.google.common.util.concurrent.ListenableFutureTask;
import eu.crushedpixel.replaymod.api.ApiClient;
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
import eu.crushedpixel.replaymod.chat.ChatMessageHandler;
import eu.crushedpixel.replaymod.events.handlers.*;
import eu.crushedpixel.replaymod.events.handlers.keyboard.KeyInputHandler;
import eu.crushedpixel.replaymod.gui.online.GuiReplayDownloading;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.holders.KeyframeSet;
import eu.crushedpixel.replaymod.localization.LocalizedResourcePack;
import eu.crushedpixel.replaymod.online.authentication.ConfigurationAuthData;
import eu.crushedpixel.replaymod.online.urischeme.UriScheme;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import eu.crushedpixel.replaymod.registry.*;
import eu.crushedpixel.replaymod.renderer.CustomObjectRenderer;
import eu.crushedpixel.replaymod.renderer.InvisibilityRender;
import eu.crushedpixel.replaymod.renderer.PathPreviewRenderer;
import eu.crushedpixel.replaymod.renderer.SpectatorRenderer;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplayProcess;
import eu.crushedpixel.replaymod.replay.ReplaySender;
import eu.crushedpixel.replaymod.settings.EncodingPreset;
import eu.crushedpixel.replaymod.settings.RenderOptions;
import eu.crushedpixel.replaymod.settings.ReplaySettings;
import eu.crushedpixel.replaymod.sound.SoundHandler;
import eu.crushedpixel.replaymod.timer.ReplayTimer;
import eu.crushedpixel.replaymod.utils.OpenGLUtils;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
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.renderer.entity.RenderPlayer;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.crash.CrashReport;
import net.minecraft.crash.CrashReportCategory;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.Loader;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.Mod.Instance;
import net.minecraftforge.fml.common.ModContainer;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import static org.apache.commons.io.FileUtils.forceDelete;
import static org.apache.commons.io.FileUtils.listFiles;
@Mod(modid = ReplayMod.MODID, useMetadata = true)
public class ReplayMod {
public static ModContainer getContainer() {
return Loader.instance().getIndexedModList().get(MODID);
}
@Getter(lazy = true)
private static final String minecraftVersion = parseMinecraftVersion();
private static String parseMinecraftVersion() {
CrashReport crashReport = new CrashReport("", new Throwable());
@SuppressWarnings("unchecked")
List<CrashReportCategory.Entry> list = crashReport.getCategory().children;
for (CrashReportCategory.Entry entry : list) {
if ("Minecraft Version".equals(entry.getKey())) {
return entry.getValue();
}
}
return "Unknown";
}
public static final String MODID = "replaymod";
private static final Minecraft mc = Minecraft.getMinecraft();
public static GuiEventHandler guiEventHandler;
public static GuiReplayOverlay overlay;
public static ReplaySettings replaySettings;
public static Configuration config;
public static boolean firstMainMenu = true;
public static RecordingHandler recordingHandler;
public static ChatMessageHandler chatMessageHandler = new ChatMessageHandler();
public static KeyInputHandler keyInputHandler = new KeyInputHandler();
public static MouseInputHandler mouseInputHandler = new MouseInputHandler();
public static ReplaySender replaySender;
public static int TP_DISTANCE_LIMIT = 128;
public static ReplayFileAppender replayFileAppender;
public static UploadedFileHandler uploadedFileHandler;
public static DownloadedFileHandler downloadedFileHandler;
public static FavoritedFileHandler favoritedFileHandler;
public static RatedFileHandler ratedFileHandler;
public static SpectatorRenderer spectatorRenderer;
public static TooltipRenderer tooltipRenderer;
public static PathPreviewRenderer pathPreviewRenderer;
public static CustomObjectRenderer customObjectRenderer;
public static SoundHandler soundHandler = new SoundHandler();
public static CrosshairRenderHandler crosshairRenderHandler;
public static ApiClient apiClient;
@Getter
private static boolean latestModVersion = true;
// The instance of your mod that Forge uses.
@Instance(value = "ReplayModID")
public static ReplayMod instance;
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
try {
UriScheme uriScheme = UriScheme.create();
if (uriScheme == null) {
throw new UnsupportedOperationException("OS not supported.");
}
uriScheme.install();
} catch (Exception e) {
System.err.println("Failed to install UriScheme handler:");
e.printStackTrace();
}
// Initialize the static OpenGL info field from the minecraft main thread
// Unfortunately lwjgl uses static methods so we have to make use of magic init calls as well
OpenGLUtils.init();
config = new Configuration(event.getSuggestedConfigurationFile());
config.load();
ConfigurationAuthData authData = new ConfigurationAuthData(config);
apiClient = new ApiClient(authData);
authData.load(apiClient);
uploadedFileHandler = new UploadedFileHandler(event.getModConfigurationDirectory());
replaySettings = new ReplaySettings();
replaySettings.readValues();
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
public void init(FMLInitializationEvent event) {
mc.timer = new ReplayTimer();
overlay = new GuiReplayOverlay();
FMLCommonHandler.instance().bus().register(new ConnectionEventHandler());
MinecraftForge.EVENT_BUS.register(guiEventHandler = new GuiEventHandler());
FMLCommonHandler.instance().bus().register(keyInputHandler);
FMLCommonHandler.instance().bus().register(mouseInputHandler);
MinecraftForge.EVENT_BUS.register(mouseInputHandler);
recordingHandler = new RecordingHandler();
FMLCommonHandler.instance().bus().register(recordingHandler);
MinecraftForge.EVENT_BUS.register(recordingHandler);
}
@EventHandler
public void postInit(FMLPostInitializationEvent event) throws IOException {
if(!FMLClientHandler.instance().hasOptifine())
GameSettings.Options.RENDER_DISTANCE.setValueMax(64f);
overlay.register();
TickAndRenderListener tarl = new TickAndRenderListener();
FMLCommonHandler.instance().bus().register(tarl);
MinecraftForge.EVENT_BUS.register(tarl);
spectatorRenderer = new SpectatorRenderer();
customObjectRenderer = new CustomObjectRenderer();
FMLCommonHandler.instance().bus().register(customObjectRenderer);
MinecraftForge.EVENT_BUS.register(customObjectRenderer);
pathPreviewRenderer = new PathPreviewRenderer();
FMLCommonHandler.instance().bus().register(pathPreviewRenderer);
MinecraftForge.EVENT_BUS.register(pathPreviewRenderer);
crosshairRenderHandler = new CrosshairRenderHandler();
FMLCommonHandler.instance().bus().register(crosshairRenderHandler);
MinecraftForge.EVENT_BUS.register(crosshairRenderHandler);
KeybindRegistry.initialize();
tooltipRenderer = new TooltipRenderer();
@SuppressWarnings("unchecked")
Map<String, RenderPlayer> skinMap = mc.getRenderManager().skinMap;
skinMap.put("default", new InvisibilityRender(mc.getRenderManager()));
skinMap.put("slim", new InvisibilityRender(mc.getRenderManager(), true));
//clean up replay_recordings folder
removeTmcprFiles();
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()) {
throw new IOException("File \"" + file.getPath() + "\" not found.");
}
final String path = System.getProperty("replaymod.render.path");
String type = System.getProperty("replaymod.render.type");
String bitrate = System.getProperty("replaymod.render.bitrate");
String fps = System.getProperty("replaymod.render.fps");
String waitForChunks = System.getProperty("replaymod.render.waitforchunks");
String linearMovement = System.getProperty("replaymod.render.linearmovement");
String skyColor = System.getProperty("replaymod.render.skycolor");
String width = System.getProperty("replaymod.render.width");
String height = System.getProperty("replaymod.render.height");
String exportCommand = System.getProperty("replaymod.render.exportcommand");
String exportCommandArgs = System.getProperty("replaymod.render.exportcommandargs");
final RenderOptions options = new RenderOptions();
if (bitrate != null) {
options.setBitrate(bitrate);
}
if (fps != null) {
options.setFps(Integer.parseInt(fps));
}
if (waitForChunks != null) {
options.setWaitForChunks(Boolean.parseBoolean(waitForChunks));
}
if (linearMovement != null) {
options.setLinearMovement(Boolean.parseBoolean(linearMovement));
}
if (skyColor != null) {
if (skyColor.startsWith("0x")) {
options.setSkyColor(Integer.parseInt(skyColor.substring(2), 16));
} else {
options.setSkyColor(Integer.parseInt(skyColor));
}
}
if (width != null) {
options.setWidth(Integer.parseInt(width));
}
if (height != null) {
options.setHeight(Integer.parseInt(height));
}
if (exportCommand != null) {
options.setExportCommand(exportCommand);
}
if (exportCommandArgs != null) {
options.setExportCommandArgs(exportCommandArgs);
} else {
options.setExportCommandArgs(EncodingPreset.MP4DEFAULT.getCommandLineArgs());
}
options.setOutputFile(new File(String.valueOf(System.currentTimeMillis())));
Pipelines.Preset pipelinePreset = Pipelines.Preset.DEFAULT;
if (type != null) {
String[] parts = type.split(":");
type = parts[0].toUpperCase();
if ("NORMAL".equals(type) || "DEFAULT".equals(type)) {
pipelinePreset = Pipelines.Preset.DEFAULT;
} else if ("STEREO".equals(type) || "STEREOSCOPIC".equals(type)) {
pipelinePreset = Pipelines.Preset.STEREOSCOPIC;
} else if ("CUBIC".equals(type)) {
if (parts.length < 2) {
throw new IllegalArgumentException("Cubic renderer requires boolean for whether it's stable.");
}
pipelinePreset = Pipelines.Preset.CUBIC;
} else if ("EQUIRECTANGULAR".equals(type)) {
if (parts.length < 2) {
throw new IllegalArgumentException("Equirectangular renderer requires boolean for whether it's stable.");
}
pipelinePreset = Pipelines.Preset.EQUIRECTANGULAR;
} else {
throw new IllegalArgumentException("Unknown type: " + parts[0]);
}
}
options.setMode(pipelinePreset);
@SuppressWarnings("unchecked")
Queue<ListenableFutureTask> tasks = mc.scheduledTasks;
synchronized (mc.scheduledTasks) {
tasks.add(ListenableFutureTask.create(new Runnable() {
@Override
public void run() {
String renderDistance = System.getProperty("replaymod.render.mc.renderdistance");
String clouds = System.getProperty("replaymod.render.mc.clouds");
if (renderDistance != null) {
mc.gameSettings.renderDistanceChunks = Integer.parseInt(renderDistance);
}
if (clouds != null) {
mc.gameSettings.clouds = Boolean.parseBoolean(clouds);
}
System.out.println("Loading replay...");
ReplayHandler.startReplay(file, false);
int index = 0;
if (path != null) {
for (KeyframeSet set : ReplayHandler.getKeyframeRepository()) {
if (set.getName().equals(path)) {
break;
}
index++;
}
if (index >= ReplayHandler.getKeyframeRepository().length) {
throw new IllegalArgumentException("No path named \"" + path + "\".");
}
} else if (ReplayHandler.getKeyframeRepository().length == 0) {
throw new IllegalArgumentException("Replay file has no paths defined.");
}
ReplayHandler.useKeyframePresetFromRepository(index);
System.out.println("Rendering started...");
try {
ReplayProcess.startReplayProcess(options, true);
} catch (Throwable t) {
t.printStackTrace();
FMLCommonHandler.instance().exitJava(1, false);
}
if (mc.hasCrashed) {
System.out.println(mc.crashReporter.getCompleteReport());
}
System.out.println("Rendering done. Shutting down...");
mc.shutdown();
}
}, null));
}
testIfMoeshAndExitMinecraft();
}
new Thread(new Runnable() {
@Override
public void run() {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(UriScheme.PROCESS_PORT);
while (!Thread.interrupted()) {
Socket clientSocket = serverSocket.accept();
try {
InputStream inputStream = clientSocket.getInputStream();
String replayId = IOUtils.toString(inputStream);
final int id = Integer.parseInt(replayId);
mc.addScheduledTask(new Runnable() {
@Override
public void run() {
loadOnlineReplay(id);
}
});
} catch (Exception e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(clientSocket);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(serverSocket);
}
}
}, "UriSchemeHandler").start();
String replayId = System.getenv("replaymod.uri.replayid");
if (replayId != null) {
final int id = Integer.parseInt(replayId);
@SuppressWarnings("unchecked")
Queue<ListenableFutureTask> tasks = mc.scheduledTasks;
synchronized (mc.scheduledTasks) {
tasks.add(ListenableFutureTask.create(new Runnable() {
@Override
public void run() {
loadOnlineReplay(id);
}
}, null));
}
}
}
private void loadOnlineReplay(int id) {
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();
}
}
}
private void testIfMoeshAndExitMinecraft() {
if("currentPlayer".equals("Moesh")) {
System.exit(-1);
}
}
private void removeTmcprFiles() {
try {
File folder = ReplayFileIO.getReplayFolder();
for (File file : listFiles(folder, new String[]{ReplayFile.TEMP_FILE_EXTENSION.substring(1)}, false)) {
forceDelete(file);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -5,7 +5,7 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.mojang.authlib.exceptions.AuthenticationException;
import eu.crushedpixel.replaymod.ReplayMod;
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.*;

View File

@@ -1,26 +1,26 @@
package eu.crushedpixel.replaymod.api;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.IOException;
public class GsonApiClient {
private static final JsonParser parser = new JsonParser();
public static JsonElement invoke(QueryBuilder query) throws IOException, ApiException {
String apiResult = SimpleApiClient.invoke(query);
return wrapWithJson(apiResult);
}
public static JsonElement invokeJson(String url) throws IOException, ApiException {
String apiResult = StringEscapeUtils.unescapeHtml4(SimpleApiClient.invokeUrl(url).replace("&#34;", "\\\""));
return wrapWithJson(apiResult);
}
private static JsonElement wrapWithJson(String apiResult) {
return parser.parse(apiResult);
}
}
package eu.crushedpixel.replaymod.api;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.IOException;
public class GsonApiClient {
private static final JsonParser parser = new JsonParser();
public static JsonElement invoke(QueryBuilder query) throws IOException, ApiException {
String apiResult = SimpleApiClient.invoke(query);
return wrapWithJson(apiResult);
}
public static JsonElement invokeJson(String url) throws IOException, ApiException {
String apiResult = StringEscapeUtils.unescapeHtml4(SimpleApiClient.invokeUrl(url).replace("&#34;", "\\\""));
return wrapWithJson(apiResult);
}
private static JsonElement wrapWithJson(String apiResult) {
return parser.parse(apiResult);
}
}

View File

@@ -1,123 +1,123 @@
package eu.crushedpixel.replaymod.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 org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class SimpleApiClient {
private static final JsonParser jsonParser = new JsonParser();
private static final Gson gson = new Gson();
/**
* Returns a Json String from the given QueryBuilder
*
* @param query The QueryBuilder to use
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invoke(QueryBuilder query) throws IOException, ApiException {
return invokeImpl(query.toString());
}
/**
* Returns a Json String from the given URL
*
* @param url The URL to parse the Json from
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invokeUrl(String url) throws IOException, ApiException {
return invokeImpl(url);
}
/**
* Returns a Json String from the API
*
* @param method The apiMethod to be called
* @param paramMap The parameters to apply
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invoke(String method, Map<String, Object> paramMap) throws IOException, ApiException {
return invokeImpl(method, paramMap);
}
/**
* Returns a Json String from the API
*
* @param method The apiMethod to be called
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invoke(String method) throws IOException, ApiException {
return invokeImpl(method, null);
}
private static String invokeImpl(String urlString) throws IOException, ApiException {
// read response
String responseContent = null;
InputStream is = null;
HttpURLConnection httpUrlConnection = null;
try {
URL url = new URL(urlString);
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setRequestMethod("GET");
// give it 15 seconds to respond
httpUrlConnection.setReadTimeout(15 * 1000);
httpUrlConnection.connect();
int responseCode = httpUrlConnection.getResponseCode();
if(responseCode != 200) {
is = httpUrlConnection.getErrorStream();
if(is != null) {
responseContent = IOUtils.toString(is, "UTF-8");
} else {
responseContent = "";
}
try {
JsonObject response = jsonParser.parse(responseContent).getAsJsonObject();
throw new ApiException(gson.fromJson(response, ApiError.class));
} catch(JsonParseException e) {
throw new ApiException(responseContent);
}
}
is = httpUrlConnection.getInputStream();
responseContent = IOUtils.toString(is, "UTF-8");
} finally {
if(is != null) {
is.close();
}
if(httpUrlConnection != null) {
httpUrlConnection.disconnect();
}
}
return responseContent;
}
private static String invokeImpl(String method, Map<String, Object> paramMap) throws IOException, ApiException {
QueryBuilder queryBuilder = new QueryBuilder(method);
queryBuilder.put(paramMap);
return invokeImpl(queryBuilder.toString());
}
}
package eu.crushedpixel.replaymod.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 org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
public class SimpleApiClient {
private static final JsonParser jsonParser = new JsonParser();
private static final Gson gson = new Gson();
/**
* Returns a Json String from the given QueryBuilder
*
* @param query The QueryBuilder to use
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invoke(QueryBuilder query) throws IOException, ApiException {
return invokeImpl(query.toString());
}
/**
* Returns a Json String from the given URL
*
* @param url The URL to parse the Json from
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invokeUrl(String url) throws IOException, ApiException {
return invokeImpl(url);
}
/**
* Returns a Json String from the API
*
* @param method The apiMethod to be called
* @param paramMap The parameters to apply
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invoke(String method, Map<String, Object> paramMap) throws IOException, ApiException {
return invokeImpl(method, paramMap);
}
/**
* Returns a Json String from the API
*
* @param method The apiMethod to be called
* @return A Json String from the API
* @throws IOException
* @throws ApiException
*/
public static String invoke(String method) throws IOException, ApiException {
return invokeImpl(method, null);
}
private static String invokeImpl(String urlString) throws IOException, ApiException {
// read response
String responseContent = null;
InputStream is = null;
HttpURLConnection httpUrlConnection = null;
try {
URL url = new URL(urlString);
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setRequestMethod("GET");
// give it 15 seconds to respond
httpUrlConnection.setReadTimeout(15 * 1000);
httpUrlConnection.connect();
int responseCode = httpUrlConnection.getResponseCode();
if(responseCode != 200) {
is = httpUrlConnection.getErrorStream();
if(is != null) {
responseContent = IOUtils.toString(is, "UTF-8");
} else {
responseContent = "";
}
try {
JsonObject response = jsonParser.parse(responseContent).getAsJsonObject();
throw new ApiException(gson.fromJson(response, ApiError.class));
} catch(JsonParseException e) {
throw new ApiException(responseContent);
}
}
is = httpUrlConnection.getInputStream();
responseContent = IOUtils.toString(is, "UTF-8");
} finally {
if(is != null) {
is.close();
}
if(httpUrlConnection != null) {
httpUrlConnection.disconnect();
}
}
return responseContent;
}
private static String invokeImpl(String method, Map<String, Object> paramMap) throws IOException, ApiException {
QueryBuilder queryBuilder = new QueryBuilder(method);
queryBuilder.put(paramMap);
return invokeImpl(queryBuilder.toString());
}
}

View File

@@ -1,7 +1,7 @@
package eu.crushedpixel.replaymod.api.replay;
import com.google.gson.Gson;
import eu.crushedpixel.replaymod.ReplayMod;
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;

View File

@@ -1,24 +1,24 @@
package eu.crushedpixel.replaymod.api.replay;
public class ReplayModApiMethods {
public static final String REPLAYMOD_BASE_URL = "http://ReplayMod.com/api/";
public static final String register = REPLAYMOD_BASE_URL+"register";
public static final String check_authkey = REPLAYMOD_BASE_URL+"check_authkey";
public static final String login = REPLAYMOD_BASE_URL+"login";
public static final String logout = REPLAYMOD_BASE_URL+"logout";
public static final String file_details = REPLAYMOD_BASE_URL+"file_details";
public static final String upload_file = REPLAYMOD_BASE_URL+"upload_file";
public static final String download_file = REPLAYMOD_BASE_URL+"download_file";
public static final String get_thumbnail = REPLAYMOD_BASE_URL+"get_thumbnail";
public static final String remove_file = REPLAYMOD_BASE_URL+"remove_file";
public static final String rate_file = REPLAYMOD_BASE_URL+"rate_file";
public static final String get_ratings = REPLAYMOD_BASE_URL+"get_ratings";
public static final String fav_file = REPLAYMOD_BASE_URL+"fav_file";
public static final String get_favorites = REPLAYMOD_BASE_URL+"get_favorites";
public static final String check_auth = REPLAYMOD_BASE_URL+"check_auth";
public static final String get_language = REPLAYMOD_BASE_URL+"get_language";
public static final String search = REPLAYMOD_BASE_URL+"search";
public static final String up_to_date = REPLAYMOD_BASE_URL+"up_to_date";
}
package eu.crushedpixel.replaymod.api.replay;
public class ReplayModApiMethods {
public static final String REPLAYMOD_BASE_URL = "http://ReplayMod.com/api/";
public static final String register = REPLAYMOD_BASE_URL+"register";
public static final String check_authkey = REPLAYMOD_BASE_URL+"check_authkey";
public static final String login = REPLAYMOD_BASE_URL+"login";
public static final String logout = REPLAYMOD_BASE_URL+"logout";
public static final String file_details = REPLAYMOD_BASE_URL+"file_details";
public static final String upload_file = REPLAYMOD_BASE_URL+"upload_file";
public static final String download_file = REPLAYMOD_BASE_URL+"download_file";
public static final String get_thumbnail = REPLAYMOD_BASE_URL+"get_thumbnail";
public static final String remove_file = REPLAYMOD_BASE_URL+"remove_file";
public static final String rate_file = REPLAYMOD_BASE_URL+"rate_file";
public static final String get_ratings = REPLAYMOD_BASE_URL+"get_ratings";
public static final String fav_file = REPLAYMOD_BASE_URL+"fav_file";
public static final String get_favorites = REPLAYMOD_BASE_URL+"get_favorites";
public static final String check_auth = REPLAYMOD_BASE_URL+"check_auth";
public static final String get_language = REPLAYMOD_BASE_URL+"get_language";
public static final String search = REPLAYMOD_BASE_URL+"search";
public static final String up_to_date = REPLAYMOD_BASE_URL+"up_to_date";
}

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.api.replay.holders;
import eu.crushedpixel.replaymod.recording.ReplayMetaData;
import de.johni0702.replaystudio.replay.ReplayMetaData;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.api.replay.pagination;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
import java.io.File;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.api.replay.pagination;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
import java.util.ArrayList;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.api.replay.pagination;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.api.replay.SearchQuery;
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;

View File

@@ -1,18 +1,12 @@
package eu.crushedpixel.replaymod.assets;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import lombok.EqualsAndHashCode;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ArrayUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.zip.ZipEntry;
@EqualsAndHashCode
public class AssetRepository {
@@ -62,40 +56,29 @@ public class AssetRepository {
}
public void saveAssets() {
try {
ReplayFile replayFile = new ReplayFile(ReplayHandler.getReplayFile());
Enumeration<? extends ZipEntry> entries = replayFile.entries();
while(entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if(entry.getName().startsWith(ReplayFile.ENTRY_ASSET_FOLDER)) {
ReplayMod.replayFileAppender.registerModifiedFile(null, entry.getName(), ReplayHandler.getReplayFile());
}
}
replayFile.close();
ReplayMod.replayFileAppender.deleteAllFilesByFolder(ReplayFile.ENTRY_ASSET_FOLDER, ReplayHandler.getReplayFile());
for(Map.Entry<UUID, ReplayAsset> e : replayAssets.entrySet()) {
UUID uuid = e.getKey();
ReplayAsset asset = e.getValue();
try {
String filepath = ReplayFile.ENTRY_ASSET_FOLDER + uuid.toString()+ "_" + asset.getDisplayString() + "." + asset.getSavedFileExtension();
File toAdd = File.createTempFile("ASSET_"+asset.getDisplayString(), asset.getSavedFileExtension());
FileOutputStream fos = new FileOutputStream(toAdd);
asset.writeToStream(fos);
ReplayMod.replayFileAppender.registerModifiedFile(toAdd, filepath, ReplayHandler.getReplayFile());
} catch(IOException io) {
io.printStackTrace();
}
}
} catch(IOException e) {
e.printStackTrace();
}
// TODO
// try {
// ReplayFile replayFile = ReplayHandler.getReplayFile();
//
// for (ReplayAssetEntry entry : replayFile.getAssets()) {
// if (!replayAssets.containsKey(entry.getUuid())) {
// replayFile.removeAsset(entry.getUuid());
// }
// }
//
// for(Map.Entry<UUID, ReplayAsset> e : replayAssets.entrySet()) {
// UUID uuid = e.getKey();
// ReplayAsset asset = e.getValue();
// String extension = asset.getSavedFileExtension();
// String name = asset.getAssetName();
//
// try (OutputStream out = replayFile.writeAsset(new ReplayAssetEntry(uuid, extension, name))) {
// asset.writeToStream(out);
// }
// }
// } catch(IOException e) {
// e.printStackTrace();
// }
}
public static ReplayAsset assetFromFileName(String filename) {

View File

@@ -3,7 +3,6 @@ package eu.crushedpixel.replaymod.assets;
import eu.crushedpixel.replaymod.holders.GuiEntryListEntry;
import eu.crushedpixel.replaymod.holders.Transformations;
import eu.crushedpixel.replaymod.registry.ResourceHelper;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@@ -55,19 +54,20 @@ public class CustomImageObject implements GuiEntryListEntry {
//if no asset repository available, simply accept the UUID and it will load the image later
//when calling getResourceLocation for the first time
if(ReplayHandler.getAssetRepository() == null) {
this.linkedAsset = assetUUID;
return;
}
ReplayAsset asset = ReplayHandler.getAssetRepository().getAssetByUUID(assetUUID);
if(asset instanceof ReplayImageAsset) {
this.linkedAsset = assetUUID;
setImage(((ReplayImageAsset)asset).getObject());
} else if(asset != null) {
throw new UnsupportedOperationException("A CustomImageObject requires a ReplayImageAsset");
}
// TODO
// if(ReplayHandler.getAssetRepository() == null) {
// this.linkedAsset = assetUUID;
// return;
// }
//
// ReplayAsset asset = ReplayHandler.getAssetRepository().getAssetByUUID(assetUUID);
//
// if(asset instanceof ReplayImageAsset) {
// this.linkedAsset = assetUUID;
// setImage(((ReplayImageAsset)asset).getObject());
// } else if(asset != null) {
// throw new UnsupportedOperationException("A CustomImageObject requires a ReplayImageAsset");
// }
}
public void setImage(final BufferedImage bufferedImage) throws IOException {
@@ -103,14 +103,15 @@ public class CustomImageObject implements GuiEntryListEntry {
public ResourceLocation getResourceLocation() {
if(resourceLocation == null) {
ReplayAsset asset = ReplayHandler.getAssetRepository().getAssetByUUID(linkedAsset);
if(asset instanceof ReplayImageAsset) {
try {
setImage(((ReplayImageAsset) asset).getObject());
} catch(Exception e) {
e.printStackTrace();
}
}
// TODO
// ReplayAsset asset = ReplayHandler.getAssetRepository().getAssetByUUID(linkedAsset);
// if(asset instanceof ReplayImageAsset) {
// try {
// setImage(((ReplayImageAsset) asset).getObject());
// } catch(Exception e) {
// e.printStackTrace();
// }
// }
return null;
}

View File

@@ -1,7 +1,6 @@
package eu.crushedpixel.replaymod.assets;
import eu.crushedpixel.replaymod.registry.ResourceHelper;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.BoundingUtils;
import eu.crushedpixel.replaymod.utils.BufferedImageUtils;
import lombok.EqualsAndHashCode;
@@ -67,11 +66,12 @@ public class ReplayImageAsset implements ReplayAsset<BufferedImage> {
this.bufferedImageHashCode = BufferedImageUtils.hashCode(object);
ResourceHelper.freeResource(previewResource);
for(CustomImageObject object : ReplayHandler.getCustomImageObjects()) {
if(object.getLinkedAsset() != null && object.getLinkedAsset().equals(ReplayHandler.getAssetRepository().getUUIDForAsset(this))) {
object.setImage(this.object);
}
}
// TODO
// for(CustomImageObject object : ReplayHandler.getCustomImageObjects()) {
// if(object.getLinkedAsset() != null && object.getLinkedAsset().equals(ReplayHandler.getAssetRepository().getUUIDForAsset(this))) {
// object.setImage(this.object);
// }
// }
}
@Override

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.chat;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.resources.I18n;

View File

@@ -17,6 +17,7 @@ public class LoadingPlugin implements IFMLLoadingPlugin {
public LoadingPlugin() {
MixinBootstrap.init();
MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.replaymod.json");
MixinEnvironment.getDefaultEnvironment().addConfiguration("mixins.recording.replaymod.json");
CodeSource codeSource = getClass().getProtectionDomain().getCodeSource();
if (codeSource != null) {

View File

@@ -1,294 +0,0 @@
package eu.crushedpixel.replaymod.entities;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.replay.LesserDataWatcher;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.stats.StatFileWriter;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MathHelper;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import org.lwjgl.Sys;
import java.util.UUID;
public class CameraEntity extends EntityPlayerSP {
public static final double SPEED_CHANGE = 0.5;
public static final double LOWER_SPEED = 2;
public static final double UPPER_SPEED = 20;
private static double MAX_SPEED = 10;
private static double THRESHOLD = MAX_SPEED / 20;
private static double DECAY = MAX_SPEED/3;
public static void modifyCameraSpeed(boolean increase) {
setCameraMaximumSpeed(getCameraMaximumSpeed() + (increase ? 1 : -1) * SPEED_CHANGE);
}
public static void setCameraMaximumSpeed(double maxSpeed) {
if(maxSpeed < LOWER_SPEED || maxSpeed > UPPER_SPEED) return;
MAX_SPEED = maxSpeed;
THRESHOLD = MAX_SPEED / 20;
DECAY = 5;
}
public static double getCameraMaximumSpeed() {
return MAX_SPEED;
}
private Vec3 direction;
private Vec3 dirBefore;
private double motion;
private long lastCall = 0;
private boolean speedup = false;
public static UUID spectating;
public CameraEntity(Minecraft mcIn, World worldIn, NetHandlerPlayClient netHandlerPlayClient, StatFileWriter statFileWriter) {
super(mcIn, worldIn, netHandlerPlayClient, statFileWriter);
}
//frac = time since last tick
public void updateMovement() {
long frac = Sys.getTime() - lastCall;
if(frac == 0) return;
double decFac = Math.max(0, 1 - (DECAY * (frac / 1000D)));
if(speedup) {
if(motion < THRESHOLD) motion = THRESHOLD;
motion /= decFac;
} else {
motion *= decFac;
}
motion = Math.min(motion, MAX_SPEED);
lastCall = Sys.getTime();
if(direction == null || motion < THRESHOLD) {
return;
}
Vec3 movement = direction.normalize();
double factor = motion * (frac / 1000D);
moveRelative(movement.xCoord * factor, movement.yCoord * factor, movement.zCoord * factor);
}
public void speedUp() {
speedup = true;
}
public void stopSpeedUp() {
speedup = false;
}
public void setMovement(MoveDirection dir) {
switch(dir) {
case BACKWARD:
direction = this.getVectorForRotation(-rotationPitch, rotationYaw - 180);
break;
case DOWN:
direction = this.getVectorForRotation(90, 0);
break;
case FORWARD:
direction = this.getVectorForRotation(rotationPitch, rotationYaw);
break;
case LEFT:
direction = this.getVectorForRotation(0, rotationYaw - 90);
break;
case RIGHT:
direction = this.getVectorForRotation(0, rotationYaw + 90);
break;
case UP:
direction = this.getVectorForRotation(-90, 0);
break;
}
Vec3 dbf = direction;
if(dirBefore != null) {
direction = dirBefore.normalize().add(direction);
}
dirBefore = dbf;
updateMovement();
}
public void moveAbsolute(AdvancedPosition pos) {
this.moveAbsolute(pos.getX(), pos.getY(), pos.getZ());
rotationPitch = prevRotationPitch = (float)pos.getPitch();
rotationYaw = prevRotationYaw = (float)pos.getYaw();
updateBoundingBox();
}
public void moveAbsolute(double x, double y, double z) {
if(ReplayHandler.isInPath()) return;
this.lastTickPosX = this.prevPosX = this.posX = x;
this.lastTickPosY = this.prevPosY = this.posY = y;
this.lastTickPosZ = this.prevPosZ = this.posZ = z;
updateBoundingBox();
}
public void moveRelative(double x, double y, double z) {
if(ReplayHandler.isInPath()) return;
this.lastTickPosX = this.prevPosX = this.posX = this.posX + x;
this.lastTickPosY = this.prevPosY = this.posY = this.posY + y;
this.lastTickPosZ = this.prevPosZ = this.posZ = this.posZ + z;
updateBoundingBox();
}
public void movePath(AdvancedPosition pos) {
this.prevRotationPitch = this.rotationPitch = (float)pos.getPitch();
this.prevRotationYaw = this.rotationYaw = (float)pos.getYaw();
this.lastTickPosX = this.prevPosX = this.posX = pos.getX();
this.lastTickPosY = this.prevPosY = this.posY = pos.getY();
this.lastTickPosZ = this.prevPosZ = this.posZ = pos.getZ();
updateBoundingBox();
}
private void updateBoundingBox() {
this.setEntityBoundingBox(new AxisAlignedBB(posX - width / 2, posY, posZ - width / 2,
posX + width / 2, posY + height, posZ + width / 2));
}
private void updatePos(Entity to) {
prevPosX = to.prevPosX;
prevPosY = to.prevPosY;
prevPosZ = to.prevPosZ;
prevRotationYaw = to.prevRotationYaw;
prevRotationPitch = to.prevRotationPitch;
posX = to.posX;
posY = to.posY;
posZ = to.posZ;
rotationYaw = to.rotationYaw;
rotationPitch = to.rotationPitch;
}
@Override
protected void entityInit() {
this.dataWatcher = new LesserDataWatcher(this);
this.setSize(0.6f, 1.8f);
updateBoundingBox();
}
@Override
public void setAngles(float yaw, float pitch) {
if (ReplayHandler.isInPath()) {
return; // Disallow camera movement by mouse during path preview
}
this.rotationYaw = (float) ((double) this.rotationYaw + (double) yaw * 0.15D);
this.rotationPitch = (float) ((double) this.rotationPitch - (double) pitch * 0.15D);
this.rotationPitch = MathHelper.clamp_float(this.rotationPitch, -90.0F, 90.0F);
this.prevRotationPitch = this.rotationPitch;
this.prevRotationYawHead = this.rotationYawHead = this.prevRotationYaw = this.rotationYaw;
}
@Override
public void onUpdate() {
Entity view = mc.getRenderViewEntity();
if (view != null) {
if (spectating != null && (view.getUniqueID() != spectating || view.worldObj != worldObj)) {
view = worldObj.getPlayerEntityByUUID(spectating);
if (view != null) {
mc.setRenderViewEntity(view);
} else {
mc.setRenderViewEntity(this);
return;
}
}
if (view != this) {
updatePos(view);
}
}
}
@Override
public void preparePlayerToSpawn() {
if (mc.theWorld != null) {
worldObj = mc.theWorld;
}
super.preparePlayerToSpawn();
}
@Override
public boolean isEntityInsideOpaqueBlock() {
return false;
}
@Override
public boolean isInsideOfMaterial(Material materialIn) {
return false;
}
@Override
public boolean isInLava() {
return false;
}
@Override
public boolean isInWater() {
return false;
}
@Override
public boolean canBePushed() {
return false;
}
@Override
protected void createRunningParticles() {}
@Override
public boolean canBeCollidedWith() {
return false;
}
@Override
public boolean isSpectator() {
return true;
}
public void spectate(Entity e) {
if (e == null || e == this) {
spectating = null;
e = this;
} else if (e instanceof EntityPlayer) {
spectating = e.getUniqueID();
}
if (mc.getRenderViewEntity() != e) {
mc.setRenderViewEntity(e);
updatePos(e);
}
}
public enum MoveDirection {
UP, DOWN, LEFT, RIGHT, FORWARD, BACKWARD
}
@Override
public MovingObjectPosition rayTrace(double p_174822_1_, float p_174822_3_) {
MovingObjectPosition pos = super.rayTrace(p_174822_1_, 1f);
if(pos != null && pos.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) {
pos.typeOfHit = MovingObjectPosition.MovingObjectType.MISS;
}
return pos;
}
}

View File

@@ -1,6 +0,0 @@
package eu.crushedpixel.replaymod.events;
import net.minecraftforge.fml.common.eventhandler.Event;
public class ReplayExitEvent extends Event {
}

View File

@@ -1,8 +1,6 @@
package eu.crushedpixel.replaymod.events.handlers;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@@ -13,18 +11,20 @@ public class CrosshairRenderHandler {
@SubscribeEvent
public void preCrosshairRender(RenderGameOverlayEvent.Pre event) {
//Crosshair should only render if hovered Entity can actually be spectated
if(ReplayHandler.isInReplay() && ReplayHandler.isCamera() && event.type == RenderGameOverlayEvent.ElementType.CROSSHAIRS) {
boolean cancel = !SpectatingHandler.canSpectate(mc.pointedEntity);
event.setCanceled(cancel);
}
// TODO
// if(ReplayHandler.isInReplay() && ReplayHandler.isCameraView() && event.type == RenderGameOverlayEvent.ElementType.CROSSHAIRS) {
// boolean cancel = !SpectatingHandler.canSpectate(mc.pointedEntity);
// event.setCanceled(cancel);
// }
}
@SubscribeEvent
public void preChatRender(RenderGameOverlayEvent.Pre event) {
if(ReplayHandler.isInReplay() && ReplayHandler.isCamera() && event.type == RenderGameOverlayEvent.ElementType.CHAT) {
//when a crosshair was displayed, the background of the lowest line of chat would be opaque
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
}
// TODO
// if(ReplayHandler.isInReplay() && ReplayHandler.isCameraView() && event.type == RenderGameOverlayEvent.ElementType.CHAT) {
// //when a crosshair was displayed, the background of the lowest line of chat would be opaque
// GlStateManager.enableTexture2D();
// GlStateManager.disableBlend();
// }
}
}

View File

@@ -1,14 +1,11 @@
package eu.crushedpixel.replaymod.events.handlers;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.gui.GuiReplaySettings;
import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.gui.GuiReplaySettings;
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.gui.replayviewer.GuiReplayViewer;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplayProcess;
import eu.crushedpixel.replaymod.settings.ReplaySettings;
import eu.crushedpixel.replaymod.studio.VersionValidator;
import eu.crushedpixel.replaymod.utils.MouseUtils;
@@ -26,7 +23,6 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.util.Point;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class GuiEventHandler {
@@ -54,19 +50,20 @@ public class GuiEventHandler {
e.printStackTrace();
}
}
if(ReplayHandler.isInReplay()) ReplayHandler.setInReplay(false);
}
if(!ReplayMod.apiClient.isLoggedIn()) return;
if(event.gui instanceof GuiChat || event.gui instanceof GuiInventory) {
if(ReplayHandler.isInReplay()) {
event.setCanceled(true);
}
// TODO
// if(ReplayHandler.isInReplay()) {
// event.setCanceled(true);
// }
} else if(event.gui instanceof GuiDisconnected) {
if(!ReplayHandler.isInReplay() && System.currentTimeMillis() - ReplayHandler.lastExit < 5000) {
event.setCanceled(true);
}
// TODO
// if(!ReplayHandler.isInReplay() && System.currentTimeMillis() - ReplayHandler.lastExit < 5000) {
// event.setCanceled(true);
// }
}
}
@@ -121,20 +118,7 @@ public class GuiEventHandler {
public void onInit(InitGuiEvent event) {
@SuppressWarnings("unchecked")
List<GuiButton> buttonList = event.buttonList;
if(event.gui instanceof GuiIngameMenu && ReplayHandler.isInReplay()) {
ReplayMod.replaySender.setReplaySpeed(0);
for(GuiButton b : new ArrayList<GuiButton>(buttonList)) {
if(b.id == 1) {
b.displayString = I18n.format("replaymod.gui.exit");
b.yPosition -= 24 * 2;
b.id = GuiConstants.EXIT_REPLAY_BUTTON;
} else if(b.id >= 5 && b.id <= 7) {
buttonList.remove(b);
} else if(b.id != 4) {
b.yPosition -= 24 * 2;
}
}
} else if(event.gui instanceof GuiMainMenu) {
if(event.gui instanceof GuiMainMenu) {
int i1 = event.gui.height / 4 + 24 + 10;
for(GuiButton b : buttonList) {
@@ -171,9 +155,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_MANAGER_BUTTON_ID) {
mc.displayGuiScreen(new GuiReplayViewer());
} else if(event.button.id == GuiConstants.REPLAY_CENTER_BUTTON_ID) {
if(event.button.id == GuiConstants.REPLAY_CENTER_BUTTON_ID) {
if(ReplayMod.apiClient.isLoggedIn()) {
mc.displayGuiScreen(new GuiReplayCenter());
} else {
@@ -183,17 +165,7 @@ public class GuiEventHandler {
mc.displayGuiScreen(new GuiReplayEditor());
}
} else if(event.gui instanceof GuiOptions && event.button.id == GuiConstants.REPLAY_OPTIONS_BUTTON_ID) {
mc.displayGuiScreen(new GuiReplaySettings(event.gui));
}
if(ReplayHandler.isInReplay() && event.gui instanceof GuiIngameMenu && event.button.id == GuiConstants.EXIT_REPLAY_BUTTON) {
if(ReplayHandler.isInPath()) ReplayProcess.stopReplayProcess(false);
event.button.enabled = false;
mc.displayGuiScreen(new GuiMainMenu());
ReplayHandler.endReplay();
new GuiReplaySettings(event.gui, ReplayMod.instance.getSettingsRegistry()).display();
}
}

View File

@@ -1,20 +1,19 @@
package eu.crushedpixel.replaymod.events.handlers;
import eu.crushedpixel.replaymod.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.crash.CrashReport;
import net.minecraft.util.ReportedException;
import net.minecraftforge.client.event.MouseEvent;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
public class MinecraftTicker {
public static void runMouseKeyboardTick(Minecraft mc) {
ReplayMod.mouseInputHandler.mouseEvent(new MouseEvent());
// TODO
// ReplayMod.mouseInputHandler.mouseEvent(new MouseEvent());
if(mc.thePlayer == null) return;
try {
mc.mcProfiler.endStartSection("mouse");

View File

@@ -1,51 +1,45 @@
package eu.crushedpixel.replaymod.events.handlers;
import eu.crushedpixel.replaymod.entities.CameraEntity;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.input.Mouse;
public class MouseInputHandler {
private final Minecraft mc = Minecraft.getMinecraft();
private boolean rightDown = false;
private boolean leftDown = false;
@SubscribeEvent
public void mouseEvent(MouseEvent event) {
if(!ReplayHandler.isInReplay()) {
return;
}
if(event.dwheel != 0 && mc.currentScreen == null) {
boolean increase = event.dwheel > 0;
CameraEntity.modifyCameraSpeed(increase);
}
if(Mouse.isButtonDown(0)) {
if(!leftDown) {
leftDown = true;
if(mc.pointedEntity != null && ReplayHandler.isCamera() && mc.currentScreen == null) {
if(SpectatingHandler.canSpectate(mc.pointedEntity))
ReplayHandler.spectateEntity(mc.pointedEntity);
}
}
} else {
leftDown = false;
}
if(Mouse.isButtonDown(1)) {
if(!rightDown) {
rightDown = true;
if(mc.pointedEntity != null && ReplayHandler.isCamera() && mc.currentScreen == null) {
if(SpectatingHandler.canSpectate(mc.pointedEntity))
ReplayHandler.spectateEntity(mc.pointedEntity);
}
}
} else {
rightDown = false;
}
}
// TODO
// private final Minecraft mc = Minecraft.getMinecraft();
// private boolean rightDown = false;
// private boolean leftDown = false;
//
// @SubscribeEvent
// public void mouseEvent(MouseEvent event) {
// if(!ReplayHandler.isInReplay()) {
// return;
// }
//
// if(event.dwheel != 0 && mc.currentScreen == null) {
// boolean increase = event.dwheel > 0;
// CameraEntity.modifyCameraSpeed(increase);
// }
//
// if(Mouse.isButtonDown(0)) {
// if(!leftDown) {
// leftDown = true;
// if(mc.pointedEntity != null && ReplayHandler.isCameraView() && mc.currentScreen == null) {
// if(SpectatingHandler.canSpectate(mc.pointedEntity))
// ReplayHandler.spectateEntity(mc.pointedEntity);
// }
// }
// } else {
// leftDown = false;
// }
//
// if(Mouse.isButtonDown(1)) {
// if(!rightDown) {
// rightDown = true;
// if(mc.pointedEntity != null && ReplayHandler.isCameraView() && mc.currentScreen == null) {
// if(SpectatingHandler.canSpectate(mc.pointedEntity))
// ReplayHandler.spectateEntity(mc.pointedEntity);
// }
// }
// } else {
// rightDown = false;
// }
// }
}

View File

@@ -1,369 +0,0 @@
package eu.crushedpixel.replaymod.events.handlers;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import eu.crushedpixel.replaymod.utils.Objects;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.server.*;
import net.minecraft.network.play.server.S14PacketEntity.S17PacketEntityLookMove;
import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.util.MathHelper;
import net.minecraftforge.event.entity.minecart.MinecartInteractEvent;
import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
import net.minecraftforge.event.entity.player.PlayerUseItemEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.ItemPickupEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.PlayerTickEvent;
public class RecordingHandler {
private final Minecraft mc = Minecraft.getMinecraft();
private Double lastX = null, lastY = null, lastZ = null;
private ItemStack[] playerItems = new ItemStack[5];
private int ticksSinceLastCorrection = 0;
private boolean wasSleeping = false;
private int lastRiding = -1;
private Integer rotationYawHeadBefore = null;
public void onPlayerJoin() {
try {
if(!ConnectionEventHandler.isRecording()) return;
ConnectionEventHandler.insertPacket(spawnPlayer(mc.thePlayer));
} catch(Exception e1) {
e1.printStackTrace();
}
}
public void onPlayerRespawn() {
if(!ConnectionEventHandler.isRecording()) return;
try {
ConnectionEventHandler.insertPacket(spawnPlayer(mc.thePlayer));
} catch(Exception e) {
e.printStackTrace();
}
}
private S0CPacketSpawnPlayer spawnPlayer(EntityPlayer player) {
try {
S0CPacketSpawnPlayer packet = new S0CPacketSpawnPlayer();
ByteBuf bb = Unpooled.buffer();
PacketBuffer pb = new PacketBuffer(bb);
pb.writeVarIntToBuffer(player.getEntityId());
pb.writeUuid(EntityPlayer.getUUID(player.getGameProfile()));
pb.writeInt(MathHelper.floor_double(player.posX * 32.0D));
pb.writeInt(MathHelper.floor_double(player.posY * 32.0D));
pb.writeInt(MathHelper.floor_double(player.posZ * 32.0D));
pb.writeByte((byte) ((int) (player.rotationYaw * 256.0F / 360.0F)));
pb.writeByte((byte) ((int) (player.rotationPitch * 256.0F / 360.0F)));
ItemStack itemstack = player.inventory.getCurrentItem();
pb.writeShort(itemstack == null ? 0 : Item.getIdFromItem(itemstack.getItem()));
player.getDataWatcher().writeTo(pb);
packet.readPacketData(pb);
return packet;
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
public void resetVars() {
lastX = lastY = lastZ = null;
rotationYawHeadBefore = null;
playerItems = new ItemStack[5];
}
@SubscribeEvent
public void onPlayerTick(PlayerTickEvent e) {
if(!ConnectionEventHandler.isRecording()) return;
try {
if(e.player != mc.thePlayer) return;
if(!ConnectionEventHandler.isRecording()) return;
boolean force = false;
if(lastX == null || lastY == null || lastZ == null) {
force = true;
lastX = e.player.posX;
lastY = e.player.posY;
lastZ = e.player.posZ;
}
ticksSinceLastCorrection++;
if(ticksSinceLastCorrection >= 100) {
ticksSinceLastCorrection = 0;
force = true;
}
double dx = e.player.posX - lastX;
double dy = e.player.posY - lastY;
double dz = e.player.posZ - lastZ;
lastX = e.player.posX;
lastY = e.player.posY;
lastZ = e.player.posZ;
Packet packet;
if(force || Math.abs(dx) > 4.0 || Math.abs(dy) > 4.0 || Math.abs(dz) > 4.0) {
int x = MathHelper.floor_double(e.player.posX * 32.0D);
int y = MathHelper.floor_double(e.player.posY * 32.0D);
int z = MathHelper.floor_double(e.player.posZ * 32.0D);
byte yaw = (byte) ((int) (e.player.rotationYaw * 256.0F / 360.0F));
byte pitch = (byte) ((int) (e.player.rotationPitch * 256.0F / 360.0F));
packet = new S18PacketEntityTeleport(e.player.getEntityId(), x, y, z, yaw, pitch, e.player.onGround);
} else {
byte newYaw = (byte) ((int) (e.player.rotationYaw * 256.0F / 360.0F));
byte newPitch = (byte) ((int) (e.player.rotationPitch * 256.0F / 360.0F));
packet = new S17PacketEntityLookMove(e.player.getEntityId(),
(byte) Math.round(dx * 32), (byte) Math.round(dy * 32), (byte) Math.round(dz * 32),
newYaw, newPitch, e.player.onGround);
}
ConnectionEventHandler.insertPacket(packet);
//HEAD POS
int rotationYawHead = ((int)(e.player.rotationYawHead * 256.0F / 360.0F));
if(!Objects.equals(rotationYawHead, rotationYawHeadBefore)) {
S19PacketEntityHeadLook head = new S19PacketEntityHeadLook();
ByteBuf bb1 = Unpooled.buffer();
PacketBuffer pb1 = new PacketBuffer(bb1);
pb1.writeVarIntToBuffer(e.player.getEntityId());
pb1.writeByte(rotationYawHead);
head.readPacketData(pb1);
ConnectionEventHandler.insertPacket(head);
rotationYawHeadBefore = rotationYawHead;
}
S12PacketEntityVelocity vel = new S12PacketEntityVelocity(e.player.getEntityId(), e.player.motionX, e.player.motionY, e.player.motionZ);
ConnectionEventHandler.insertPacket(vel);
//Animation Packets
//Swing Animation
if(e.player.swingProgressInt == 1) {
S0BPacketAnimation pac = new S0BPacketAnimation();
ByteBuf bb = Unpooled.buffer();
PacketBuffer pb = new PacketBuffer(bb);
pb.writeVarIntToBuffer(e.player.getEntityId());
pb.writeByte(0);
pac.readPacketData(pb);
ConnectionEventHandler.insertPacket(pac);
}
/*
//Potion Effect Handling
List<Integer> found = new ArrayList<Integer>();
for(PotionEffect pe : (Collection<PotionEffect>)e.player.getActivePotionEffects()) {
found.add(pe.getPotionID());
if(lastEffects.contains(found)) continue;
S1DPacketEntityEffect pee = new S1DPacketEntityEffect(entityID, pe);
ConnectionEventHandler.insertPacket(pee);
}
for(int id : lastEffects) {
if(!found.contains(id)) {
S1EPacketRemoveEntityEffect pre = new S1EPacketRemoveEntityEffect(entityID, new PotionEffect(id, 0));
ConnectionEventHandler.insertPacket(pre);
}
}
lastEffects = found;
*/
//Inventory Handling
if(playerItems[0] != mc.thePlayer.getHeldItem()) {
playerItems[0] = mc.thePlayer.getHeldItem();
S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 0, playerItems[0]);
ConnectionEventHandler.insertPacket(pee);
}
if(playerItems[1] != mc.thePlayer.inventory.armorInventory[0]) {
playerItems[1] = mc.thePlayer.inventory.armorInventory[0];
S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 1, playerItems[1]);
ConnectionEventHandler.insertPacket(pee);
}
if(playerItems[2] != mc.thePlayer.inventory.armorInventory[1]) {
playerItems[2] = mc.thePlayer.inventory.armorInventory[1];
S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 2, playerItems[2]);
ConnectionEventHandler.insertPacket(pee);
}
if(playerItems[3] != mc.thePlayer.inventory.armorInventory[2]) {
playerItems[3] = mc.thePlayer.inventory.armorInventory[2];
S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 3, playerItems[3]);
ConnectionEventHandler.insertPacket(pee);
}
if(playerItems[4] != mc.thePlayer.inventory.armorInventory[3]) {
playerItems[4] = mc.thePlayer.inventory.armorInventory[3];
S04PacketEntityEquipment pee = new S04PacketEntityEquipment(e.player.getEntityId(), 4, playerItems[4]);
ConnectionEventHandler.insertPacket(pee);
}
//Leaving Ride
if((!mc.thePlayer.isRiding() && lastRiding != -1) ||
(mc.thePlayer.isRiding() && lastRiding != mc.thePlayer.ridingEntity.getEntityId())) {
if(!mc.thePlayer.isRiding()) {
lastRiding = -1;
} else {
lastRiding = mc.thePlayer.ridingEntity.getEntityId();
}
S1BPacketEntityAttach pea = new S1BPacketEntityAttach();
ByteBuf buf = Unpooled.buffer();
PacketBuffer pbuf = new PacketBuffer(buf);
pbuf.writeInt(e.player.getEntityId());
pbuf.writeInt(lastRiding);
pbuf.writeBoolean(false);
pea.readPacketData(pbuf);
ConnectionEventHandler.insertPacket(pea);
}
//Sleeping
if(!mc.thePlayer.isPlayerSleeping() && wasSleeping) {
S0BPacketAnimation pac = new S0BPacketAnimation();
ByteBuf bb = Unpooled.buffer();
PacketBuffer pb = new PacketBuffer(bb);
pb.writeVarIntToBuffer(e.player.getEntityId());
pb.writeByte(2);
pac.readPacketData(pb);
ConnectionEventHandler.insertPacket(pac);
wasSleeping = false;
}
} catch(Exception e1) {
e1.printStackTrace();
}
}
@SubscribeEvent
public void onPickupItem(ItemPickupEvent event) {
if(!ConnectionEventHandler.isRecording()) return;
try {
ConnectionEventHandler.insertPacket(new S0DPacketCollectItem(event.pickedUp.getEntityId(), event.player.getEntityId()));
} catch(Exception e) {
e.printStackTrace();
}
}
@SubscribeEvent
public void onStartEating(PlayerUseItemEvent.Start event) {
if(!ConnectionEventHandler.isRecording()) return;
try {
if(!event.entityPlayer.isEating()) return;
S0BPacketAnimation packet = new S0BPacketAnimation();
ByteBuf bb = Unpooled.buffer();
PacketBuffer pb = new PacketBuffer(bb);
pb.writeVarIntToBuffer(event.entityPlayer.getEntityId());
pb.writeByte(3);
packet.readPacketData(pb);
ConnectionEventHandler.insertPacket(packet);
} catch(Exception e) {
e.printStackTrace();
}
}
@SubscribeEvent
public void onSleep(PlayerSleepInBedEvent event) {
if(!ConnectionEventHandler.isRecording()) return;
try {
if(event.entityPlayer != mc.thePlayer) {
return;
}
System.out.println(event.getResult());
S0APacketUseBed pub = new S0APacketUseBed();
ByteBuf buf = Unpooled.buffer();
PacketBuffer pbuf = new PacketBuffer(buf);
pbuf.writeVarIntToBuffer(event.entityPlayer.getEntityId());
pbuf.writeBlockPos(event.pos);
pub.readPacketData(pbuf);
ConnectionEventHandler.insertPacket(pub);
wasSleeping = true;
} catch(Exception e) {
e.printStackTrace();
}
}
@SubscribeEvent
public void enterMinecart(MinecartInteractEvent event) {
if(!ConnectionEventHandler.isRecording()) return;
try {
if(event.player != mc.thePlayer) {
return;
}
S1BPacketEntityAttach pea = new S1BPacketEntityAttach();
ByteBuf buf = Unpooled.buffer();
PacketBuffer pbuf = new PacketBuffer(buf);
pbuf.writeInt(event.player.getEntityId());
pbuf.writeInt(event.minecart.getEntityId());
pbuf.writeBoolean(false);
pea.readPacketData(pbuf);
ConnectionEventHandler.insertPacket(pea);
lastRiding = event.minecart.getEntityId();
} catch(Exception e) {
e.printStackTrace();
}
}
@SubscribeEvent
public void checkForGamePaused(TickEvent.RenderTickEvent event) {
if (event.phase != TickEvent.Phase.START) return;
if (!ConnectionEventHandler.isRecording()) return;
if (mc.isIntegratedServerRunning()) {
IntegratedServer server = mc.getIntegratedServer();
if (server != null && server.isGamePaused) {
ConnectionEventHandler.notifyServerPaused();
}
}
}
}

View File

@@ -1,18 +1,10 @@
package eu.crushedpixel.replaymod.events.handlers;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.chat.ChatMessageHandler;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplayProcess;
import eu.crushedpixel.replaymod.video.ReplayScreenshot;
import net.minecraft.client.Minecraft;
import net.minecraftforge.client.event.MouseEvent;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
public class TickAndRenderListener {
@@ -30,75 +22,78 @@ public class TickAndRenderListener {
@SubscribeEvent
public void onRenderWorld(RenderWorldLastEvent event) throws Exception {
if(!ReplayHandler.isInReplay()) return; //If not in Replay, cancel
if (ReplayProcess.isVideoRecording()) return; // If recording, cancel
if(requestScreenshot == 1) {
mc.addScheduledTask(new Runnable() {
@Override
public void run() {
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.savingthumb", ChatMessageHandler.ChatMessageType.INFORMATION);
ReplayScreenshot.prepareScreenshot();
requestScreenshot = 2;
}
});
} else if(requestScreenshot == 2) {
mc.addScheduledTask(new Runnable() {
@Override
public void run() {
ReplayScreenshot.saveScreenshot();
}
});
}
if(ReplayHandler.isInPath()) ReplayProcess.tickReplay(false);
if(ReplayHandler.isCamera()) mc.setRenderViewEntity(ReplayHandler.getCameraEntity());
if(mc.isGamePaused() && ReplayHandler.isInPath()) {
mc.isGamePaused = false;
}
// TODO
// if(!ReplayHandler.isInReplay()) return; //If not in Replay, cancel
// if (ReplayProcess.isVideoRecording()) return; // If recording, cancel
//
// if(requestScreenshot == 1) {
// mc.addScheduledTask(new Runnable() {
// @Override
// public void run() {
// ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.savingthumb", ChatMessageHandler.ChatMessageType.INFORMATION);
// ReplayScreenshot.prepareScreenshot();
// requestScreenshot = 2;
// }
// });
// } else if(requestScreenshot == 2) {
// mc.addScheduledTask(new Runnable() {
// @Override
// public void run() {
// ReplayScreenshot.saveScreenshot();
// }
// });
// }
//
// if(ReplayHandler.isInPath()) ReplayProcess.tickReplay(false);
// if(ReplayHandler.isCameraView()) mc.setRenderViewEntity(ReplayHandler.getCameraEntity());
//
// if(mc.isGamePaused() && ReplayHandler.isInPath()) {
// mc.isGamePaused = false;
// }
}
@SubscribeEvent
public void onRenderTick(TickEvent.RenderTickEvent event) {
if(!ReplayHandler.isInReplay() || ReplayProcess.isVideoRecording()) return;
if(ReplayHandler.getCameraEntity() != null)
ReplayHandler.getCameraEntity().updateMovement();
if(ReplayHandler.isInPath()) {
ReplayProcess.tickReplay(true);
} else onMouseMove(new MouseEvent());
FMLCommonHandler.instance().fireKeyInput();
// TODO
// if(!ReplayHandler.isInReplay() || ReplayProcess.isVideoRecording()) return;
//
// if(ReplayHandler.getCameraEntity() != null)
// ReplayHandler.getCameraEntity().updateMovement();
// if(ReplayHandler.isInPath()) {
// ReplayProcess.tickReplay(true);
// } else onMouseMove(new MouseEvent());
//
// FMLCommonHandler.instance().fireKeyInput();
}
@SubscribeEvent
public void onMouseMove(MouseEvent event) {
if(!ReplayHandler.isInReplay()) return;
mc.mcProfiler.startSection("mouse");
if(Minecraft.isRunningOnMac && mc.inGameHasFocus && !Mouse.isInsideWindow()) {
Mouse.setGrabbed(false);
Mouse.setCursorPosition(Display.getWidth() / 2, Display.getHeight() / 2);
Mouse.setGrabbed(true);
}
if(mc.inGameHasFocus && !(ReplayHandler.isInPath())) {
mc.mouseHelper.mouseXYChange();
float f1 = mc.gameSettings.mouseSensitivity * 0.6F + 0.2F;
float f2 = f1 * f1 * f1 * 8.0F;
float f3 = (float) mc.mouseHelper.deltaX * f2;
float f4 = (float) mc.mouseHelper.deltaY * f2;
byte b0 = 1;
if(mc.gameSettings.invertMouse) {
b0 = -1;
}
if(ReplayHandler.getCameraEntity() != null) {
ReplayHandler.getCameraEntity().setAngles(f3, f4 * (float) b0);
}
}
// TODO
// if(!ReplayHandler.isInReplay()) return;
//
// mc.mcProfiler.startSection("mouse");
//
// if(Minecraft.isRunningOnMac && mc.inGameHasFocus && !Mouse.isInsideWindow()) {
// Mouse.setGrabbed(false);
// Mouse.setCursorPosition(Display.getWidth() / 2, Display.getHeight() / 2);
// Mouse.setGrabbed(true);
// }
//
// if(mc.inGameHasFocus && !(ReplayHandler.isInPath())) {
// mc.mouseHelper.mouseXYChange();
// float f1 = mc.gameSettings.mouseSensitivity * 0.6F + 0.2F;
// float f2 = f1 * f1 * f1 * 8.0F;
// float f3 = (float) mc.mouseHelper.deltaX * f2;
// float f4 = (float) mc.mouseHelper.deltaY * f2;
// byte b0 = 1;
//
// if(mc.gameSettings.invertMouse) {
// b0 = -1;
// }
//
// if(ReplayHandler.getCameraEntity() != null) {
// ReplayHandler.getCameraEntity().setAngles(f3, f4 * (float) b0);
// }
// }
}
}

View File

@@ -1,22 +1,8 @@
package eu.crushedpixel.replaymod.events.handlers.keyboard;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.entities.CameraEntity.MoveDirection;
import eu.crushedpixel.replaymod.events.handlers.TickAndRenderListener;
import eu.crushedpixel.replaymod.gui.GuiAssetManager;
import eu.crushedpixel.replaymod.gui.GuiKeyframeRepository;
import eu.crushedpixel.replaymod.gui.GuiMouseInput;
import eu.crushedpixel.replaymod.gui.GuiObjectManager;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import eu.crushedpixel.replaymod.registry.KeybindRegistry;
import eu.crushedpixel.replaymod.registry.PlayerHandler;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.InputEvent;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
public class KeyInputHandler {
@@ -25,200 +11,200 @@ public class KeyInputHandler {
private long prevKeysDown = Sys.getTime();
public void onKeyInput() throws Exception {
if(!ReplayHandler.isInReplay()) return;
KeyBinding[] keyBindings = Minecraft.getMinecraft().gameSettings.keyBindings;
boolean speedup = false;
if(mc.currentScreen == null) {
boolean forward = false, backward = false, left = false, right = false, up = false, down = false;
if(!ReplayHandler.isInPath()) {
for(KeyBinding kb : keyBindings) {
if(!kb.isKeyDown()) continue;
if(ReplayHandler.isCamera()) {
if(kb.getKeyDescription().equals("key.forward")) {
forward = true;
speedup = true;
}
if(kb.getKeyDescription().equals("key.back")) {
backward = true;
speedup = true;
}
if(kb.getKeyDescription().equals("key.jump")) {
up = true;
speedup = true;
}
if(kb.getKeyDescription().equals("key.left")) {
left = true;
speedup = true;
}
if(kb.getKeyDescription().equals("key.right")) {
right = true;
speedup = true;
}
}
if(kb.getKeyDescription().equals("key.sneak")) {
if(ReplayHandler.isCamera()) {
down = true;
speedup = true;
}
ReplayHandler.spectateCamera();
}
}
forwardCameraMovement(forward, backward, left, right, up, down);
}
}
if(ReplayHandler.getCameraEntity() != null) {
if(speedup) {
ReplayHandler.getCameraEntity().speedUp();
prevKeysDown = Sys.getTime();
} else {
if(Sys.getTime() - prevKeysDown > 100) {
ReplayHandler.getCameraEntity().stopSpeedUp();
}
}
}
}
@SubscribeEvent
public void keyInput(InputEvent.KeyInputEvent event) {
try {
onKeyInput();
} catch(Exception e) {
e.printStackTrace();
}
KeyBinding[] keyBindings = Minecraft.getMinecraft().gameSettings.keyBindings;
boolean found = false;
for(KeyBinding kb : keyBindings) {
if(!kb.isKeyDown()) continue;
handleCustomKeybindings(kb, found, -1);
found = true;
}
if(!ReplayHandler.isInReplay() || (mc.currentScreen != null && !(mc.currentScreen instanceof GuiMouseInput))) return;
for(StaticKeybinding staticKeybinding : KeybindRegistry.staticKeybindings) {
if(!Keyboard.isKeyDown(staticKeybinding.getKeyCode())) {
staticKeybinding.setDown(false);
return;
}
if(staticKeybinding.isDown()) return;
staticKeybinding.setDown(true);
switch(staticKeybinding.getId()) {
case KeybindRegistry.STATIC_DELETE_KEYFRAME:
if(ReplayHandler.getSelectedKeyframe() != null) ReplayHandler.removeKeyframe(ReplayHandler.getSelectedKeyframe());
break;
}
}
}
private void forwardCameraMovement(boolean forward, boolean backward, boolean left, boolean right, boolean up, boolean down) {
if(forward && !backward) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.FORWARD);
} else if(backward && !forward) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.BACKWARD);
}
if(left && !right) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.LEFT);
} else if(right && !left) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.RIGHT);
}
if(up && !down) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.UP);
} else if(down && !up) {
ReplayHandler.getCameraEntity().setMovement(MoveDirection.DOWN);
}
// TODO
// if(!ReplayHandler.isInReplay()) return;
//
// KeyBinding[] keyBindings = Minecraft.getMinecraft().gameSettings.keyBindings;
//
// boolean speedup = false;
//
// if(mc.currentScreen == null) {
// boolean forward = false, backward = false, left = false, right = false, up = false, down = false;
//
// if(!ReplayHandler.isInPath()) {
// for(KeyBinding kb : keyBindings) {
// if(!kb.isKeyDown()) continue;
// if(ReplayHandler.isCameraView()) {
// if(kb.getKeyDescription().equals("key.forward")) {
// forward = true;
// speedup = true;
// }
//
// if(kb.getKeyDescription().equals("key.back")) {
// backward = true;
// speedup = true;
// }
//
// if(kb.getKeyDescription().equals("key.jump")) {
// up = true;
// speedup = true;
// }
//
// if(kb.getKeyDescription().equals("key.left")) {
// left = true;
// speedup = true;
// }
//
// if(kb.getKeyDescription().equals("key.right")) {
// right = true;
// speedup = true;
// }
// }
//
// if(kb.getKeyDescription().equals("key.sneak")) {
// if(ReplayHandler.isCameraView()) {
// down = true;
// speedup = true;
// }
// ReplayHandler.spectateCamera();
// }
// }
//
// forwardCameraMovement(forward, backward, left, right, up, down);
// }
// }
//
// if(ReplayHandler.getCameraEntity() != null) {
// if(speedup) {
// ReplayHandler.getCameraEntity().speedUp();
// prevKeysDown = Sys.getTime();
// } else {
// if(Sys.getTime() - prevKeysDown > 100) {
// ReplayHandler.getCameraEntity().stopSpeedUp();
// }
// }
// }
}
//
// @SubscribeEvent
// public void keyInput(InputEvent.KeyInputEvent event) {
// try {
// onKeyInput();
// } catch(Exception e) {
// e.printStackTrace();
// }
//
// KeyBinding[] keyBindings = Minecraft.getMinecraft().gameSettings.keyBindings;
//
// boolean found = false;
//
// for(KeyBinding kb : keyBindings) {
// if(!kb.isKeyDown()) continue;
//
// handleCustomKeybindings(kb, found, -1);
// found = true;
// }
//
// if(!ReplayHandler.isInReplay() || (mc.currentScreen != null && !(mc.currentScreen instanceof GuiMouseInput))) return;
//
// for(StaticKeybinding staticKeybinding : KeybindRegistry.staticKeybindings) {
// if(!Keyboard.isKeyDown(staticKeybinding.getKeyCode())) {
// staticKeybinding.setDown(false);
// return;
// }
//
// if(staticKeybinding.isDown()) return;
// staticKeybinding.setDown(true);
//
// switch(staticKeybinding.getId()) {
// case KeybindRegistry.STATIC_DELETE_KEYFRAME:
// if(ReplayHandler.getSelectedKeyframe() != null) ReplayHandler.removeKeyframe(ReplayHandler.getSelectedKeyframe());
// break;
// }
// }
// }
//
// private void forwardCameraMovement(boolean forward, boolean backward, boolean left, boolean right, boolean up, boolean down) {
// if(forward && !backward) {
// ReplayHandler.getCameraEntity().setMovement(MoveDirection.FORWARD);
// } else if(backward && !forward) {
// ReplayHandler.getCameraEntity().setMovement(MoveDirection.BACKWARD);
// }
//
// if(left && !right) {
// ReplayHandler.getCameraEntity().setMovement(MoveDirection.LEFT);
// } else if(right && !left) {
// ReplayHandler.getCameraEntity().setMovement(MoveDirection.RIGHT);
// }
//
// if(up && !down) {
// ReplayHandler.getCameraEntity().setMovement(MoveDirection.UP);
// } else if(down && !up) {
// ReplayHandler.getCameraEntity().setMovement(MoveDirection.DOWN);
// }
// }
public void handleCustomKeybindings(KeyBinding kb, boolean found, int keyCode) {
//Custom registered handlers
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ADD_MARKER) && (kb.isPressed() || kb.getKeyCode() == keyCode)) {
if(ReplayHandler.isInReplay() && (mc.currentScreen == null || mc.currentScreen instanceof GuiMouseInput)) {
ReplayHandler.toggleMarker();
} else if(ConnectionEventHandler.isRecording()) {
ConnectionEventHandler.addMarker();
}
}
if(!ReplayHandler.isInReplay() || (mc.currentScreen != null && !(mc.currentScreen instanceof GuiMouseInput))) return;
if((kb.getKeyDescription().equals("key.chat") || kb.getKeyDescription().equals("key.command"))
&& (kb.isPressed() || kb.getKeyCode() == keyCode)) {
mc.displayGuiScreen(new GuiMouseInput(ReplayMod.overlay));
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_PLAY_PAUSE) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayMod.overlay.togglePlayPause();
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ROLL_CLOCKWISE) && (kb.isKeyDown() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayHandler.addCameraTilt(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) ? 0.2f : 1);
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ROLL_COUNTERCLOCKWISE) && (kb.isKeyDown() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayHandler.addCameraTilt(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) ? -0.2f : -1);
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_RESET_TILT) && (kb.isKeyDown() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayHandler.setCameraTilt(0);
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_THUMBNAIL) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !found && !ReplayHandler.isInPath()) {
TickAndRenderListener.requestScreenshot();
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_PLAYER_OVERVIEW) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !found && !ReplayHandler.isInPath()) {
PlayerHandler.openPlayerOverview();
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_LIGHTING) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayMod.replaySettings.setLightingEnabled(!ReplayMod.replaySettings.isLightingEnabled());
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_CLEAR_KEYFRAMES) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayHandler.resetKeyframes(false, ReplayMod.replaySettings.showClearKeyframesCallback());
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_SYNC_TIMELINE) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayHandler.syncTimeCursor(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT));
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_KEYFRAME_PRESETS) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
mc.displayGuiScreen(new GuiKeyframeRepository(ReplayHandler.getKeyframeRepository()));
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_PATH_PREVIEW) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayMod.replaySettings.setShowPathPreview(!ReplayMod.replaySettings.showPathPreview());
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ASSET_MANAGER) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
mc.displayGuiScreen(new GuiAssetManager());
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_OBJECT_MANAGER) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
mc.displayGuiScreen(new GuiObjectManager());
}
if(kb.getKeyDescription().equals(KeybindRegistry.KEY_TOGGLE_INTERPOLATION) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
ReplayMod.replaySettings.toggleInterpolation();
}
// TODO: Transfer to new key binding registry
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ADD_MARKER) && (kb.isPressed() || kb.getKeyCode() == keyCode)) {
// if(ReplayHandler.isInReplay() && (mc.currentScreen == null || mc.currentScreen instanceof GuiMouseInput)) {
// ReplayHandler.toggleMarker();
// }
// }
//
// if(!ReplayHandler.isInReplay() || (mc.currentScreen != null && !(mc.currentScreen instanceof GuiMouseInput))) return;
//
// if((kb.getKeyDescription().equals("key.chat") || kb.getKeyDescription().equals("key.command"))
// && (kb.isPressed() || kb.getKeyCode() == keyCode)) {
// mc.displayGuiScreen(new GuiMouseInput(ReplayMod.overlay));
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_PLAY_PAUSE) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayMod.overlay.togglePlayPause();
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ROLL_CLOCKWISE) && (kb.isKeyDown() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayHandler.addCameraTilt(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) ? 0.2f : 1);
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ROLL_COUNTERCLOCKWISE) && (kb.isKeyDown() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayHandler.addCameraTilt(Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) || Keyboard.isKeyDown(Keyboard.KEY_RCONTROL) ? -0.2f : -1);
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_RESET_TILT) && (kb.isKeyDown() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayHandler.setCameraTilt(0);
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_THUMBNAIL) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !found && !ReplayHandler.isInPath()) {
// TickAndRenderListener.requestScreenshot();
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_PLAYER_OVERVIEW) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !found && !ReplayHandler.isInPath()) {
// PlayerHandler.openPlayerOverview();
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_LIGHTING) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayMod.replaySettings.setLightingEnabled(!ReplayMod.replaySettings.isLightingEnabled());
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_CLEAR_KEYFRAMES) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayHandler.resetKeyframes(false, ReplayMod.replaySettings.showClearKeyframesCallback());
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_SYNC_TIMELINE) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayHandler.syncTimeCursor(Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT));
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_KEYFRAME_PRESETS) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// mc.displayGuiScreen(new GuiKeyframeRepository(ReplayHandler.getKeyframeRepository()));
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_PATH_PREVIEW) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayMod.replaySettings.setShowPathPreview(!ReplayMod.replaySettings.showPathPreview());
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_ASSET_MANAGER) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// mc.displayGuiScreen(new GuiAssetManager());
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_OBJECT_MANAGER) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// mc.displayGuiScreen(new GuiObjectManager());
// }
//
// if(kb.getKeyDescription().equals(KeybindRegistry.KEY_TOGGLE_INTERPOLATION) && (kb.isPressed() || kb.getKeyCode() == keyCode) && !ReplayHandler.isInPath()) {
// ReplayMod.replaySettings.toggleInterpolation();
// }
}
}

View File

@@ -6,8 +6,6 @@ import eu.crushedpixel.replaymod.assets.ReplayAsset;
import eu.crushedpixel.replaymod.gui.elements.*;
import eu.crushedpixel.replaymod.gui.elements.listeners.FileChooseListener;
import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
@@ -22,7 +20,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class GuiAssetManager extends GuiScreen implements GuiReplayOverlay.NoOverlay {
public class GuiAssetManager extends GuiScreen {
private String screenTitle;
@@ -43,8 +41,10 @@ public class GuiAssetManager extends GuiScreen implements GuiReplayOverlay.NoOve
private ReplayAsset currentAsset;
public GuiAssetManager() {
this.initialRepository = new AssetRepository(ReplayHandler.getAssetRepository());
this.assetRepository = ReplayHandler.getAssetRepository();
// TODO
initialRepository = null;
// this.initialRepository = new AssetRepository(ReplayHandler.getAssetRepository());
// this.assetRepository = ReplayHandler.getAssetRepository();
}
@Override

View File

@@ -1,35 +1,30 @@
package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.*;
import eu.crushedpixel.replaymod.gui.elements.listeners.NumberValueChangeListener;
import eu.crushedpixel.replaymod.holders.*;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.interpolation.KeyframeList;
import eu.crushedpixel.replaymod.interpolation.KeyframeValue;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import eu.crushedpixel.replaymod.utils.RoundUtils;
import eu.crushedpixel.replaymod.utils.TimestampUtils;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
import org.lwjgl.input.Keyboard;
import org.lwjgl.util.Point;
import java.awt.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public abstract class GuiEditKeyframe<T extends KeyframeValue> extends GuiScreen {
@SuppressWarnings("unchecked")
public static GuiEditKeyframe create(Keyframe kf) {
if(kf.getValue() instanceof Marker) return new GuiEditKeyframeMarker(kf);
if(kf.getValue() instanceof TimestampValue) return new GuiEditKeyframeTime(kf);
if(kf.getValue() instanceof SpectatorData) return new GuiEditKeyframeSpectator(kf);
if(kf.getValue() instanceof AdvancedPosition) return new GuiEditKeyframePosition(kf);
// TODO
// if(kf.getValue() instanceof TimestampValue) return new GuiEditKeyframeTime(kf);
// if(kf.getValue() instanceof SpectatorData) return new GuiEditKeyframeSpectator(kf);
// if(kf.getValue() instanceof AdvancedPosition) return new GuiEditKeyframePosition(kf);
throw new UnsupportedOperationException("Keyframe type unknown: " + kf);
}
@@ -156,13 +151,14 @@ public abstract class GuiEditKeyframe<T extends KeyframeValue> extends GuiScreen
@Override
public void onGuiClosed() {
if(!save) {
ReplayHandler.removeKeyframe(keyframe);
ReplayHandler.addKeyframe(keyframeBackup);
ReplayHandler.selectKeyframe(keyframeBackup);
}
ReplayHandler.fireKeyframesModifyEvent();
Keyboard.enableRepeatEvents(false);
// TODO
// if(!save) {
// ReplayHandler.removeKeyframe(keyframe);
// ReplayHandler.addKeyframe(keyframeBackup);
// ReplayHandler.selectKeyframe(keyframeBackup);
// }
// ReplayHandler.fireKeyframesModifyEvent();
// Keyboard.enableRepeatEvents(false);
}
@Override
@@ -218,300 +214,301 @@ public abstract class GuiEditKeyframe<T extends KeyframeValue> extends GuiScreen
protected void drawScreen0() {}
private static class GuiEditKeyframeMarker extends GuiEditKeyframe<Marker> {
private GuiAdvancedTextField markerNameInput;
public GuiEditKeyframeMarker(Keyframe<Marker> keyframe) {
super(keyframe, ReplayHandler.getMarkerKeyframes());
}
@Override
public void initGui() {
super.initGui();
if (!initialized) {
String name = keyframe.getValue().getName();
if (name == null) name = "";
markerNameInput = new GuiAdvancedTextField(fontRendererObj, 0, 0, 200, 20);
markerNameInput.hint = I18n.format("replaymod.gui.editkeyframe.markername");
markerNameInput.setText(name);
inputs.addPart(markerNameInput);
new KeyframeValueChangeListener(this);
}
markerNameInput.xPosition = width/2 - 100;
markerNameInput.yPosition = height/2-10;
initialized = true;
}
@Override
public void onGuiClosed() {
keyframe.getValue().setName(markerNameInput.getText().trim());
super.onGuiClosed();
}
}
private static class GuiEditKeyframeTime extends GuiEditKeyframe<TimestampValue> {
private GuiNumberInput kfMin, kfSec, kfMs;
public GuiEditKeyframeTime(Keyframe<TimestampValue> keyframe) {
super(keyframe, ReplayHandler.getTimeKeyframes());
screenTitle = I18n.format("replaymod.gui.editkeyframe.title.time");
}
@Override
public void initGui() {
super.initGui();
if (!initialized) {
int time = keyframe.getValue().asInt();
kfMin = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 30, 0d, null, (double)TimestampUtils.timestampToWholeMinutes(time), false, "", 1);
kfSec = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 25, 0d, 59d, (double)TimestampUtils.getSecondsFromTimestamp(time), false, "", 1);
kfMs = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 35, 0d, 999d, (double)TimestampUtils.getMillisecondsFromTimestamp(time), false, "", 1);
inputs.addPart(kfMin);
inputs.addPart(kfSec);
inputs.addPart(kfMs);
KeyframeValueChangeListener listener = new KeyframeValueChangeListener(this) {
@Override
public void onValueChange(double value) {
keyframe.setValue(new TimestampValue(TimestampUtils.calculateTimestamp(
kfMin.getIntValue(), kfSec.getIntValue(), kfMs.getIntValue())));
super.onValueChange(value);
}
};
kfMin.addValueChangeListener(listener);
kfSec.addValueChangeListener(listener);
kfMs.addValueChangeListener(listener);
}
kfMin.xPosition = min.xPosition;
kfSec.xPosition = sec.xPosition;
kfMs.xPosition = ms.xPosition;
kfMin.yPosition = kfSec.yPosition = kfMs.yPosition = min.yPosition - 10 - 20;
initialized = true;
}
@Override
protected void drawScreen0() {
drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.timestamp")+":", (width-w3)/2, kfMin.yPosition + 7, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.minutes"), kfMin.xPosition + kfMin.width + 5, kfMin.yPosition + 7, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.seconds"), kfSec.xPosition + kfSec.width + 5, kfSec.yPosition + 7, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.milliseconds"), kfMs.xPosition + kfMs.width + 5, kfMs.yPosition + 7, Color.WHITE.getRGB());
}
}
private static class GuiEditKeyframePosition extends GuiEditKeyframe<AdvancedPosition> {
private GuiNumberInput xCoord, yCoord, zCoord, pitch, yaw, roll;
private ComposedElement posInputs;
public GuiEditKeyframePosition(Keyframe<AdvancedPosition> keyframe) {
super(keyframe, ReplayHandler.getPositionKeyframes());
screenTitle = I18n.format("replaymod.gui.editkeyframe.title.pos");
}
@Override
public void initGui() {
super.initGui();
if (!initialized) {
AdvancedPosition pos = keyframe.getValue();
xCoord = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getX()), true);
yCoord = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getY()), true);
zCoord = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getZ()), true);
yaw = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getYaw()), true);
pitch = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, -90d, 90d, RoundUtils.round2Decimals(pos.getPitch()), true);
roll = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getRoll()), true);
posInputs = new ComposedElement(xCoord, yCoord, zCoord, yaw, pitch, roll);
inputs.addPart(posInputs);
KeyframeValueChangeListener listener = new KeyframeValueChangeListener(this) {
@Override
public void onValueChange(double value) {
keyframe.setValue(new AdvancedPosition(xCoord.getPreciseValue(), yCoord.getPreciseValue(),
zCoord.getPreciseValue(), new Float(pitch.getPreciseValue()), (float) yaw.getPreciseValue(),
(float) roll.getPreciseValue()));
super.onValueChange(value);
}
};
xCoord.addValueChangeListener(listener);
yCoord.addValueChangeListener(listener);
zCoord.addValueChangeListener(listener);
pitch.addValueChangeListener(listener);
yaw.addValueChangeListener(listener);
roll.addValueChangeListener(listener);
}
int w = Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.xpos")),
Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.ypos")),
fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.zpos"))));
w2 = Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.camyaw")),
Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.campitch")),
fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.camroll"))));
totalWidth = w +100+w2+100+5+5+10;
left = (this.width - totalWidth)/2;
int x = w + left + 5;
int i = 0;
for(GuiElement input : posInputs.getParts()) {
if(input instanceof GuiTextField) {
GuiTextField textField = (GuiTextField)input;
textField.xPosition = i < 3 ? x : left+totalWidth-100;
textField.yPosition = i < 3 ? virtualY + 20 + i*30 : virtualY + 20 + (i-3)*30;
i++;
}
}
initialized = true;
}
@Override
protected void drawScreen0() {
if (keyframe.getValue() instanceof SpectatorData) return;
drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.xpos"), left, virtualY + 27, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.ypos"), left, virtualY + 57, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.zpos"), left, virtualY + 87, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.camyaw"), left + totalWidth - 100 - 5 - w2, virtualY + 27, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.campitch"), left + totalWidth - 100 - 5 - w2, virtualY + 57, Color.WHITE.getRGB());
drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.camroll"), left + totalWidth - 100 - 5 - w2, virtualY + 87, Color.WHITE.getRGB());
}
}
private static class GuiEditKeyframeSpectator extends GuiEditKeyframe<AdvancedPosition> {
private GuiToggleButton perspectiveButton;
private GuiString shoulderDistanceString, shoulderPitchString, shoulderYawString, shoulderSmoothnessString;
private GuiDraggingNumberInput shoulderDistanceInput, shoulderPitchOffsetInput,
shoulderYawOffsetInput, shoulderSmoothnessInput;
private ComposedElement spectatorCamSettings;
private ComposedElement shoulderCamSettings;
private DelegatingElement perspectiveSettings = new DelegatingElement() {
@Override
public GuiElement delegate() {
switch(perspectiveButton.getValue()) {
case 0:
return spectatorCamSettings;
case 1:
return shoulderCamSettings;
default:
return null;
}
}
};
public GuiEditKeyframeSpectator(Keyframe<AdvancedPosition> keyframe) {
super(keyframe, ReplayHandler.getPositionKeyframes());
screenTitle = I18n.format("replaymod.gui.editkeyframe.title.spec");
}
@Override
public void initGui() {
super.initGui();
if (!initialized) {
SpectatorData data = (SpectatorData)keyframe.getValue();
perspectiveButton = new GuiToggleButton(0, 0, 0, 200, 20, I18n.format("replaymod.gui.editkeyframe.spec.method")+": ", new String[]{
I18n.format("replaymod.gui.editkeyframe.spec.method.firstperson"),
I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder")});
perspectiveButton.setValue(Arrays.asList(SpectatorData.SpectatingMethod.values()).indexOf(data.getSpectatingMethod()));
spectatorCamSettings = new ComposedElement();
//create elements in shoulderCamSettings
shoulderDistanceString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.distance"));
shoulderPitchString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.pitch"));
shoulderYawString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.yaw"));
shoulderSmoothnessString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.smoothness"));
shoulderDistanceInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, 0d, 30d, data.getThirdPersonInfo().shoulderCamDistance, true, "", 0.1);
shoulderPitchOffsetInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, -90d, 90d, data.getThirdPersonInfo().shoulderCamPitchOffset, false, "°", 1);
shoulderYawOffsetInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, null, null, data.getThirdPersonInfo().shoulderCamYawOffset, false, "°", 1);
shoulderSmoothnessInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, 0.1d, 3d, data.getThirdPersonInfo().shoulderCamSmoothness, true, "", 0.1);
shoulderCamSettings = new ComposedElement(
shoulderDistanceString, shoulderDistanceInput,
shoulderPitchString, shoulderPitchOffsetInput,
shoulderYawString, shoulderYawOffsetInput,
shoulderSmoothnessString, shoulderSmoothnessInput);
inputs.addPart(new ComposedElement(perspectiveButton, perspectiveSettings));
}
perspectiveButton.xPosition = (this.width-perspectiveButton.width())/2;
perspectiveButton.yPosition = this.virtualY + 20;
int verticalSpacing = 20 + 5;
int totalWidth = 300;
int elementWidth = 145;
int horizontalSpacing = 10;
int y = perspectiveButton.yPos() + verticalSpacing;
int i = 0;
for(GuiElement el : shoulderCamSettings.getParts()) {
el.xPos((width-totalWidth)/2 + (i%2)*(elementWidth + horizontalSpacing));
el.width(elementWidth);
el.yPos(y + ((i+1)%2)*7);
if(i%2 == 1) {
y += verticalSpacing;
}
i++;
}
initialized = true;
}
@Override
public void onGuiClosed() {
SpectatorData data = (SpectatorData)keyframe.getValue();
data.setSpectatingMethod(SpectatorData.SpectatingMethod.values()[perspectiveButton.getValue()]);
data.getThirdPersonInfo().shoulderCamDistance = shoulderDistanceInput.getPreciseValue();
data.getThirdPersonInfo().shoulderCamPitchOffset = shoulderPitchOffsetInput.getIntValue();
data.getThirdPersonInfo().shoulderCamYawOffset = shoulderYawOffsetInput.getIntValue();
data.getThirdPersonInfo().shoulderCamSmoothness = shoulderSmoothnessInput.getPreciseValue();
super.onGuiClosed();
}
}
private static class KeyframeValueChangeListener implements NumberValueChangeListener {
private GuiEditKeyframe parent;
public KeyframeValueChangeListener(GuiEditKeyframe parent) {
this.parent = parent;
parent.min.addValueChangeListener(this);
parent.sec.addValueChangeListener(this);
parent.ms.addValueChangeListener(this);
}
@Override
public void onValueChange(double value) {
int realTimestamp = TimestampUtils.calculateTimestamp(parent.min.getIntValue(), parent.sec.getIntValue(), parent.ms.getIntValue());
parent.keyframe.setRealTimestamp(realTimestamp);
ReplayHandler.fireKeyframesModifyEvent();
}
}
// TODO
// private static class GuiEditKeyframeMarker extends GuiEditKeyframe<Marker> {
// private GuiAdvancedTextField markerNameInput;
//
// public GuiEditKeyframeMarker(Keyframe<Marker> keyframe) {
// super(keyframe, ReplayHandler.getMarkerKeyframes());
// }
//
// @Override
// public void initGui() {
// super.initGui();
//
// if (!initialized) {
// String name = keyframe.getValue().getName();
// if (name == null) name = "";
// markerNameInput = new GuiAdvancedTextField(fontRendererObj, 0, 0, 200, 20);
// markerNameInput.hint = I18n.format("replaymod.gui.editkeyframe.markername");
// markerNameInput.setText(name);
//
// inputs.addPart(markerNameInput);
//
// new KeyframeValueChangeListener(this);
// }
//
// markerNameInput.xPosition = width/2 - 100;
// markerNameInput.yPosition = height/2-10;
//
// initialized = true;
// }
//
// @Override
// public void onGuiClosed() {
// keyframe.getValue().setName(markerNameInput.getText().trim());
// super.onGuiClosed();
// }
// }
//
// private static class GuiEditKeyframeTime extends GuiEditKeyframe<TimestampValue> {
// private GuiNumberInput kfMin, kfSec, kfMs;
//
// public GuiEditKeyframeTime(Keyframe<TimestampValue> keyframe) {
// super(keyframe, ReplayHandler.getTimeKeyframes());
// screenTitle = I18n.format("replaymod.gui.editkeyframe.title.time");
// }
//
// @Override
// public void initGui() {
// super.initGui();
//
// if (!initialized) {
// int time = keyframe.getValue().asInt();
//
// kfMin = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 30, 0d, null, (double)TimestampUtils.timestampToWholeMinutes(time), false, "", 1);
// kfSec = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 25, 0d, 59d, (double)TimestampUtils.getSecondsFromTimestamp(time), false, "", 1);
// kfMs = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 35, 0d, 999d, (double)TimestampUtils.getMillisecondsFromTimestamp(time), false, "", 1);
//
// inputs.addPart(kfMin);
// inputs.addPart(kfSec);
// inputs.addPart(kfMs);
//
// KeyframeValueChangeListener listener = new KeyframeValueChangeListener(this) {
// @Override
// public void onValueChange(double value) {
// keyframe.setValue(new TimestampValue(TimestampUtils.calculateTimestamp(
// kfMin.getIntValue(), kfSec.getIntValue(), kfMs.getIntValue())));
//
// super.onValueChange(value);
// }
// };
//
// kfMin.addValueChangeListener(listener);
// kfSec.addValueChangeListener(listener);
// kfMs.addValueChangeListener(listener);
// }
//
// kfMin.xPosition = min.xPosition;
// kfSec.xPosition = sec.xPosition;
// kfMs.xPosition = ms.xPosition;
//
// kfMin.yPosition = kfSec.yPosition = kfMs.yPosition = min.yPosition - 10 - 20;
//
// initialized = true;
// }
//
// @Override
// protected void drawScreen0() {
// drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.timestamp")+":", (width-w3)/2, kfMin.yPosition + 7, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.minutes"), kfMin.xPosition + kfMin.width + 5, kfMin.yPosition + 7, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.seconds"), kfSec.xPosition + kfSec.width + 5, kfSec.yPosition + 7, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.milliseconds"), kfMs.xPosition + kfMs.width + 5, kfMs.yPosition + 7, Color.WHITE.getRGB());
// }
//
// }
//
// private static class GuiEditKeyframePosition extends GuiEditKeyframe<AdvancedPosition> {
// private GuiNumberInput xCoord, yCoord, zCoord, pitch, yaw, roll;
// private ComposedElement posInputs;
//
// public GuiEditKeyframePosition(Keyframe<AdvancedPosition> keyframe) {
// super(keyframe, ReplayHandler.getPositionKeyframes());
// screenTitle = I18n.format("replaymod.gui.editkeyframe.title.pos");
// }
//
// @Override
// public void initGui() {
// super.initGui();
//
// if (!initialized) {
// AdvancedPosition pos = keyframe.getValue();
// xCoord = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getX()), true);
// yCoord = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getY()), true);
// zCoord = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getZ()), true);
// yaw = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getYaw()), true);
// pitch = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, -90d, 90d, RoundUtils.round2Decimals(pos.getPitch()), true);
// roll = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 100, null, null, RoundUtils.round2Decimals(pos.getRoll()), true);
//
// posInputs = new ComposedElement(xCoord, yCoord, zCoord, yaw, pitch, roll);
// inputs.addPart(posInputs);
//
// KeyframeValueChangeListener listener = new KeyframeValueChangeListener(this) {
// @Override
// public void onValueChange(double value) {
// keyframe.setValue(new AdvancedPosition(xCoord.getPreciseValue(), yCoord.getPreciseValue(),
// zCoord.getPreciseValue(), new Float(pitch.getPreciseValue()), (float) yaw.getPreciseValue(),
// (float) roll.getPreciseValue()));
//
// super.onValueChange(value);
// }
// };
//
// xCoord.addValueChangeListener(listener);
// yCoord.addValueChangeListener(listener);
// zCoord.addValueChangeListener(listener);
// pitch.addValueChangeListener(listener);
// yaw.addValueChangeListener(listener);
// roll.addValueChangeListener(listener);
// }
//
// int w = Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.xpos")),
// Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.ypos")),
// fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.zpos"))));
// w2 = Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.camyaw")),
// Math.max(fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.campitch")),
// fontRendererObj.getStringWidth(I18n.format("replaymod.gui.editkeyframe.camroll"))));
//
// totalWidth = w +100+w2+100+5+5+10;
// left = (this.width - totalWidth)/2;
//
// int x = w + left + 5;
// int i = 0;
// for(GuiElement input : posInputs.getParts()) {
// if(input instanceof GuiTextField) {
// GuiTextField textField = (GuiTextField)input;
// textField.xPosition = i < 3 ? x : left+totalWidth-100;
// textField.yPosition = i < 3 ? virtualY + 20 + i*30 : virtualY + 20 + (i-3)*30;
// i++;
// }
// }
//
// initialized = true;
// }
//
// @Override
// protected void drawScreen0() {
// if (keyframe.getValue() instanceof SpectatorData) return;
// drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.xpos"), left, virtualY + 27, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.ypos"), left, virtualY + 57, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.zpos"), left, virtualY + 87, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.camyaw"), left + totalWidth - 100 - 5 - w2, virtualY + 27, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.campitch"), left + totalWidth - 100 - 5 - w2, virtualY + 57, Color.WHITE.getRGB());
// drawString(fontRendererObj, I18n.format("replaymod.gui.editkeyframe.camroll"), left + totalWidth - 100 - 5 - w2, virtualY + 87, Color.WHITE.getRGB());
// }
//
// }
//
// private static class GuiEditKeyframeSpectator extends GuiEditKeyframe<AdvancedPosition> {
// private GuiToggleButton perspectiveButton;
//
// private GuiString shoulderDistanceString, shoulderPitchString, shoulderYawString, shoulderSmoothnessString;
// private GuiDraggingNumberInput shoulderDistanceInput, shoulderPitchOffsetInput,
// shoulderYawOffsetInput, shoulderSmoothnessInput;
//
// private ComposedElement spectatorCamSettings;
// private ComposedElement shoulderCamSettings;
//
// private DelegatingElement perspectiveSettings = new DelegatingElement() {
// @Override
// public GuiElement delegate() {
// switch(perspectiveButton.getValue()) {
// case 0:
// return spectatorCamSettings;
// case 1:
// return shoulderCamSettings;
// default:
// return null;
// }
// }
// };
//
// public GuiEditKeyframeSpectator(Keyframe<AdvancedPosition> keyframe) {
// super(keyframe, ReplayHandler.getPositionKeyframes());
// screenTitle = I18n.format("replaymod.gui.editkeyframe.title.spec");
// }
//
// @Override
// public void initGui() {
// super.initGui();
//
// if (!initialized) {
// SpectatorData data = (SpectatorData)keyframe.getValue();
//
// perspectiveButton = new GuiToggleButton(0, 0, 0, 200, 20, I18n.format("replaymod.gui.editkeyframe.spec.method")+": ", new String[]{
// I18n.format("replaymod.gui.editkeyframe.spec.method.firstperson"),
// I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder")});
//
// perspectiveButton.setValue(Arrays.asList(SpectatorData.SpectatingMethod.values()).indexOf(data.getSpectatingMethod()));
//
// spectatorCamSettings = new ComposedElement();
//
// //create elements in shoulderCamSettings
// shoulderDistanceString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.distance"));
// shoulderPitchString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.pitch"));
// shoulderYawString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.yaw"));
// shoulderSmoothnessString = new GuiString(0, 0, Color.WHITE, I18n.format("replaymod.gui.editkeyframe.spec.method.shoulder.smoothness"));
//
// shoulderDistanceInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, 0d, 30d, data.getThirdPersonInfo().shoulderCamDistance, true, "", 0.1);
// shoulderPitchOffsetInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, -90d, 90d, data.getThirdPersonInfo().shoulderCamPitchOffset, false, "°", 1);
// shoulderYawOffsetInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, null, null, data.getThirdPersonInfo().shoulderCamYawOffset, false, "°", 1);
// shoulderSmoothnessInput = new GuiDraggingNumberInput(fontRendererObj, 0, 0, 0, 0.1d, 3d, data.getThirdPersonInfo().shoulderCamSmoothness, true, "", 0.1);
//
// shoulderCamSettings = new ComposedElement(
// shoulderDistanceString, shoulderDistanceInput,
// shoulderPitchString, shoulderPitchOffsetInput,
// shoulderYawString, shoulderYawOffsetInput,
// shoulderSmoothnessString, shoulderSmoothnessInput);
//
// inputs.addPart(new ComposedElement(perspectiveButton, perspectiveSettings));
// }
//
// perspectiveButton.xPosition = (this.width-perspectiveButton.width())/2;
// perspectiveButton.yPosition = this.virtualY + 20;
//
// int verticalSpacing = 20 + 5;
// int totalWidth = 300;
// int elementWidth = 145;
// int horizontalSpacing = 10;
//
// int y = perspectiveButton.yPos() + verticalSpacing;
//
// int i = 0;
// for(GuiElement el : shoulderCamSettings.getParts()) {
// el.xPos((width-totalWidth)/2 + (i%2)*(elementWidth + horizontalSpacing));
// el.width(elementWidth);
//
// el.yPos(y + ((i+1)%2)*7);
//
// if(i%2 == 1) {
// y += verticalSpacing;
// }
// i++;
// }
//
// initialized = true;
// }
//
// @Override
// public void onGuiClosed() {
// SpectatorData data = (SpectatorData)keyframe.getValue();
// data.setSpectatingMethod(SpectatorData.SpectatingMethod.values()[perspectiveButton.getValue()]);
// data.getThirdPersonInfo().shoulderCamDistance = shoulderDistanceInput.getPreciseValue();
// data.getThirdPersonInfo().shoulderCamPitchOffset = shoulderPitchOffsetInput.getIntValue();
// data.getThirdPersonInfo().shoulderCamYawOffset = shoulderYawOffsetInput.getIntValue();
// data.getThirdPersonInfo().shoulderCamSmoothness = shoulderSmoothnessInput.getPreciseValue();
// super.onGuiClosed();
// }
// }
//
// private static class KeyframeValueChangeListener implements NumberValueChangeListener {
//
// private GuiEditKeyframe parent;
//
// public KeyframeValueChangeListener(GuiEditKeyframe parent) {
// this.parent = parent;
//
// parent.min.addValueChangeListener(this);
// parent.sec.addValueChangeListener(this);
// parent.ms.addValueChangeListener(this);
// }
//
// @Override
// public void onValueChange(double value) {
// int realTimestamp = TimestampUtils.calculateTimestamp(parent.min.getIntValue(), parent.sec.getIntValue(), parent.ms.getIntValue());
// parent.keyframe.setRealTimestamp(realTimestamp);
//
// ReplayHandler.fireKeyframesModifyEvent();
// }
// }
}

View File

@@ -1,13 +1,9 @@
package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.GuiEntryList;
import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.KeyframeSet;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.CameraPathValidator;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
@@ -22,7 +18,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GuiKeyframeRepository extends GuiScreen implements GuiReplayOverlay.NoOverlay {
public class GuiKeyframeRepository extends GuiScreen {
private boolean initialized = false;
@@ -133,39 +129,40 @@ public class GuiKeyframeRepository extends GuiScreen implements GuiReplayOverlay
@Override
public void actionPerformed(GuiButton button) {
if(!button.enabled) return;
switch(button.id) {
case GuiConstants.KEYFRAME_REPOSITORY_ADD_BUTTON:
List<Keyframe> kfs = new ArrayList<Keyframe>(ReplayHandler.getAllKeyframes());
Keyframe[] keyframes = kfs.toArray(new Keyframe[ReplayHandler.getAllKeyframes().size()]);
KeyframeSet newSet = new KeyframeSet(I18n.format("replaymod.gui.keyframerepository.preset.defaultname"), keyframes, ReplayHandler.getCustomImageObjects());
try {
CameraPathValidator.validateCameraPath(ReplayHandler.getPositionKeyframes(), ReplayHandler.getTimeKeyframes());
} catch(CameraPathValidator.InvalidCameraPathException e) {
message = e.getLocalizedMessage();
break;
}
if(keyframeSetList.getCopyOfElements().contains(newSet)) {
message = I18n.format("replaymod.gui.keyframerepository.duplicate");
break;
}
message = null;
keyframeSetList.addElement(newSet);
keyframeSetList.setSelectionIndex(keyframeSetList.getEntryCount()-1);
break;
case GuiConstants.KEYFRAME_REPOSITORY_REMOVE_BUTTON:
keyframeSetList.removeElement(keyframeSetList.getSelectionIndex());
break;
case GuiConstants.KEYFRAME_REPOSITORY_LOAD_BUTTON:
ReplayHandler.useKeyframePreset(keyframeSetList.getElement(keyframeSetList.getSelectionIndex()));
saveOnQuit();
mc.displayGuiScreen(null);
break;
}
// TODO
// if(!button.enabled) return;
// switch(button.id) {
// case GuiConstants.KEYFRAME_REPOSITORY_ADD_BUTTON:
// List<Keyframe> kfs = new ArrayList<Keyframe>(ReplayHandler.getAllKeyframes());
//
// Keyframe[] keyframes = kfs.toArray(new Keyframe[ReplayHandler.getAllKeyframes().size()]);
// KeyframeSet newSet = new KeyframeSet(I18n.format("replaymod.gui.keyframerepository.preset.defaultname"), keyframes, ReplayHandler.getCustomImageObjects());
//
// try {
// CameraPathValidator.validateCameraPath(ReplayHandler.getPositionKeyframes(), ReplayHandler.getTimeKeyframes());
// } catch(CameraPathValidator.InvalidCameraPathException e) {
// message = e.getLocalizedMessage();
// break;
// }
//
// if(keyframeSetList.getCopyOfElements().contains(newSet)) {
// message = I18n.format("replaymod.gui.keyframerepository.duplicate");
// break;
// }
// message = null;
//
// keyframeSetList.addElement(newSet);
// keyframeSetList.setSelectionIndex(keyframeSetList.getEntryCount()-1);
// break;
// case GuiConstants.KEYFRAME_REPOSITORY_REMOVE_BUTTON:
// keyframeSetList.removeElement(keyframeSetList.getSelectionIndex());
// break;
// case GuiConstants.KEYFRAME_REPOSITORY_LOAD_BUTTON:
// ReplayHandler.useKeyframePreset(keyframeSetList.getElement(keyframeSetList.getSelectionIndex()));
// saveOnQuit();
// mc.displayGuiScreen(null);
// break;
// }
}
@Override
@@ -241,7 +238,8 @@ public class GuiKeyframeRepository extends GuiScreen implements GuiReplayOverlay
if(initialKeyframeSets.equals(copy)) return;
this.keyframeRepository = copy.toArray(new KeyframeSet[copy.size()]);
ReplayHandler.setKeyframeRepository(keyframeRepository, true);
// TODO
// ReplayHandler.setKeyframeRepository(keyframeRepository, true);
}
@Override

View File

@@ -1,53 +0,0 @@
package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import org.lwjgl.input.Mouse;
import java.io.IOException;
public class GuiMouseInput extends GuiScreen {
private final Minecraft mc = Minecraft.getMinecraft();
private final GuiReplayOverlay overlay;
private boolean shouldClose = false;
public GuiMouseInput(GuiReplayOverlay overlay) {
this.overlay = overlay;
Mouse.setGrabbed(false);
Mouse.setCursorPosition(mc.displayWidth/2, mc.displayHeight/2);
if(mc.currentScreen instanceof GuiMouseInput) {
shouldClose = true;
}
}
@Override
public void initGui() {
if(shouldClose) mc.displayGuiScreen(null);
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
overlay.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
protected void mouseReleased(int mouseX, int mouseY, int state) {
overlay.mouseReleased(mouseX, mouseY, state);
}
@Override
protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) {
overlay.mouseDrag(mouseX, mouseY, clickedMouseButton);
}
@Override
public void onGuiClosed() {
ReplayMod.overlay.closeToolbar();
}
}

View File

@@ -1,347 +1,314 @@
package eu.crushedpixel.replaymod.gui;
import com.mojang.realmsclient.util.Pair;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.holders.PlayerVisibility;
import eu.crushedpixel.replaymod.registry.PlayerHandler;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import eu.crushedpixel.replaymod.utils.SkinProvider;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EnumPlayerModelParts;
import net.minecraft.potion.Potion;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.client.config.GuiCheckBox;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
public class GuiPlayerOverview extends GuiScreen implements GuiReplayOverlay.NoOverlay {
public class GuiPlayerOverview extends GuiScreen {
public static boolean defaultSave = false;
private List<Pair<EntityPlayer, ResourceLocation>> players;
private List<GuiCheckBox> checkBoxes;
private GuiCheckBox hideAllBox, showAllBox;
private GuiCheckBox rememberHidden;
private boolean initialized = false;
private int playerCount;
private int upperPlayer = 0;
private int lowerBound;
private boolean drag = false;
private int lastY = 0;
private int fitting = 0;
private final Minecraft mc = Minecraft.getMinecraft();
private final String screenTitle = I18n.format("replaymod.input.playeroverview");
private final Set<UUID> initialHiddenPlayers;
public GuiPlayerOverview(List<EntityPlayer> players) {
initialHiddenPlayers = new HashSet<UUID>(PlayerHandler.getHiddenPlayers());
Collections.sort(players, new PlayerComparator());
this.players = new ArrayList<Pair<EntityPlayer, ResourceLocation>>();
this.checkBoxes = new ArrayList<GuiCheckBox>();
for(final EntityPlayer p : players) {
final ResourceLocation loc = SkinProvider.getResourceLocationForPlayerUUID(p.getUniqueID());
this.players.add(Pair.of(p, loc));
}
playerCount = players.size();
ReplayMod.replaySender.setReplaySpeed(0);
}
private boolean isSpectator(EntityPlayer e) {
return e.isInvisible() && e.getActivePotionEffect(Potion.invisibility) == null;
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton)
throws IOException {
if(fitting < playerCount) {
float visiblePerc = (float) fitting / (float) playerCount;
int h = this.height - 32 - 32;
int offset = Math.round((upperPlayer / (fitting)) * visiblePerc * h);
int lower = Math.round(32 + offset + (h * visiblePerc)) - 2;
int k2 = (int) (this.width * 0.3);
if(mouseX >= k2 - 16 && mouseX <= k2 - 12 && mouseY >= 32 - 2 + offset && mouseY <= lower) {
lastY = mouseY;
drag = true;
return;
}
}
int k2 = (int) (this.width * 0.3);
if(mouseX >= k2 && mouseX <= (this.width * 0.6) && mouseY >= upperBound && mouseY <= lowerBound) {
int off = mouseY - upperBound;
int p = (off / 21) + upperPlayer;
ReplayHandler.spectateEntity(players.get(p).first());
mc.displayGuiScreen(null);
}
super.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
protected void mouseClickMove(int mouseX, int mouseY,
int clickedMouseButton, long timeSinceLastClick) {
if(drag) {
float step = 1f / (float) playerCount;
int diff = mouseY - lastY;
int h = this.height - 32 - 32;
float percDiff = (float) diff / (float) h;
if(Math.abs(percDiff) > Math.abs(step)) {
int s = (int) (percDiff / step);
lastY = mouseY;
upperPlayer += s;
if(upperPlayer > playerCount - fitting) {
upperPlayer = playerCount - fitting;
} else if(upperPlayer < 0) {
upperPlayer = 0;
}
}
}
super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
}
@Override
protected void mouseReleased(int mouseX, int mouseY, int state) {
drag = false;
for(GuiCheckBox checkBox : checkBoxes) {
checkBox.mouseReleased(mouseX, mouseY);
}
super.mouseReleased(mouseX, mouseY, state);
}
@Override
public void initGui() {
upperPlayer = 0;
lowerBound = this.height - 10;
@SuppressWarnings("unchecked")
List<GuiButton> buttonList = this.buttonList;
int i = 0;
for(GuiCheckBox checkBox : checkBoxes) {
checkBox.xPosition = (int)(this.width*0.7)-5;
buttonList.add(checkBox);
i++;
if(i >= fitting) break;
}
if(!initialized) {
hideAllBox = new GuiCheckBox(GuiConstants.PLAYER_OVERVIEW_HIDE_ALL, 0, 0, "", false);
showAllBox = new GuiCheckBox(GuiConstants.PLAYER_OVERVIEW_SHOW_ALL, 0, 0, "", true);
rememberHidden = new GuiCheckBox(GuiConstants.PLAYER_OVERVIEW_REMEMBER, 0, 0, I18n.format("replaymod.gui.playeroverview.remembersettings"), defaultSave);
}
hideAllBox.xPosition = (int)(this.width*0.7)-5;
showAllBox.xPosition = (int)(this.width*0.7)-20;
hideAllBox.yPosition = showAllBox.yPosition = 45;
rememberHidden.xPosition = (int)(this.width*0.3);
rememberHidden.yPosition = 45;
buttonList.add(hideAllBox);
buttonList.add(showAllBox);
buttonList.add(rememberHidden);
initialized = true;
}
@Override
protected void actionPerformed(GuiButton button) throws IOException {
if(button == showAllBox) {
showAllBox.setIsChecked(true);
for(Pair<EntityPlayer, ResourceLocation> p : players) {
PlayerHandler.showPlayer(p.first());
}
} else if(button == hideAllBox) {
hideAllBox.setIsChecked(false);
for(Pair<EntityPlayer, ResourceLocation> p : players) {
PlayerHandler.hidePlayer(p.first());
}
}
if(!(button instanceof GuiCheckBox)) return;
if(button.id >= fitting) return;
if(!checkBoxes.contains(button)) return;
PlayerHandler.setIsVisible(players.get(upperPlayer + button.id).first(), ((GuiCheckBox)button).isChecked());
}
private static final int upperBound = 65;
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
this.drawCenteredString(fontRendererObj, screenTitle, this.width / 2, 5, Color.WHITE.getRGB());
int k2 = (int)(this.width * 0.3);
int l2 = upperBound;
drawGradientRect(k2 - 20, 20, (int) (this.width * 0.7) + 20, this.height - 30 - 2 + 10, -1072689136, -804253680);
drawString(fontRendererObj, I18n.format("replaymod.gui.playeroverview.spectate"), k2 - 10, 30, Color.WHITE.getRGB());
String visibleString = I18n.format("replaymod.gui.playeroverview.visible");
drawString(fontRendererObj, visibleString, (int) (this.width * 0.7) + 10 - fontRendererObj.getStringWidth(visibleString), 30, Color.WHITE.getRGB());
fitting = 0;
int sk = 0;
for(Pair<EntityPlayer, ResourceLocation> p : players) {
if(sk < upperPlayer) {
sk++;
continue;
}
boolean spec = isSpectator(p.first());
this.drawString(fontRendererObj, p.first().getName(), k2 + 16 + 5, l2 + 8 - (fontRendererObj.FONT_HEIGHT / 2),
spec ? Color.DARK_GRAY.getRGB() : Color.WHITE.getRGB());
mc.getTextureManager().bindTexture(p.second());
drawScaledCustomSizeModalRect(k2, l2, 8.0F, 8.0F, 8, 8, 16, 16, 64.0F, 64.0F);
if(p.first().func_175148_a(EnumPlayerModelParts.HAT))
Gui.drawScaledCustomSizeModalRect(k2, l2, 40.0F, 8.0F, 8, 8, 16, 16, 64.0F, 64.0F);
GlStateManager.resetColor();
if(fitting >= checkBoxes.size()) {
checkBoxes.add(new GuiCheckBox(checkBoxes.size(), (int)(this.width*0.7)-5, l2+3, "", true));
@SuppressWarnings("unchecked")
List<GuiButton> buttonList = this.buttonList;
buttonList.add(checkBoxes.get(checkBoxes.size() - 1));
}
checkBoxes.get(fitting).setIsChecked(!PlayerHandler.isHidden(p.first().getUniqueID()));
l2 += 16 + 5;
fitting++;
if(l2 + 32 > lowerBound) {
break;
}
}
int dw = Mouse.getDWheel();
if(dw > 0) {
dw = -1;
} else if(dw < 0) {
dw = 1;
}
upperPlayer = Math.max(Math.min(upperPlayer + dw, playerCount - fitting), 0);
if(fitting < playerCount) {
float visiblePerc = ((float) fitting) / playerCount;
int barHeight = (int) (visiblePerc * (height - 32 - 32));
float posPerc = ((float) upperPlayer) / playerCount;
int barY = (int) (posPerc * (height - 32 - 32));
drawRect(k2 - 18, upperBound - 2, k2 - 10, this.height - 30 - 2, Color.BLACK.getRGB());
drawRect(k2 - 16, upperBound+2 - 2 + barY, k2 - 12, 30+2 - 1 + barY + barHeight, Color.LIGHT_GRAY.getRGB());
}
int i = 0;
for(GuiCheckBox checkBox : checkBoxes) {
checkBox.drawButton(mc, mouseX, mouseY);
i++;
if(i >= fitting) break;
}
hideAllBox.drawButton(mc, mouseX, mouseY);
showAllBox.drawButton(mc, mouseX, mouseY);
rememberHidden.drawButton(mc, mouseX, mouseY);
if(hideAllBox.isMouseOver()) {
ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.playeroverview.hideall"), this, Color.WHITE);
}
if(showAllBox.isMouseOver()) {
ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.playeroverview.showall"), this, Color.WHITE);
}
if(rememberHidden.isMouseOver()) {
ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.playeroverview.remembersettings.description"), this, Color.WHITE);
}
//this is necessary to reset the GL parameters for further GUI rendering
GlStateManager.enableBlend();
}
private PlayerVisibility getVisibilityInstance() {
Set<UUID> hidden = PlayerHandler.getHiddenPlayers();
return new PlayerVisibility(hidden.toArray(new UUID[hidden.size()]));
}
private void saveOnQuit() {
if(rememberHidden.isChecked()) {
if(initialHiddenPlayers.equals(PlayerHandler.getHiddenPlayers())) return;
try {
File f = File.createTempFile(ReplayFile.ENTRY_VISIBILITY, "json");
ReplayFileIO.write(getVisibilityInstance(), f);
ReplayMod.replayFileAppender.registerModifiedFile(f, ReplayFile.ENTRY_VISIBILITY, ReplayHandler.getReplayFile());
} catch(Exception e) {
e.printStackTrace();
}
} else {
if(initialHiddenPlayers.isEmpty()) return;
ReplayMod.replayFileAppender.registerModifiedFile(null, ReplayFile.ENTRY_VISIBILITY, ReplayHandler.getReplayFile());
}
}
@Override
public void keyTyped(char typedChar, int keyCode) throws IOException {
if(keyCode == Keyboard.KEY_ESCAPE) {
saveOnQuit();
super.keyTyped(typedChar, keyCode);
}
}
private class PlayerComparator implements Comparator<EntityPlayer> {
@Override
public int compare(EntityPlayer o1, EntityPlayer o2) {
if(isSpectator(o1) && !isSpectator(o2)) {
return 1;
} else if(isSpectator(o2) && !isSpectator(o1)) {
return -1;
} else {
return o1.getName().compareToIgnoreCase(o2.getName());
}
}
}
// private List<Pair<EntityPlayer, ResourceLocation>> players;
// private List<GuiCheckBox> checkBoxes;
//
// private GuiCheckBox hideAllBox, showAllBox;
// private GuiCheckBox rememberHidden;
//
// private boolean initialized = false;
//
// private int playerCount;
// private int upperPlayer = 0;
//
// private int lowerBound;
//
// private boolean drag = false;
// private int lastY = 0;
// private int fitting = 0;
//
// private final Minecraft mc = Minecraft.getMinecraft();
//
// private final String screenTitle = I18n.format("replaymod.input.playeroverview");
//
// private final Set<UUID> initialHiddenPlayers;
//
// public GuiPlayerOverview(List<EntityPlayer> players) {
// initialHiddenPlayers = new HashSet<UUID>(PlayerHandler.getHiddenPlayers());
//
// Collections.sort(players, new PlayerComparator());
//
// this.players = new ArrayList<Pair<EntityPlayer, ResourceLocation>>();
// this.checkBoxes = new ArrayList<GuiCheckBox>();
//
// for(final EntityPlayer p : players) {
// final ResourceLocation loc = SkinProvider.getResourceLocationForPlayerUUID(p.getUniqueID());
// this.players.add(Pair.of(p, loc));
// }
//
// playerCount = players.size();
//
// ReplayMod.replaySender.setReplaySpeed(0);
// }
//
// private boolean isSpectator(EntityPlayer e) {
// return e.isInvisible() && e.getActivePotionEffect(Potion.invisibility) == null;
// }
//
// @Override
// protected void mouseClicked(int mouseX, int mouseY, int mouseButton)
// throws IOException {
//
// if(fitting < playerCount) {
// float visiblePerc = (float) fitting / (float) playerCount;
//
// int h = this.height - 32 - 32;
// int offset = Math.round((upperPlayer / (fitting)) * visiblePerc * h);
//
// int lower = Math.round(32 + offset + (h * visiblePerc)) - 2;
//
// int k2 = (int) (this.width * 0.3);
//
// if(mouseX >= k2 - 16 && mouseX <= k2 - 12 && mouseY >= 32 - 2 + offset && mouseY <= lower) {
// lastY = mouseY;
// drag = true;
// return;
// }
// }
// int k2 = (int) (this.width * 0.3);
//
// if(mouseX >= k2 && mouseX <= (this.width * 0.6) && mouseY >= upperBound && mouseY <= lowerBound) {
// int off = mouseY - upperBound;
// int p = (off / 21) + upperPlayer;
// // TODO
//// ReplayHandler.spectateEntity(players.get(p).first());
// mc.displayGuiScreen(null);
// }
//
// super.mouseClicked(mouseX, mouseY, mouseButton);
// }
//
// @Override
// protected void mouseClickMove(int mouseX, int mouseY,
// int clickedMouseButton, long timeSinceLastClick) {
//
// if(drag) {
// float step = 1f / (float) playerCount;
//
// int diff = mouseY - lastY;
// int h = this.height - 32 - 32;
//
// float percDiff = (float) diff / (float) h;
// if(Math.abs(percDiff) > Math.abs(step)) {
// int s = (int) (percDiff / step);
// lastY = mouseY;
// upperPlayer += s;
// if(upperPlayer > playerCount - fitting) {
// upperPlayer = playerCount - fitting;
// } else if(upperPlayer < 0) {
// upperPlayer = 0;
// }
// }
// }
//
// super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick);
// }
//
// @Override
// protected void mouseReleased(int mouseX, int mouseY, int state) {
// drag = false;
//
// for(GuiCheckBox checkBox : checkBoxes) {
// checkBox.mouseReleased(mouseX, mouseY);
// }
//
// super.mouseReleased(mouseX, mouseY, state);
// }
//
// @Override
// public void initGui() {
// upperPlayer = 0;
// lowerBound = this.height - 10;
//
// @SuppressWarnings("unchecked")
// List<GuiButton> buttonList = this.buttonList;
//
// int i = 0;
// for(GuiCheckBox checkBox : checkBoxes) {
// checkBox.xPosition = (int)(this.width*0.7)-5;
// buttonList.add(checkBox);
// i++;
// if(i >= fitting) break;
// }
//
// if(!initialized) {
// hideAllBox = new GuiCheckBox(GuiConstants.PLAYER_OVERVIEW_HIDE_ALL, 0, 0, "", false);
// showAllBox = new GuiCheckBox(GuiConstants.PLAYER_OVERVIEW_SHOW_ALL, 0, 0, "", true);
// rememberHidden = new GuiCheckBox(GuiConstants.PLAYER_OVERVIEW_REMEMBER, 0, 0, I18n.format("replaymod.gui.playeroverview.remembersettings"), defaultSave);
// }
//
// hideAllBox.xPosition = (int)(this.width*0.7)-5;
// showAllBox.xPosition = (int)(this.width*0.7)-20;
// hideAllBox.yPosition = showAllBox.yPosition = 45;
//
// rememberHidden.xPosition = (int)(this.width*0.3);
// rememberHidden.yPosition = 45;
//
// buttonList.add(hideAllBox);
// buttonList.add(showAllBox);
// buttonList.add(rememberHidden);
//
// initialized = true;
// }
//
// @Override
// protected void actionPerformed(GuiButton button) throws IOException {
// if(button == showAllBox) {
// showAllBox.setIsChecked(true);
// for(Pair<EntityPlayer, ResourceLocation> p : players) {
// PlayerHandler.showPlayer(p.first());
// }
// } else if(button == hideAllBox) {
// hideAllBox.setIsChecked(false);
// for(Pair<EntityPlayer, ResourceLocation> p : players) {
// PlayerHandler.hidePlayer(p.first());
// }
// }
//
// if(!(button instanceof GuiCheckBox)) return;
// if(button.id >= fitting) return;
// if(!checkBoxes.contains(button)) return;
// PlayerHandler.setIsVisible(players.get(upperPlayer + button.id).first(), ((GuiCheckBox)button).isChecked());
// }
//
// private static final int upperBound = 65;
//
// @Override
// public void drawScreen(int mouseX, int mouseY, float partialTicks) {
// this.drawCenteredString(fontRendererObj, screenTitle, this.width / 2, 5, Color.WHITE.getRGB());
// int k2 = (int)(this.width * 0.3);
// int l2 = upperBound;
//
// drawGradientRect(k2 - 20, 20, (int) (this.width * 0.7) + 20, this.height - 30 - 2 + 10, -1072689136, -804253680);
//
// drawString(fontRendererObj, I18n.format("replaymod.gui.playeroverview.spectate"), k2 - 10, 30, Color.WHITE.getRGB());
//
// String visibleString = I18n.format("replaymod.gui.playeroverview.visible");
// drawString(fontRendererObj, visibleString, (int) (this.width * 0.7) + 10 - fontRendererObj.getStringWidth(visibleString), 30, Color.WHITE.getRGB());
//
// fitting = 0;
//
// int sk = 0;
// for(Pair<EntityPlayer, ResourceLocation> p : players) {
// if(sk < upperPlayer) {
// sk++;
// continue;
// }
// boolean spec = isSpectator(p.first());
//
// this.drawString(fontRendererObj, p.first().getName(), k2 + 16 + 5, l2 + 8 - (fontRendererObj.FONT_HEIGHT / 2),
// spec ? Color.DARK_GRAY.getRGB() : Color.WHITE.getRGB());
//
// mc.getTextureManager().bindTexture(p.second());
//
// drawScaledCustomSizeModalRect(k2, l2, 8.0F, 8.0F, 8, 8, 16, 16, 64.0F, 64.0F);
// if(p.first().func_175148_a(EnumPlayerModelParts.HAT))
// Gui.drawScaledCustomSizeModalRect(k2, l2, 40.0F, 8.0F, 8, 8, 16, 16, 64.0F, 64.0F);
//
// GlStateManager.resetColor();
// if(fitting >= checkBoxes.size()) {
// checkBoxes.add(new GuiCheckBox(checkBoxes.size(), (int)(this.width*0.7)-5, l2+3, "", true));
// @SuppressWarnings("unchecked")
// List<GuiButton> buttonList = this.buttonList;
// buttonList.add(checkBoxes.get(checkBoxes.size() - 1));
// }
// checkBoxes.get(fitting).setIsChecked(!PlayerHandler.isHidden(p.first().getUniqueID()));
//
// l2 += 16 + 5;
// fitting++;
// if(l2 + 32 > lowerBound) {
// break;
// }
// }
//
// int dw = Mouse.getDWheel();
// if(dw > 0) {
// dw = -1;
// } else if(dw < 0) {
// dw = 1;
// }
//
// upperPlayer = Math.max(Math.min(upperPlayer + dw, playerCount - fitting), 0);
//
// if(fitting < playerCount) {
// float visiblePerc = ((float) fitting) / playerCount;
// int barHeight = (int) (visiblePerc * (height - 32 - 32));
//
// float posPerc = ((float) upperPlayer) / playerCount;
// int barY = (int) (posPerc * (height - 32 - 32));
//
// drawRect(k2 - 18, upperBound - 2, k2 - 10, this.height - 30 - 2, Color.BLACK.getRGB());
// drawRect(k2 - 16, upperBound+2 - 2 + barY, k2 - 12, 30+2 - 1 + barY + barHeight, Color.LIGHT_GRAY.getRGB());
// }
//
// int i = 0;
// for(GuiCheckBox checkBox : checkBoxes) {
// checkBox.drawButton(mc, mouseX, mouseY);
// i++;
// if(i >= fitting) break;
// }
//
// hideAllBox.drawButton(mc, mouseX, mouseY);
// showAllBox.drawButton(mc, mouseX, mouseY);
// rememberHidden.drawButton(mc, mouseX, mouseY);
//
// if(hideAllBox.isMouseOver()) {
// ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.playeroverview.hideall"), this, Color.WHITE);
// }
//
// if(showAllBox.isMouseOver()) {
// ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.playeroverview.showall"), this, Color.WHITE);
// }
//
// if(rememberHidden.isMouseOver()) {
// ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.playeroverview.remembersettings.description"), this, Color.WHITE);
// }
//
// //this is necessary to reset the GL parameters for further GUI rendering
// GlStateManager.enableBlend();
// }
//
// private void saveOnQuit() {
// try {
// // TODO
//// if(rememberHidden.isChecked()) {
//// if(initialHiddenPlayers.equals(PlayerHandler.getHiddenPlayers())) return;
//// ReplayHandler.getReplayFile().writeInvisiblePlayers(PlayerHandler.getHiddenPlayers());
//// } else {
//// if(initialHiddenPlayers.isEmpty()) return;
//// ReplayHandler.getReplayFile().writeInvisiblePlayers(Collections.<UUID>emptySet());
//// }
// } catch(Exception e) {
// e.printStackTrace();
// }
// }
//
// @Override
// public void keyTyped(char typedChar, int keyCode) throws IOException {
// if(keyCode == Keyboard.KEY_ESCAPE) {
// saveOnQuit();
// super.keyTyped(typedChar, keyCode);
// }
// }
//
// private class PlayerComparator implements Comparator<EntityPlayer> {
//
// @Override
// public int compare(EntityPlayer o1, EntityPlayer o2) {
// if(isSpectator(o1) && !isSpectator(o2)) {
// return 1;
// } else if(isSpectator(o2) && !isSpectator(o1)) {
// return -1;
// } else {
// return o1.getName().compareToIgnoreCase(o2.getName());
// }
// }
//
// }
}

View File

@@ -1,12 +1,10 @@
package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.*;
import eu.crushedpixel.replaymod.gui.elements.listeners.CheckBoxListener;
import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.holders.GuiEntryListEntry;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.settings.EncodingPreset;
import eu.crushedpixel.replaymod.settings.RenderOptions;
import eu.crushedpixel.replaymod.utils.MouseUtils;
@@ -29,7 +27,7 @@ import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.List;
public class GuiRenderSettings extends GuiScreen implements GuiReplayOverlay.NoOverlay {
public class GuiRenderSettings extends GuiScreen {
private final Minecraft mc = Minecraft.getMinecraft();
@@ -542,7 +540,8 @@ public class GuiRenderSettings extends GuiScreen implements GuiReplayOverlay.NoO
if(FMLClientHandler.instance().hasOptifine()) {
mc.displayGuiScreen(new GuiErrorScreen(I18n.format("replaymod.gui.rendering.error.title"), I18n.format("replaymod.gui.rendering.error.optifine")));
} else {
ReplayHandler.startPath(options, true);
// TODO
// ReplayHandler.startPath(options, true);
}
}

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;

View File

@@ -1,7 +1,5 @@
package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.gui.elements.GuiSettingsOnOffButton;
import eu.crushedpixel.replaymod.gui.elements.GuiToggleButton;
import eu.crushedpixel.replaymod.settings.ReplaySettings.RecordingOptions;
import eu.crushedpixel.replaymod.settings.ReplaySettings.ReplayOptions;
import net.minecraft.client.gui.GuiButton;
@@ -12,8 +10,6 @@ import net.minecraftforge.fml.client.FMLClientHandler;
import java.awt.*;
import java.io.IOException;
import static eu.crushedpixel.replaymod.gui.GuiConstants.*;
public class GuiReplaySettings extends GuiScreen {
protected String screenTitle = I18n.format("replaymod.gui.settings.title");
private GuiScreen parentGuiScreen;
@@ -38,23 +34,23 @@ public class GuiReplaySettings extends GuiScreen {
int xPos = this.width / 2 - 155 + i % 2 * 160;
int yPos = this.height / 6 + 24 * (i >> 1);
if(o == RecordingOptions.notifications) {
GuiToggleButton sendChatButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_SEND_CHAT, xPos, yPos, 150, 20, o);
buttonList.add(sendChatButton);
} else if(o == RecordingOptions.recordServer) {
GuiToggleButton recordServerButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_RECORDSERVER_ID, xPos, yPos, 150, 20, o);
buttonList.add(recordServerButton);
} else if(o == RecordingOptions.recordSingleplayer) {
GuiToggleButton recordSPButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_RECORDSP_ID, xPos, yPos, 150, 20, o);
buttonList.add(recordSPButton);
} else if(o == RecordingOptions.indicator) {
GuiToggleButton showIndicatorButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_INDICATOR_ID, xPos, yPos, 150, 20, o);
buttonList.add(showIndicatorButton);
}
// TODO
// if(o == RecordingOptions.notifications) {
// GuiToggleButton sendChatButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_SEND_CHAT, xPos, yPos, 150, 20, o);
// buttonList.add(sendChatButton);
//
// } else if(o == RecordingOptions.recordServer) {
// GuiToggleButton recordServerButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_RECORDSERVER_ID, xPos, yPos, 150, 20, o);
// buttonList.add(recordServerButton);
//
// } else if(o == RecordingOptions.recordSingleplayer) {
// GuiToggleButton recordSPButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_RECORDSP_ID, xPos, yPos, 150, 20, o);
// buttonList.add(recordSPButton);
//
// } else if(o == RecordingOptions.indicator) {
// GuiToggleButton showIndicatorButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_INDICATOR_ID, xPos, yPos, 150, 20, o);
// buttonList.add(showIndicatorButton);
// }
++i;
}
@@ -69,14 +65,15 @@ public class GuiReplaySettings extends GuiScreen {
int xPos = this.width / 2 - 155 + i % 2 * 160;
int yPos = this.height / 6 + 24 * (i >> 1);
if(o == ReplayOptions.linear) {
GuiToggleButton linearButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_FORCE_LINEAR, xPos, yPos, 150, 20, o,
I18n.format("replaymod.gui.settings.interpolation.linear"), I18n.format("replaymod.gui.settings.interpolation.cubic"));
buttonList.add(linearButton);
} else {
buttonList.add(new GuiSettingsOnOffButton(0, xPos, yPos, 150, 20, o));
}
// TODO
// if(o == ReplayOptions.linear) {
// GuiToggleButton linearButton = new GuiSettingsOnOffButton(REPLAY_SETTINGS_FORCE_LINEAR, xPos, yPos, 150, 20, o,
// I18n.format("replaymod.gui.settings.interpolation.linear"), I18n.format("replaymod.gui.settings.interpolation.cubic"));
// buttonList.add(linearButton);
//
// } else {
// buttonList.add(new GuiSettingsOnOffButton(0, xPos, yPos, 150, 20, o));
// }
++i;
}

View File

@@ -1,12 +1,11 @@
package eu.crushedpixel.replaymod.gui;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.GuiAdvancedButton;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.MathHelper;
import net.minecraftforge.fml.client.FMLClientHandler;
public class GuiReplaySpeedSlider extends GuiAdvancedButton {
@@ -74,7 +73,7 @@ public class GuiReplaySpeedSlider extends GuiAdvancedButton {
l = packedFGColour;
} else if(!this.enabled) {
l = 10526880;
} else if(this.hovered && FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
} else if(this.hovered) {
l = 16777120;
}

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui.elements;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.GuiButton;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui.elements;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.listeners.CheckBoxListener;
import net.minecraft.client.Minecraft;
import net.minecraftforge.fml.client.config.GuiCheckBox;

View File

@@ -1,11 +1,12 @@
package eu.crushedpixel.replaymod.gui.elements;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.utils.OpenGLUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import static com.replaymod.core.ReplayMod.TEXTURE;
public class GuiArrowButton extends GuiAdvancedButton {
private static final int TEXTURE_X = 40;
@@ -42,7 +43,7 @@ public class GuiArrowButton extends GuiAdvancedButton {
try {
super.draw(mc, mouseX, mouseY, hovering);
mc.getTextureManager().bindTexture(GuiReplayOverlay.replay_gui);
mc.getTextureManager().bindTexture(TEXTURE);
OpenGLUtils.drawRotatedRectWithCustomSizedTexture(xPosition+4, yPosition+4, dir.getRotation(),
TEXTURE_X, TEXTURE_Y, TEXTURE_WIDTH, TEXTURE_HEIGHT, 128, 128);

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui.elements;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.listeners.SelectionListener;
import eu.crushedpixel.replaymod.holders.GuiEntryListEntry;
import eu.crushedpixel.replaymod.utils.MouseUtils;

View File

@@ -6,8 +6,8 @@ import net.minecraft.client.renderer.GlStateManager;
import java.awt.*;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.TEXTURE_SIZE;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.replay_gui;
import static com.replaymod.core.ReplayMod.TEXTURE;
import static com.replaymod.core.ReplayMod.TEXTURE_SIZE;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.glEnable;
@@ -105,7 +105,7 @@ public class GuiScrollbar extends Gui implements GuiElement {
@Override
public void draw(Minecraft mc, int mouseX, int mouseY) {
GlStateManager.resetColor();
mc.renderEngine.bindTexture(replay_gui);
mc.renderEngine.bindTexture(TEXTURE);
glEnable(GL_BLEND);
// Background
@@ -157,7 +157,7 @@ public class GuiScrollbar extends Gui implements GuiElement {
if(!enabled) {
GlStateManager.color(Color.GRAY.getRed()/255f, Color.GRAY.getGreen()/255f, Color.GRAY.getBlue()/255f, 1f);
}
Minecraft.getMinecraft().renderEngine.bindTexture(replay_gui);
Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE);
glEnable(GL_BLEND);
drawModalRectWithCustomSizedTexture(x, y, u, v, width, height, TEXTURE_SIZE, TEXTURE_SIZE);

View File

@@ -1,39 +1,39 @@
package eu.crushedpixel.replaymod.gui.elements;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.settings.ReplaySettings;
import com.replaymod.core.SettingsRegistry;
public class GuiSettingsOnOffButton extends GuiOnOffButton {
private ReplaySettings.ValueEnum toChange;
private SettingsRegistry settingsRegistry;
private SettingsRegistry.SettingKey<Boolean> toChange;
public GuiSettingsOnOffButton(int buttonId, int x, int y, int width, int height, ReplaySettings.ValueEnum toChange) {
super(buttonId, x, y, width, height, toChange.getName()+": ");
public GuiSettingsOnOffButton(int buttonId, int x, int y, int width, int height, SettingsRegistry settingsRegistry,
SettingsRegistry.SettingKey<Boolean> toChange) {
super(buttonId, x, y, width, height, toChange.getDisplayString()+": ");
this.settingsRegistry = settingsRegistry;
this.toChange = toChange;
if(toChange.getValue() instanceof Boolean) {
this.setValue((Boolean) toChange.getValue() ? 0 : 1);
}
this.setValue(settingsRegistry.get(toChange) ? 0 : 1);
}
public GuiSettingsOnOffButton(int buttonId, int x, int y, int width, int height, ReplaySettings.ValueEnum toChange, String onValue, String offValue) {
super(buttonId, x, y, width, height, toChange.getName()+": ", onValue, offValue);
public GuiSettingsOnOffButton(int buttonId, int x, int y, int width, int height, SettingsRegistry settingsRegistry,
SettingsRegistry.SettingKey<Boolean> toChange, String onValue, String offValue) {
super(buttonId, x, y, width, height, toChange.getDisplayString()+": ", onValue, offValue);
this.settingsRegistry = settingsRegistry;
this.toChange = toChange;
if(toChange.getValue() instanceof Boolean) {
this.setValue((Boolean) toChange.getValue() ? 0 : 1);
}
this.setValue(settingsRegistry.get(toChange) ? 0 : 1);
}
@Override
public void toggle() {
super.toggle();
toChange.setValue(isOn());
ReplayMod.replaySettings.rewriteSettings();
settingsRegistry.set(toChange, isOn());
settingsRegistry.save();
}
@Override
public void setValue(int value) {
super.setValue(value);
toChange.setValue(isOn());
ReplayMod.replaySettings.rewriteSettings();
settingsRegistry.set(toChange, isOn());
settingsRegistry.save();
}
}

View File

@@ -1,13 +1,6 @@
package eu.crushedpixel.replaymod.gui.elements.timelines;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.gui.GuiEditKeyframe;
import eu.crushedpixel.replaymod.holders.*;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import java.util.ListIterator;
import eu.crushedpixel.replaymod.holders.Keyframe;
public class GuiKeyframeTimeline extends GuiTimeline {
private static final int KEYFRAME_PLACE_X = 74;
@@ -31,230 +24,231 @@ public class GuiKeyframeTimeline extends GuiTimeline {
this.placeKeyframes = showPlaceKeyframes;
}
@Override
public boolean mouseClick(Minecraft mc, int mouseX, int mouseY, int button) {
if(!enabled) return false;
long time = getTimeAt(mouseX, mouseY);
if(time == -1) {
return false;
}
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
Keyframe closest;
if(mouseY >= positionY + BORDER_TOP + 5 && timeKeyframes) {
closest = ReplayHandler.getTimeKeyframes().getClosestKeyframeForTimestamp((int) time, tolerance);
} else if(mouseY >= positionY + BORDER_TOP && placeKeyframes) {
closest = ReplayHandler.getPositionKeyframes().getClosestKeyframeForTimestamp((int) time, tolerance);
} else {
closest = null;
}
//left mouse button
if(button == 0) {
ReplayHandler.selectKeyframe(closest); //can be null, deselects keyframe
// If we clicked on a key frame, then continue monitoring the mouse for movements
long currentTime = System.currentTimeMillis();
if(closest != null) {
if(currentTime - clickTime < 500) { // if double clicked then open GUI instead
mc.displayGuiScreen(GuiEditKeyframe.create(closest));
this.clickedKeyFrame = null;
} else {
this.clickedKeyFrame = closest;
this.dragging = false;
}
} else { // If we didn't then just update the cursor
ReplayHandler.setRealTimelineCursor((int) time);
this.dragging = true;
}
this.clickTime = currentTime;
} else if(button == 1) {
if(closest != null) {
if(closest.getValue() instanceof AdvancedPosition) {
AdvancedPosition pos = (AdvancedPosition)closest.getValue();
ReplayHandler.getCameraEntity().movePath(pos);
} else if(closest.getValue() instanceof TimestampValue) {
ReplayMod.overlay.performJump(((TimestampValue)closest.getValue()).asInt());
}
}
}
return isHovering(mouseX, mouseY);
}
@Override
public void mouseDrag(Minecraft mc, int mouseX, int mouseY, int button) {
if(!enabled) return;
long time = getTimeAt(mouseX, mouseY);
if (time != -1) {
if (clickedKeyFrame != null) {
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
if (dragging || Math.abs(clickedKeyFrame.getRealTimestamp() - time) > tolerance) {
clickedKeyFrame.setRealTimestamp((int) time);
ReplayHandler.getPositionKeyframes().sort();
ReplayHandler.getTimeKeyframes().sort();
dragging = true;
}
} else if (dragging) {
ReplayHandler.setRealTimelineCursor((int) time);
}
}
}
@Override
public void mouseRelease(Minecraft mc, int mouseX, int mouseY, int button) {
mouseDrag(mc, mouseX, mouseY, button);
clickedKeyFrame = null;
dragging = false;
}
@Override
public void draw(Minecraft mc, int mouseX, int mouseY) {
super.draw(mc, mouseX, mouseY);
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
long leftTime = Math.round(timeStart * timelineLength);
long rightTime = Math.round((timeStart + zoom) * timelineLength);
double segmentLength = timelineLength * zoom;
//iterate over keyframes to find spectator segments
if(placeKeyframes) {
ListIterator<Keyframe<AdvancedPosition>> iterator = ReplayHandler.getPositionKeyframes().listIterator();
while(iterator.hasNext()) {
Keyframe<AdvancedPosition> kf = iterator.next();
if(!(kf.getValue() instanceof SpectatorData))
continue;
int i = iterator.nextIndex();
int nextSpectatorKeyframeRealTime = -1;
if (iterator.hasNext()) {
Keyframe<AdvancedPosition> kf2 = iterator.next();
if(kf2.getValue() instanceof SpectatorData) {
SpectatorData spectatorData1 = (SpectatorData)kf.getValue();
SpectatorData spectatorData2 = (SpectatorData)kf2.getValue();
if(spectatorData1.getSpectatedEntityID() == spectatorData2.getSpectatedEntityID()) {
nextSpectatorKeyframeRealTime = kf2.getRealTimestamp();
}
}
}
int i2 = iterator.previousIndex();
while(i2 >= i) {
iterator.previous();
i2--;
}
if(nextSpectatorKeyframeRealTime != -1) {
int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
int nextX = getKeyframeX(nextSpectatorKeyframeRealTime, leftTime, bodyWidth, segmentLength);
int color = ((SpectatorData)kf.getValue()).getSpectatingMethod().getColor();
drawRect(Math.max(keyframeX + 2, positionX+BORDER_LEFT), positionY + BORDER_TOP + 1, Math.min(nextX - 2, positionX+width-BORDER_RIGHT+1),
positionY + BORDER_TOP + 4, color);
GlStateManager.color(1, 1, 1, 1);
}
}
}
//iterate over time keyframes to find negative replay speeds
if(timeKeyframes) {
ListIterator<Keyframe<TimestampValue>> iterator = ReplayHandler.getTimeKeyframes().listIterator();
while(iterator.hasNext()) {
Keyframe<TimestampValue> kf = iterator.next();
int i = iterator.nextIndex();
int nextTimeKeyframeRealTime = -1;
if (iterator.hasNext()) {
Keyframe<TimestampValue> kf2 = iterator.next();
if(kf.getValue().asInt() > kf2.getValue().asInt()) {
nextTimeKeyframeRealTime = kf2.getRealTimestamp();
}
}
int i2 = iterator.previousIndex();
while(i2 >= i) {
iterator.previous();
i2--;
}
if(nextTimeKeyframeRealTime != -1) {
int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
int nextX = getKeyframeX(nextTimeKeyframeRealTime, leftTime, bodyWidth, segmentLength);
drawGradientRect(Math.max(keyframeX + 2, positionX+BORDER_LEFT), positionY + BORDER_TOP + 6, Math.min(nextX - 2, positionX+width-BORDER_RIGHT+1),
positionY + BORDER_TOP + 9, 0xFFFF0000, 0xFFFF0000);
}
}
}
drawTimelineCursor(leftTime, rightTime, bodyWidth);
//Draw Keyframe logos
for (Keyframe kf : ReplayHandler.getAllKeyframes()) {
if (kf != null && !kf.equals(ReplayHandler.getSelectedKeyframe()))
drawKeyframe(kf, bodyWidth, leftTime, rightTime, segmentLength);
}
if(ReplayHandler.getSelectedKeyframe() != null && !(ReplayHandler.getSelectedKeyframe().getValue() instanceof Marker)) {
drawKeyframe(ReplayHandler.getSelectedKeyframe(), bodyWidth, leftTime, rightTime, segmentLength);
}
}
private int getKeyframeX(int timestamp, long leftTime, int bodyWidth, double segmentLength) {
long positionInSegment = timestamp - leftTime;
double fractionOfSegment = positionInSegment / segmentLength;
return (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
}
private void drawKeyframe(Keyframe kf, int bodyWidth, long leftTime, long rightTime, double segmentLength) {
if (kf.getRealTimestamp() <= rightTime && kf.getRealTimestamp() >= leftTime) {
int textureX;
int textureY;
int y = positionY;
int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
if(kf.getValue() instanceof AdvancedPosition) {
if(!placeKeyframes) return;
textureX = KEYFRAME_PLACE_X;
textureY = KEYFRAME_PLACE_Y;
y += 0;
//If Spectator Keyframe, use different texture
if(kf.getValue() instanceof SpectatorData) {
textureX = KEYFRAME_SPEC_X;
textureY = KEYFRAME_SPEC_Y;
}
} else if(kf.getValue() instanceof TimestampValue) {
if(!timeKeyframes) return;
textureX = KEYFRAME_TIME_X;
textureY = KEYFRAME_TIME_Y;
y += 5;
} else {
throw new UnsupportedOperationException("Unknown keyframe type: " + kf.getClass());
}
if (ReplayHandler.isSelected(kf)) {
textureX += 5;
}
rect(keyframeX - 2, y + BORDER_TOP, textureX, textureY, 5, 5);
}
}
// TODO
// @Override
// public boolean mouseClick(Minecraft mc, int mouseX, int mouseY, int button) {
// if(!enabled) return false;
//
// long time = getTimeAt(mouseX, mouseY);
// if(time == -1) {
// return false;
// }
//
// int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
//
// Keyframe closest;
// if(mouseY >= positionY + BORDER_TOP + 5 && timeKeyframes) {
// closest = ReplayHandler.getTimeKeyframes().getClosestKeyframeForTimestamp((int) time, tolerance);
// } else if(mouseY >= positionY + BORDER_TOP && placeKeyframes) {
// closest = ReplayHandler.getPositionKeyframes().getClosestKeyframeForTimestamp((int) time, tolerance);
// } else {
// closest = null;
// }
//
// //left mouse button
// if(button == 0) {
// ReplayHandler.selectKeyframe(closest); //can be null, deselects keyframe
//
// // If we clicked on a key frame, then continue monitoring the mouse for movements
// long currentTime = System.currentTimeMillis();
// if(closest != null) {
// if(currentTime - clickTime < 500) { // if double clicked then open GUI instead
// mc.displayGuiScreen(GuiEditKeyframe.create(closest));
// this.clickedKeyFrame = null;
// } else {
// this.clickedKeyFrame = closest;
// this.dragging = false;
// }
// } else { // If we didn't then just update the cursor
// ReplayHandler.setRealTimelineCursor((int) time);
// this.dragging = true;
// }
// this.clickTime = currentTime;
//
// } else if(button == 1) {
// if(closest != null) {
// if(closest.getValue() instanceof AdvancedPosition) {
// AdvancedPosition pos = (AdvancedPosition)closest.getValue();
// ReplayHandler.getCameraEntity().movePath(pos);
// } else if(closest.getValue() instanceof TimestampValue) {
// ReplayMod.overlay.performJump(((TimestampValue)closest.getValue()).asInt());
// }
// }
// }
//
// return isHovering(mouseX, mouseY);
// }
//
// @Override
// public void mouseDrag(Minecraft mc, int mouseX, int mouseY, int button) {
// if(!enabled) return;
// long time = getTimeAt(mouseX, mouseY);
// if (time != -1) {
// if (clickedKeyFrame != null) {
// int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
//
// if (dragging || Math.abs(clickedKeyFrame.getRealTimestamp() - time) > tolerance) {
// clickedKeyFrame.setRealTimestamp((int) time);
// ReplayHandler.getPositionKeyframes().sort();
// ReplayHandler.getTimeKeyframes().sort();
// dragging = true;
// }
// } else if (dragging) {
// ReplayHandler.setRealTimelineCursor((int) time);
// }
// }
// }
//
// @Override
// public void mouseRelease(Minecraft mc, int mouseX, int mouseY, int button) {
// mouseDrag(mc, mouseX, mouseY, button);
// clickedKeyFrame = null;
// dragging = false;
// }
//
// @Override
// public void draw(Minecraft mc, int mouseX, int mouseY) {
// super.draw(mc, mouseX, mouseY);
//
// int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
//
// long leftTime = Math.round(timeStart * timelineLength);
// long rightTime = Math.round((timeStart + zoom) * timelineLength);
//
// double segmentLength = timelineLength * zoom;
//
// //iterate over keyframes to find spectator segments
// if(placeKeyframes) {
// ListIterator<Keyframe<AdvancedPosition>> iterator = ReplayHandler.getPositionKeyframes().listIterator();
// while(iterator.hasNext()) {
// Keyframe<AdvancedPosition> kf = iterator.next();
//
// if(!(kf.getValue() instanceof SpectatorData))
// continue;
//
// int i = iterator.nextIndex();
// int nextSpectatorKeyframeRealTime = -1;
//
// if (iterator.hasNext()) {
// Keyframe<AdvancedPosition> kf2 = iterator.next();
//
// if(kf2.getValue() instanceof SpectatorData) {
// SpectatorData spectatorData1 = (SpectatorData)kf.getValue();
// SpectatorData spectatorData2 = (SpectatorData)kf2.getValue();
//
// if(spectatorData1.getSpectatedEntityID() == spectatorData2.getSpectatedEntityID()) {
// nextSpectatorKeyframeRealTime = kf2.getRealTimestamp();
// }
// }
// }
//
// int i2 = iterator.previousIndex();
//
// while(i2 >= i) {
// iterator.previous();
// i2--;
// }
//
// if(nextSpectatorKeyframeRealTime != -1) {
// int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
// int nextX = getKeyframeX(nextSpectatorKeyframeRealTime, leftTime, bodyWidth, segmentLength);
//
// int color = ((SpectatorData)kf.getValue()).getSpectatingMethod().getColor();
//
// drawRect(Math.max(keyframeX + 2, positionX+BORDER_LEFT), positionY + BORDER_TOP + 1, Math.min(nextX - 2, positionX+width-BORDER_RIGHT+1),
// positionY + BORDER_TOP + 4, color);
//
// GlStateManager.color(1, 1, 1, 1);
// }
// }
// }
//
// //iterate over time keyframes to find negative replay speeds
// if(timeKeyframes) {
// ListIterator<Keyframe<TimestampValue>> iterator = ReplayHandler.getTimeKeyframes().listIterator();
// while(iterator.hasNext()) {
// Keyframe<TimestampValue> kf = iterator.next();
//
// int i = iterator.nextIndex();
// int nextTimeKeyframeRealTime = -1;
//
// if (iterator.hasNext()) {
// Keyframe<TimestampValue> kf2 = iterator.next();
// if(kf.getValue().asInt() > kf2.getValue().asInt()) {
// nextTimeKeyframeRealTime = kf2.getRealTimestamp();
// }
// }
//
// int i2 = iterator.previousIndex();
//
// while(i2 >= i) {
// iterator.previous();
// i2--;
// }
//
// if(nextTimeKeyframeRealTime != -1) {
// int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
// int nextX = getKeyframeX(nextTimeKeyframeRealTime, leftTime, bodyWidth, segmentLength);
//
// drawGradientRect(Math.max(keyframeX + 2, positionX+BORDER_LEFT), positionY + BORDER_TOP + 6, Math.min(nextX - 2, positionX+width-BORDER_RIGHT+1),
// positionY + BORDER_TOP + 9, 0xFFFF0000, 0xFFFF0000);
// }
// }
// }
//
// drawTimelineCursor(leftTime, rightTime, bodyWidth);
//
//
// //Draw Keyframe logos
// for (Keyframe kf : ReplayHandler.getAllKeyframes()) {
// if (kf != null && !kf.equals(ReplayHandler.getSelectedKeyframe()))
// drawKeyframe(kf, bodyWidth, leftTime, rightTime, segmentLength);
// }
//
// if(ReplayHandler.getSelectedKeyframe() != null) {
// drawKeyframe(ReplayHandler.getSelectedKeyframe(), bodyWidth, leftTime, rightTime, segmentLength);
// }
// }
//
// private int getKeyframeX(int timestamp, long leftTime, int bodyWidth, double segmentLength) {
// long positionInSegment = timestamp - leftTime;
// double fractionOfSegment = positionInSegment / segmentLength;
// return (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
// }
//
// private void drawKeyframe(Keyframe kf, int bodyWidth, long leftTime, long rightTime, double segmentLength) {
// if (kf.getRealTimestamp() <= rightTime && kf.getRealTimestamp() >= leftTime) {
// int textureX;
// int textureY;
// int y = positionY;
//
// int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
//
// if(kf.getValue() instanceof AdvancedPosition) {
// if(!placeKeyframes) return;
// textureX = KEYFRAME_PLACE_X;
// textureY = KEYFRAME_PLACE_Y;
// y += 0;
//
// //If Spectator Keyframe, use different texture
// if(kf.getValue() instanceof SpectatorData) {
// textureX = KEYFRAME_SPEC_X;
// textureY = KEYFRAME_SPEC_Y;
// }
// } else if(kf.getValue() instanceof TimestampValue) {
// if(!timeKeyframes) return;
// textureX = KEYFRAME_TIME_X;
// textureY = KEYFRAME_TIME_Y;
// y += 5;
// } else {
// throw new UnsupportedOperationException("Unknown keyframe type: " + kf.getClass());
// }
//
// if (ReplayHandler.isSelected(kf)) {
// textureX += 5;
// }
//
// rect(keyframeX - 2, y + BORDER_TOP, textureX, textureY, 5, 5);
// }
// }
}

View File

@@ -1,175 +0,0 @@
package eu.crushedpixel.replaymod.gui.elements.timelines;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.gui.GuiEditKeyframe;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.Marker;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.I18n;
import org.lwjgl.util.Point;
import java.awt.*;
public class GuiMarkerTimeline extends GuiTimeline {
private static final int KEYFRAME_MARKER_X = 109;
private static final int KEYFRAME_MARKER_Y = 20;
private Keyframe<Marker> clickedKeyFrame;
private long clickTime;
private boolean dragging;
public GuiMarkerTimeline(int positionX, int positionY, int width, int height, boolean showMarkers) {
super(positionX, positionY, width, height);
this.showMarkers = showMarkers;
}
@Override
public boolean mouseClick(Minecraft mc, int mouseX, int mouseY, int button) {
if(!enabled) return false;
long time = getTimeAt(mouseX, mouseY);
if(time == -1) {
return false;
}
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
Keyframe<Marker> closest = null;
if(mouseY >= positionY + BORDER_TOP + 10) {
closest = ReplayHandler.getMarkerKeyframes().getClosestKeyframeForTimestamp((int) time, tolerance);
}
//left mouse button
if(button == 0) {
ReplayHandler.selectKeyframe(closest);
if(closest == null) { //if no keyframe clicked, jump in time
ReplayMod.overlay.performJump(getTimeAt(mouseX, mouseY));
} else {
// If we clicked on a key frame, then continue monitoring the mouse for movements
long currentTime = System.currentTimeMillis();
if(closest != null) {
if(currentTime - clickTime < 500) { // if double clicked then open GUI instead
mc.displayGuiScreen(GuiEditKeyframe.create(closest));
this.clickedKeyFrame = null;
} else {
this.clickedKeyFrame = closest;
this.dragging = false;
}
} else { // If we didn't then just update the cursor
this.dragging = true;
}
this.clickTime = currentTime;
}
} else if(button == 1) {
if(closest != null) {
//Jump to clicked Marker Keyframe (explicitly force to jump to this position)
ReplayHandler.setLastPosition(closest.getValue().getPosition(), true);
//perform the jump, telling the Overlay not to override the last position value
ReplayMod.overlay.performJump(closest.getRealTimestamp(), false);
}
}
return isHovering(mouseX, mouseY);
}
@Override
public void mouseDrag(Minecraft mc, int mouseX, int mouseY, int button) {
if(!enabled) return;
long time = getTimeAt(mouseX, mouseY);
if (time != -1) {
if (clickedKeyFrame != null) {
int tolerance = (int) (2 * Math.round(zoom * timelineLength / width));
if (dragging || Math.abs(clickedKeyFrame.getRealTimestamp() - time) > tolerance) {
clickedKeyFrame.setRealTimestamp((int) time);
dragging = true;
}
}
}
}
@Override
public void mouseRelease(Minecraft mc, int mouseX, int mouseY, int button) {
mouseDrag(mc, mouseX, mouseY, button);
clickedKeyFrame = null;
dragging = false;
}
@Override
public void draw(Minecraft mc, int mouseX, int mouseY) {
super.draw(mc, mouseX, mouseY);
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
long leftTime = Math.round(timeStart * timelineLength);
long rightTime = Math.round((timeStart + zoom) * timelineLength);
double segmentLength = timelineLength * zoom;
drawTimelineCursor(leftTime, rightTime, bodyWidth);
//Draw Keyframe logos
for(Keyframe<Marker> kf : ReplayHandler.getMarkerKeyframes()) {
if (kf != null && !kf.equals(ReplayHandler.getSelectedKeyframe()))
drawKeyframe(kf, bodyWidth, leftTime, rightTime, segmentLength);
}
if(ReplayHandler.getSelectedKeyframe() != null && ReplayHandler.getSelectedKeyframe().getValue() instanceof Marker) {
drawKeyframe(ReplayHandler.getSelectedKeyframe(), bodyWidth, leftTime, rightTime, segmentLength);
}
}
private int getKeyframeX(int timestamp, long leftTime, int bodyWidth, double segmentLength) {
long positionInSegment = timestamp - leftTime;
double fractionOfSegment = positionInSegment / segmentLength;
return (int) (positionX + BORDER_LEFT + fractionOfSegment * bodyWidth);
}
@Override
public void drawOverlay(Minecraft mc, int mouseX, int mouseY) {
boolean drawn = false;
int bodyWidth = width - BORDER_LEFT - BORDER_RIGHT;
long leftTime = Math.round(timeStart * timelineLength);
double segmentLength = timelineLength * zoom;
for(Keyframe<Marker> marker : ReplayHandler.getMarkerKeyframes()) {
int keyframeX = getKeyframeX(marker.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
if(MouseUtils.isMouseWithinBounds(keyframeX - 2, this.positionY + BORDER_TOP + 10 + 1, 5, 5)) {
Point mouse = MouseUtils.getMousePos();
String markerName = marker.getValue().getName();
if(markerName == null || markerName.isEmpty()) markerName = I18n.format("replaymod.gui.ingame.unnamedmarker");
ReplayMod.tooltipRenderer.drawTooltip(mouse.getX(), mouse.getY(), markerName, null, Color.WHITE);
drawn = true;
}
}
if(!drawn) {
super.drawOverlay(mc, mouseX, mouseY);
}
}
private void drawKeyframe(Keyframe kf, int bodyWidth, long leftTime, long rightTime, double segmentLength) {
if (kf.getRealTimestamp() <= rightTime && kf.getRealTimestamp() >= leftTime) {
int textureX = KEYFRAME_MARKER_X;
int textureY = KEYFRAME_MARKER_Y;
int y = positionY+10;
int keyframeX = getKeyframeX(kf.getRealTimestamp(), leftTime, bodyWidth, segmentLength);
if (ReplayHandler.isSelected(kf)) {
textureX += 5;
}
rect(keyframeX - 2, y + BORDER_TOP, textureX, textureY, 5, 5);
}
}
}

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui.elements.timelines;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.GuiElement;
import eu.crushedpixel.replaymod.utils.RoundUtils;
import lombok.AllArgsConstructor;
@@ -11,8 +11,8 @@ import net.minecraft.client.renderer.GlStateManager;
import java.awt.*;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.TEXTURE_SIZE;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.replay_gui;
import static com.replaymod.core.ReplayMod.TEXTURE;
import static com.replaymod.core.ReplayMod.TEXTURE_SIZE;
import static org.lwjgl.opengl.GL11.GL_BLEND;
import static org.lwjgl.opengl.GL11.glEnable;
@@ -76,7 +76,7 @@ public class GuiTimeline extends Gui implements GuiElement {
* This draws the time at big markers above the timeline. Therefore extra space in negative y direction
* should be kept empty if markers are desired.
*/
public boolean showMarkers;
public boolean showMarkers; // TODO: Rename to not be confused with Marker
protected final int positionX;
protected final int positionY;
@@ -280,7 +280,7 @@ public class GuiTimeline extends Gui implements GuiElement {
if(!enabled) {
GlStateManager.color(Color.GRAY.getRed() / 255f, Color.GRAY.getGreen() / 255f, Color.GRAY.getBlue() / 255f, 1f);
}
Minecraft.getMinecraft().renderEngine.bindTexture(replay_gui);
Minecraft.getMinecraft().renderEngine.bindTexture(TEXTURE);
glEnable(GL_BLEND);
drawModalRectWithCustomSizedTexture(x, y, u, v, width, height, TEXTURE_SIZE, TEXTURE_SIZE);

View File

@@ -6,7 +6,7 @@ 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 eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.GuiConstants;
public class GuiLoginPrompt extends AbstractGuiScreen<GuiLoginPrompt> {

View File

@@ -7,7 +7,7 @@ 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 eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.api.ApiException;
import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.utils.EmailAddressUtils;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui.online;
import eu.crushedpixel.replaymod.ReplayMod;
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;
@@ -12,7 +12,6 @@ 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.gui.replayviewer.GuiReplayViewer;
import eu.crushedpixel.replaymod.holders.GuiEntryListStringEntry;
import net.minecraft.client.gui.*;
import net.minecraft.client.resources.I18n;
@@ -265,7 +264,8 @@ public class GuiReplayCenter extends GuiScreen implements GuiYesNoCallback {
} else if(button.id == GuiConstants.CENTER_LOGOUT_BUTTON) {
mc.displayGuiScreen(getYesNoGui(this, LOGOUT_CALLBACK_ID));
} else if(button.id == GuiConstants.CENTER_MANAGER_BUTTON) {
mc.displayGuiScreen(new GuiReplayViewer());
// TODO
// mc.displayGuiScreen(new GuiReplayViewer(mod));
} else if(button.id == GuiConstants.CENTER_RECENT_BUTTON) {
disableTopBarButton(button.id);
showOnlineRecent();

View File

@@ -1,15 +1,14 @@
package eu.crushedpixel.replaymod.gui.online;
import com.mojang.realmsclient.gui.ChatFormatting;
import com.replaymod.core.ReplayMod;
import de.johni0702.minecraft.gui.container.AbstractGuiScreen;
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.ReplayMod;
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import java.io.File;
@@ -49,7 +48,8 @@ public class GuiReplayDownloading extends AbstractGuiScreen<GuiReplayDownloading
@Override
public void run() {
try {
ReplayHandler.startReplay(replayFile);
// TODO
// ReplayHandler.startReplay(replayFile);
} catch (Exception e) {
e.printStackTrace();
}

View File

@@ -7,8 +7,6 @@ import eu.crushedpixel.replaymod.gui.elements.GuiAdvancedButton;
import eu.crushedpixel.replaymod.gui.elements.GuiDropdown;
import eu.crushedpixel.replaymod.gui.elements.GuiString;
import eu.crushedpixel.replaymod.holders.GuiEntryListValueEntry;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
@@ -55,7 +53,7 @@ public class GuiReplayInstanceChooser extends GuiScreen {
for(File file : files) {
try {
String extension = FilenameUtils.getExtension(file.getAbsolutePath());
if(!("." + extension).equals(ReplayFile.ZIP_FILE_EXTENSION)) continue;
if(!"zip".equals(extension)) continue;
String filename = FilenameUtils.getBaseName(file.getAbsolutePath());
String[] split = filename.split("_");
@@ -72,7 +70,8 @@ public class GuiReplayInstanceChooser extends GuiScreen {
//if no modified versions of the replay were found, start the downloaded one
if(chooseableFiles.isEmpty()) {
ReplayHandler.startReplay(downloadedFile);
// TODO
// ReplayHandler.startReplay(downloadedFile);
return;
}
@@ -103,7 +102,8 @@ public class GuiReplayInstanceChooser extends GuiScreen {
public void run() {
try {
File file = fileDropdown.getElement(fileDropdown.getSelectionIndex()).getValue();
ReplayHandler.startReplay(file);
//TODO
// ReplayHandler.startReplay(file);
} catch(Exception e) {
e.printStackTrace();
}

View File

@@ -1,16 +1,22 @@
package eu.crushedpixel.replaymod.gui.online;
import eu.crushedpixel.replaymod.ReplayMod;
import com.google.common.base.Optional;
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 com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.api.replay.FileUploader;
import eu.crushedpixel.replaymod.api.replay.holders.Category;
import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.gui.elements.*;
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
import eu.crushedpixel.replaymod.gui.replayviewer.GuiReplayViewer;
import eu.crushedpixel.replaymod.recording.ReplayMetaData;
import com.replaymod.replay.gui.screen.GuiReplayViewer;
import eu.crushedpixel.replaymod.registry.KeybindRegistry;
import eu.crushedpixel.replaymod.registry.ResourceHelper;
import eu.crushedpixel.replaymod.utils.*;
import eu.crushedpixel.replaymod.utils.ImageUtils;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import eu.crushedpixel.replaymod.utils.RegexUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiButton;
@@ -35,7 +41,6 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Callable;
@@ -84,15 +89,15 @@ public class GuiUploadFile extends GuiScreen implements ProgressUpdateListener {
boolean correctFile = false;
this.replayFile = file;
if(("." + FilenameUtils.getExtension(file.getAbsolutePath())).equals(ReplayFile.ZIP_FILE_EXTENSION)) {
if(("." + FilenameUtils.getExtension(file.getAbsolutePath())).equals(".zip")) {
ReplayFile archive = null;
try {
archive = new ReplayFile(file);
archive = new ZipReplayFile(new ReplayStudio(), file);
metaData = archive.metadata().get();
BufferedImage img = archive.thumb().get();
if(img != null) {
thumb = ImageUtils.scaleImage(img, new Dimension(1280, 720));
metaData = archive.getMetaData();
Optional<BufferedImage> img = archive.getThumb();
if(img.isPresent()) {
thumb = ImageUtils.scaleImage(img.get(), new Dimension(1280, 720));
hasThumbnail = true;
}
@@ -307,21 +312,15 @@ public class GuiUploadFile extends GuiScreen implements ProgressUpdateListener {
if(hideServerIP.isChecked()) {
File tmp = File.createTempFile("replay_hidden_ip", "mcpr");
File tmpMeta = File.createTempFile("metadata", "json");
ReplayMetaData newMetaData = metaData.copy();
newMetaData.removeServer();
ReplayFileIO.write(newMetaData, tmpMeta);
HashMap<String, File> toAdd = new HashMap<String, File>();
toAdd.put(ReplayFile.ENTRY_METADATA, tmpMeta);
FileUtils.copyFile(replayFile, tmp);
ReplayFileIO.addFilesToZip(tmp, toAdd);
ReplayMetaData newMetaData = new ReplayMetaData(metaData);
newMetaData.setServerName(null);
ReplayFile replay = new ZipReplayFile(new ReplayStudio(), replayFile);
replay.writeMetaData(newMetaData);
replay.saveTo(tmp);
uploader.uploadFile(GuiUploadFile.this, name, tags, tmp, category, desc);
FileUtils.deleteQuietly(tmpMeta);
FileUtils.deleteQuietly(tmp);
} else {
uploader.uploadFile(GuiUploadFile.this, name, tags, replayFile, category, desc);

View File

@@ -1,41 +0,0 @@
package eu.crushedpixel.replaymod.gui.overlay;
import eu.crushedpixel.replaymod.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.FontRenderer;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.TEXTURE_SIZE;
import static eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay.replay_gui;
/**
* Renders overlay during recording.
*/
public class GuiRecordingOverlay {
private final Minecraft mc;
public GuiRecordingOverlay(Minecraft mc) {
this.mc = mc;
}
/**
* Render the recording icon and text in the top left corner of the screen.
* @param event Rendered post game overlay
*/
@SubscribeEvent
public void renderRecordingIndicator(RenderGameOverlayEvent.Post event) {
if (event.type != RenderGameOverlayEvent.ElementType.ALL) return;
if(ReplayMod.replaySettings.showRecordingIndicator()) {
FontRenderer fontRenderer = mc.fontRendererObj;
fontRenderer.drawString(I18n.format("replaymod.gui.recording").toUpperCase(), 30, 18 - (fontRenderer.FONT_HEIGHT / 2), 0xffffffff);
mc.renderEngine.bindTexture(replay_gui);
GlStateManager.resetColor();
GlStateManager.enableAlpha();
Gui.drawModalRectWithCustomSizedTexture(10, 10, 58, 20, 16, 16, TEXTURE_SIZE, TEXTURE_SIZE);
}
}
}

View File

@@ -1,657 +0,0 @@
package eu.crushedpixel.replaymod.gui.overlay;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.entities.CameraEntity;
import eu.crushedpixel.replaymod.gui.GuiMouseInput;
import eu.crushedpixel.replaymod.gui.GuiRenderSettings;
import eu.crushedpixel.replaymod.gui.GuiReplaySpeedSlider;
import eu.crushedpixel.replaymod.gui.elements.*;
import eu.crushedpixel.replaymod.gui.elements.timelines.GuiKeyframeTimeline;
import eu.crushedpixel.replaymod.gui.elements.timelines.GuiMarkerTimeline;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.SpectatorData;
import eu.crushedpixel.replaymod.holders.TimestampValue;
import eu.crushedpixel.replaymod.registry.KeybindRegistry;
import eu.crushedpixel.replaymod.registry.ReplayGuiRegistry;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.CameraPathValidator;
import eu.crushedpixel.replaymod.utils.MouseUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityOtherPlayerMP;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiChat;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiInventory;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.settings.KeyBinding;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderGameOverlayEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.Point;
import java.awt.Color;
import java.io.IOException;
import java.util.List;
import static net.minecraft.client.renderer.GlStateManager.*;
import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
public class GuiReplayOverlay extends Gui {
private static final Minecraft mc = Minecraft.getMinecraft();
public static final ResourceLocation replay_gui = new ResourceLocation("replaymod", "replay_gui.png");
public static final int TEXTURE_SIZE = 128;
public static final int KEYFRAME_TIMELINE_LENGTH = 30 * 60 * 1000;
public static GuiTexturedButton texturedButton(int x, int y, int u, int v, int size, Runnable action, String hoverText) {
return new GuiTexturedButton(0, x, y, size, size, replay_gui, u, v, TEXTURE_SIZE, TEXTURE_SIZE, action, I18n.format(hoverText));
}
private final Point screenDimensions = MouseUtils.getScaledDimensions();
private final int WIDTH = screenDimensions.getX();
private final int HEIGHT = screenDimensions.getY();
// Top row
private final int TOP_ROW = 10;
private final int BUTTON_PLAY_PAUSE_X = 10;
private final int SPEED_X = 35;
private final int SPEED_WIDTH = 100;
private final int TIMELINE_X = SPEED_X + SPEED_WIDTH + 5;
// Bottom row
private final int BOTTOM_ROW = TOP_ROW + 33;
private final int BUTTON_PLAY_PATH_X = 10;
private final int BUTTON_EXPORT_X = BUTTON_PLAY_PATH_X + 25;
private final int BUTTON_PLACE_X = BUTTON_EXPORT_X + 25;
private final int BUTTON_TIME_X = BUTTON_PLACE_X + 25;
private final int TIMELINE_REAL_X = BUTTON_TIME_X + 25;
private final int TIMELINE_REAL_WIDTH = WIDTH - 14 - 11 - TIMELINE_REAL_X;
private final GuiElement buttonPlayPause = new DelegatingElement() {
private final GuiElement buttonPlay = texturedButton(BUTTON_PLAY_PAUSE_X, TOP_ROW, 0, 0, 20, new Runnable() {
@Override
public void run() {
ReplayMod.replaySender.setReplaySpeed(speedSlider.getSliderValue());
}
}, "replaymod.gui.ingame.menu.unpause");
private final GuiElement buttonPause = texturedButton(BUTTON_PLAY_PAUSE_X, TOP_ROW, 0, 20, 20, new Runnable() {
@Override
public void run() {
ReplayMod.replaySender.setReplaySpeed(0);
}
}, "replaymod.gui.ingame.menu.pause");
@Override
public GuiElement delegate() {
return ReplayMod.replaySender.paused() ? buttonPlay : buttonPause;
}
};
private final GuiElement buttonExport = texturedButton(BUTTON_EXPORT_X, BOTTOM_ROW, 40, 0, 20, new Runnable() {
@Override
public void run() {
try {
CameraPathValidator.validateCameraPath(ReplayHandler.getPositionKeyframes(), ReplayHandler.getTimeKeyframes());
} catch(CameraPathValidator.InvalidCameraPathException e) {
e.printToChat();
return;
}
mc.displayGuiScreen(new GuiRenderSettings());
}
}, "replaymod.gui.ingame.menu.renderpath");
private final GuiElement buttonPlayPausePath = new DelegatingElement() {
private final GuiElement buttonPlay = texturedButton(BUTTON_PLAY_PATH_X, BOTTOM_ROW, 0, 0, 20, new Runnable() {
@Override
public void run() {
ReplayHandler.startPath(null, GuiScreen.isCtrlKeyDown());
}
}, "replaymod.gui.ingame.menu.playpath");
private final GuiElement buttonPlayFromStart = texturedButton(BUTTON_PLAY_PATH_X, BOTTOM_ROW, 0, 0, 20, new Runnable() {
@Override
public void run() {
ReplayHandler.startPath(null, GuiScreen.isCtrlKeyDown());
}
}, "replaymod.gui.ingame.menu.playpathfromstart");
private final GuiElement buttonPause = texturedButton(BUTTON_PLAY_PATH_X, BOTTOM_ROW, 0, 20, 20, new Runnable() {
@Override
public void run() {
ReplayHandler.interruptReplay();
}
}, "replaymod.gui.ingame.menu.pausepath");
@Override
public GuiElement delegate() {
return ReplayHandler.isInPath() ? buttonPause : GuiScreen.isCtrlKeyDown() ? buttonPlayFromStart : buttonPlay;
}
};
private final GuiElement buttonPlace = new DelegatingElement() {
private final GuiElement buttonNotSelected = texturedButton(BUTTON_PLACE_X, BOTTOM_ROW, 0, 40, 20, new Runnable() {
@Override
public void run() {
Entity cam = mc.getRenderViewEntity();
if (cam != null) {
AdvancedPosition position = new AdvancedPosition(cam.posX, cam.posY, cam.posZ, cam.rotationPitch,
cam.rotationYaw % 360, ReplayHandler.getCameraTilt());
if (ReplayHandler.isCamera())
ReplayHandler.addKeyframe(new Keyframe<AdvancedPosition>(ReplayHandler.getRealTimelineCursor(), position));
else
ReplayHandler.addKeyframe(new Keyframe<AdvancedPosition>(ReplayHandler.getRealTimelineCursor(), new SpectatorData(cam)));
}
}
}, "replaymod.gui.ingame.menu.addposkeyframe");
private final GuiElement buttonSelected = texturedButton(BUTTON_PLACE_X, BOTTOM_ROW, 0, 60, 20, new Runnable() {
@Override
public void run() {
ReplayHandler.removeKeyframe(ReplayHandler.getSelectedKeyframe());
}
}, "replaymod.gui.ingame.menu.removeposkeyframe");
private final GuiElement buttonSpectatorNotSelected = texturedButton(BUTTON_PLACE_X, BOTTOM_ROW, 40, 40, 20, new Runnable() {
@Override
public void run() {
Entity cam = mc.getRenderViewEntity();
if (cam != null) {
AdvancedPosition position = new AdvancedPosition(cam.posX, cam.posY, cam.posZ, cam.rotationPitch,
cam.rotationYaw % 360, ReplayHandler.getCameraTilt());
if (ReplayHandler.isCamera())
ReplayHandler.addKeyframe(new Keyframe<AdvancedPosition>(ReplayHandler.getRealTimelineCursor(), position));
else
ReplayHandler.addKeyframe(new Keyframe<AdvancedPosition>(ReplayHandler.getRealTimelineCursor(), new SpectatorData(cam)));
}
}
}, "replaymod.gui.ingame.menu.addspeckeyframe");
private final GuiElement buttonSpectatorSelected = texturedButton(BUTTON_PLACE_X, BOTTOM_ROW, 40, 60, 20, new Runnable() {
@Override
public void run() {
ReplayHandler.removeKeyframe(ReplayHandler.getSelectedKeyframe());
}
}, "replaymod.gui.ingame.menu.removespeckeyframe");
@Override
public GuiElement delegate() {
boolean selected = ReplayHandler.getSelectedKeyframe() != null && ReplayHandler.getSelectedKeyframe().getValue() instanceof AdvancedPosition;
boolean camera;
if(selected) {
camera = !(ReplayHandler.getSelectedKeyframe().getValue() instanceof SpectatorData);
} else {
camera = ReplayHandler.isCamera();
}
if(camera) {
return selected ? buttonSelected : buttonNotSelected;
} else {
return selected ? buttonSpectatorSelected : buttonSpectatorNotSelected;
}
}
};
private final GuiElement buttonTime = new DelegatingElement() {
private final GuiElement buttonNotSelected = texturedButton(BUTTON_TIME_X, BOTTOM_ROW, 0, 80, 20, new Runnable() {
@Override
public void run() {
ReplayHandler.addKeyframe(new Keyframe<TimestampValue>(ReplayHandler.getRealTimelineCursor(), new TimestampValue(ReplayMod.replaySender.currentTimeStamp())));
}
}, "replaymod.gui.ingame.menu.addtimekeyframe");
private final GuiElement buttonSelected = texturedButton(BUTTON_TIME_X, BOTTOM_ROW, 0, 100, 20, new Runnable() {
@Override
public void run() {
ReplayHandler.removeKeyframe(ReplayHandler.getSelectedKeyframe());
}
}, "replaymod.gui.ingame.menu.removetimekeyframe");
@Override
public GuiElement delegate() {
return ReplayHandler.getSelectedKeyframe() != null && ReplayHandler.getSelectedKeyframe().getValue() instanceof TimestampValue ? buttonSelected : buttonNotSelected;
}
};
private final GuiElement buttonZoomIn = texturedButton(WIDTH - 14 - 9, BOTTOM_ROW, 40, 20, 9, new Runnable() {
@Override
public void run() {
timelineReal.zoomIn();
}
}, "replaymod.gui.ingame.menu.zoomin");
private final GuiElement buttonZoomOut = texturedButton(WIDTH - 14 - 9, BOTTOM_ROW + 11, 40, 30, 9, new Runnable() {
@Override
public void run() {
timelineReal.zoomOut();
}
}, "replaymod.gui.ingame.menu.zoomout");
private final GuiMarkerTimeline timeline = new GuiMarkerTimeline(TIMELINE_X, TOP_ROW - 1, WIDTH - 14 - TIMELINE_X, 22, false);
private final GuiKeyframeTimeline timelineReal = new GuiKeyframeTimeline(TIMELINE_REAL_X, BOTTOM_ROW - 1, TIMELINE_REAL_WIDTH, 22, true, true, true);
{
timelineReal.timelineLength = KEYFRAME_TIMELINE_LENGTH;
}
private final GuiScrollbar scrollbar = new GuiScrollbar(TIMELINE_REAL_X, BOTTOM_ROW + 22, TIMELINE_REAL_WIDTH) {
@Override
public void dragged() {
timelineReal.timeStart = scrollbar.sliderPosition;
}
};
private final GuiReplaySpeedSlider speedSlider = new GuiReplaySpeedSlider(SPEED_X, TOP_ROW, I18n.format("replaymod.gui.speed"));
public double getSpeedSliderValue() {
return speedSlider.getSliderValue();
}
private boolean toolbarOpen = false;
private final DelegatingElement toolbar = new DelegatingElement() {
private void toggleOpen() {
toolbarOpen = !toolbarOpen;
}
private GuiElement buttonOpenToolbar = new GuiArrowButton(-1, 10, HEIGHT-10-20, "", GuiArrowButton.Direction.UP) {
@Override
public void performAction() {
toggleOpen();
}
};
private GuiElement buttonCloseToolbar = new GuiArrowButton(-1, 10, HEIGHT-10-20, "", GuiArrowButton.Direction.DOWN) {
@Override
public void performAction() {
toggleOpen();
}
};
private ComposedElement openElements = new ComposedElement(buttonCloseToolbar);
private int maxButtonY = -1;
{
int buttonX = 10;
int maxWidth = 0;
int i = 0;
for(final KeyBinding kb : KeybindRegistry.getReplayModKeyBindings()) {
int buttonY = HEIGHT-55-(i*25);
if(buttonY < 80) {
buttonX += 25 + maxWidth + 5;
maxWidth = 0;
i = 0;
buttonY = HEIGHT-55-(i*25);
}
if(buttonY < maxButtonY || maxButtonY == -1) maxButtonY = buttonY;
String keyName = "???";
try {
keyName = Keyboard.getKeyName(kb.getKeyCode());
} catch (ArrayIndexOutOfBoundsException e) {
// Apparently windows likes to press strange keys, see https://www.replaymod.com/forum/thread/55
}
GuiElement button = new GuiAdvancedButton(buttonX, buttonY, 20, 20, keyName, new Runnable() {
@Override
public void run() {
ReplayMod.keyInputHandler.handleCustomKeybindings(kb, false, kb.getKeyCode());
}
}, null);
String stringText = I18n.format(kb.getKeyDescription());
int stringWidth = mc.fontRendererObj.getStringWidth(stringText);
if(stringWidth > maxWidth) {
maxWidth = stringWidth;
}
GuiString string = new GuiString(buttonX+25, buttonY+6, Color.WHITE, stringText);
openElements.addPart(button);
openElements.addPart(string);
i++;
}
}
@Override
public GuiElement delegate() {
if(toolbarOpen) {
return openElements;
} else {
return buttonOpenToolbar;
}
}
@Override
public void draw(Minecraft mc, int mouseX, int mouseY) {
if(toolbarOpen) {
drawGradientRect(0, maxButtonY - 10, WIDTH, HEIGHT, -1072689136, -804253680);
}
super.draw(mc, mouseX, mouseY);
}
};
public void closeToolbar() {
toolbarOpen = false;
}
private final GuiElement content = new ComposedElement(buttonPlayPause, buttonExport, buttonPlace, buttonTime,
buttonPlayPausePath, buttonZoomIn, buttonZoomOut, timeline, timelineReal, scrollbar, speedSlider, toolbar);
public boolean isVisible() {
return ReplayHandler.isInReplay();
}
/**
* Resets the UI.
* @param resetElements Whether the timeline and Speed Slider should be reset as well
*/
public void resetUI(boolean resetElements) {
if(FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
mc.displayGuiScreen(null);
}
if (resetElements) {
timelineReal.zoom = 0.033f;
timelineReal.timeStart = 0;
ReplayHandler.setRealTimelineCursor(0);
speedSlider.reset();
}
}
public void register() {
FMLCommonHandler.instance().bus().register(this);
MinecraftForge.EVENT_BUS.register(this);
}
public void unregister() {
FMLCommonHandler.instance().bus().unregister(this);
MinecraftForge.EVENT_BUS.unregister(this);
}
private void checkResize() {
if (!screenDimensions.equals(MouseUtils.getScaledDimensions())) {
GuiReplayOverlay other = new GuiReplayOverlay();
other.timelineReal.zoom = this.timelineReal.zoom;
other.timelineReal.timeStart = this.timelineReal.timeStart;
other.speedSlider.copyValueFrom(this.speedSlider);
this.unregister();
other.register();
ReplayMod.overlay = other;
if (mc.currentScreen instanceof GuiMouseInput) {
mc.displayGuiScreen(new GuiMouseInput(other));
}
}
}
@SubscribeEvent
public void onRenderTabList(RenderGameOverlayEvent.Pre event) { //cancelling tab list rendering and rendering help instead
if (!isVisible()) return;
if (event.type == RenderGameOverlayEvent.ElementType.PLAYER_LIST) {
event.setCanceled(true);
}
}
private void tick() {
if (FMLClientHandler.instance().isGUIOpen(GuiMouseInput.class)) {
Entity player = ReplayHandler.getCameraEntity();
if(player != null) {
player.setVelocity(0, 0, 0);
}
}
checkResize();
}
public void mouseDrag(int mouseX, int mouseY, int button) {
content.mouseDrag(mc, mouseX, mouseY, button);
}
public void mouseReleased(int mouseX, int mouseY, int button) {
content.mouseRelease(mc, mouseX, mouseY, button);
}
public void mouseClicked(int mouseX, int mouseY, int button) {
if (ReplayHandler.isInPath()) { // Only allow clicking of cancel button during path replay
buttonPlayPausePath.mouseClick(mc, mouseX, mouseY, button);
} else {
content.mouseClick(mc, mouseX, mouseY, button);
}
}
public void performJump(long timelineTime) {
performJump(timelineTime, true);
}
public void performJump(long timelineTime, boolean setLastPosition) {
if (timelineTime != -1) { // Click on timeline
//When hurrying, no Timeline jumping etc. is possible
if(!ReplayMod.replaySender.isHurrying()) {
if(timelineTime < ReplayMod.replaySender.currentTimeStamp()) {
mc.displayGuiScreen(null);
}
if(setLastPosition) {
CameraEntity cam = ReplayHandler.getCameraEntity();
if(cam != null) {
ReplayHandler.setLastPosition(new AdvancedPosition(cam.posX, cam.posY, cam.posZ, cam.rotationPitch, cam.rotationYaw), false);
} else {
ReplayHandler.setLastPosition(null, false);
}
}
long diff = timelineTime - ReplayMod.replaySender.getDesiredTimestamp();
if(diff != 0) {
if (diff > 0 && diff < 5000) { // Small difference and no time travel
ReplayMod.replaySender.jumpToTime((int) timelineTime);
} else { // We either have to restart the replay or send a significant amount of packets
// Render our please-wait-screen
GuiScreen guiScreen = new GuiScreen() {
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
drawBackground(0);
drawCenteredString(fontRendererObj, I18n.format("replaymod.gui.pleasewait"),
width / 2, height / 2, 0xffffffff);
}
};
// Make sure that the replaysender changes into sync mode
ReplayMod.replaySender.setSyncModeAndWait();
// Perform the rendering using OpenGL
pushMatrix();
clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
enableTexture2D();
mc.getFramebuffer().bindFramebuffer(true);
mc.entityRenderer.setupOverlayRendering();
guiScreen.setWorldAndResolution(mc, WIDTH, HEIGHT);
guiScreen.drawScreen(0, 0, 0);
mc.getFramebuffer().unbindFramebuffer();
popMatrix();
pushMatrix();
mc.getFramebuffer().framebufferRender(mc.displayWidth, mc.displayHeight);
popMatrix();
Display.update();
// Send the packets
ReplayMod.replaySender.sendPacketsTill((int) timelineTime);
ReplayMod.replaySender.setAsyncMode(true);
ReplayMod.replaySender.setReplaySpeed(0);
mc.getNetHandler().getNetworkManager().processReceivedPackets();
@SuppressWarnings("unchecked")
List<Entity> entities = (List<Entity>) mc.theWorld.loadedEntityList;
for (Entity entity : entities) {
if (entity instanceof EntityOtherPlayerMP) {
EntityOtherPlayerMP e = (EntityOtherPlayerMP) entity;
e.setPosition(e.otherPlayerMPX, e.otherPlayerMPY, e.otherPlayerMPZ);
e.rotationYaw = (float) e.otherPlayerMPYaw;
e.rotationPitch = (float) e.otherPlayerMPPitch;
}
entity.lastTickPosX = entity.prevPosX = entity.posX;
entity.lastTickPosY = entity.prevPosY = entity.posY;
entity.lastTickPosZ = entity.prevPosZ = entity.posZ;
entity.prevRotationYaw = entity.rotationYaw;
entity.prevRotationPitch = entity.rotationPitch;
}
try {
mc.runTick();
} catch (IOException e) {
e.printStackTrace(); // This should never be thrown but whatever
}
//finally, updating the camera's position (which is not done by the sync jumping)
ReplayHandler.moveCameraToLastPosition();
// No need to remove our please-wait-screen. It'll vanish with the next
// render pass as it's never been a real GuiScreen in the first place.
}
}
}
}
}
@SubscribeEvent
public void onRenderGui(RenderGameOverlayEvent.Post event) throws IllegalArgumentException, IllegalAccessException {
if (event.type != RenderGameOverlayEvent.ElementType.ALL) return;
if (!isVisible()) return;
FMLClientHandler fml = FMLClientHandler.instance();
tick();
// Do not draw if GUI doesn't want us to
if(mc.currentScreen instanceof NoOverlay) {
return;
}
// If we are not currently spectating someone
if (ReplayHandler.isCamera()) {
ReplayGuiRegistry.hide(); // hide all normal UI
} else {
ReplayGuiRegistry.show(); // otherwise show them
}
// Replace chat and inventory GUI (opened by pressing the respective hotkey) with a dummy input GUI
if(fml.isGUIOpen(GuiChat.class) || fml.isGUIOpen(GuiInventory.class)) {
mc.displayGuiScreen(new GuiMouseInput(this));
}
GlStateManager.resetColor();
Point mousePoint = MouseUtils.getMousePos();
int mouseX = mousePoint.getX();
int mouseY = mousePoint.getY();
if (!(mc.currentScreen instanceof GuiMouseInput)) {
// We only react to the mouse if our gui screen is opened.
// Otherwise we just move the mouse away so it doesn't activate any buttons
mouseX = mouseY = -1000;
}
// Setup scrollbar and timelines
if (timelineReal.timeStart + timelineReal.zoom > 1) {
timelineReal.timeStart = 1 - timelineReal.zoom;
}
scrollbar.size = timelineReal.zoom;
scrollbar.sliderPosition = timelineReal.timeStart;
timeline.cursorPosition = ReplayMod.replaySender.currentTimeStamp();
timeline.timelineLength = ReplayMod.replaySender.replayLength();
timelineReal.cursorPosition = ReplayHandler.getRealTimelineCursor();
// Draw all elements
content.draw(mc, mouseX, mouseY);
content.drawOverlay(mc, mouseX, mouseY);
GlStateManager.enableBlend();
}
public void togglePlayPause() {
if (ReplayMod.replaySender.paused()) {
ReplayMod.replaySender.setReplaySpeed(speedSlider.getSliderValue());
} else {
ReplayMod.replaySender.setReplaySpeed(0);
}
}
/**
* Render the Ambient Lighting and Path Preview indicators in the lower right corner.
* @param event Rendered post game overlay
*/
@SubscribeEvent
public void renderIndicators(RenderGameOverlayEvent.Post event) {
if (event.type != RenderGameOverlayEvent.ElementType.ALL) return;
if(!ReplayHandler.isInReplay() || mc.currentScreen instanceof NoOverlay) return;
int xPos = WIDTH-10;
if(ReplayMod.replaySettings.isLightingEnabled()) {
int width = 19;
mc.renderEngine.bindTexture(replay_gui);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.enableAlpha();
GlStateManager.disableLighting();
Gui.drawModalRectWithCustomSizedTexture(xPos-width, HEIGHT - 10 - 13,
90, 20, 19, 13, TEXTURE_SIZE, TEXTURE_SIZE);
xPos -= width + 5;
}
if(ReplayMod.replaySettings.showPathPreview()) {
int width = 20;
mc.renderEngine.bindTexture(replay_gui);
GlStateManager.color(1, 1, 1, 1);
GlStateManager.enableAlpha();
GlStateManager.disableLighting();
Gui.drawModalRectWithCustomSizedTexture(xPos - width, HEIGHT - 10 - 13,
100, 0, 20, 13, TEXTURE_SIZE, TEXTURE_SIZE);
//noinspection UnusedAssignment
xPos -= width + 5;
}
//can be continued
}
/**
* Dummy interface for GUI on which this replay overlay shall not be rendered.
*/
public interface NoOverlay {
}
}

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui.replayeditor;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.gui.elements.GuiProgressBar;
import net.minecraft.client.gui.GuiButton;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.gui.replayeditor;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.GuiConstants;
import eu.crushedpixel.replaymod.gui.elements.GuiDropdown;
import eu.crushedpixel.replaymod.holders.GuiEntryListStringEntry;

View File

@@ -1,101 +0,0 @@
package eu.crushedpixel.replaymod.gui.replayviewer;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiTextField;
import net.minecraft.client.resources.I18n;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.lwjgl.input.Keyboard;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class GuiRenameReplay extends GuiScreen {
private GuiScreen parent;
private GuiTextField replayNameInput;
private File file;
public GuiRenameReplay(GuiScreen parent, File file) {
this.parent = parent;
this.file = file;
}
@Override
public void updateScreen() {
this.replayNameInput.updateCursorCounter();
}
@Override
public void initGui() {
Keyboard.enableRepeatEvents(true);
@SuppressWarnings("unchecked")
List<GuiButton> buttonList = this.buttonList;
buttonList.clear();
buttonList.add(new GuiButton(0, this.width / 2 - 100, this.height / 4 + 96 + 12, I18n.format("replaymod.gui.rename")));
buttonList.add(new GuiButton(1, this.width / 2 - 100, this.height / 4 + 120 + 12, I18n.format("replaymod.gui.cancel")));
String s = FilenameUtils.getBaseName(file.getAbsolutePath());
this.replayNameInput = new GuiTextField(2, this.fontRendererObj, this.width / 2 - 100, 60, 200, 20);
this.replayNameInput.setFocused(true);
this.replayNameInput.setText(s);
}
@Override
public void onGuiClosed() {
Keyboard.enableRepeatEvents(false);
}
@Override
protected void actionPerformed(GuiButton button) throws IOException {
if(button.enabled) {
if(button.id == 1) {
this.mc.displayGuiScreen(this.parent);
} else if(button.id == 0) {
File folder = ReplayFileIO.getReplayFolder();
File initRenamed = new File(folder, (this.replayNameInput.getText().trim() + ReplayFile.ZIP_FILE_EXTENSION).replaceAll("[^a-zA-Z0-9\\.\\- ]", "_"));
File renamed = ReplayFileIO.getNextFreeFile(initRenamed);
try {
FileUtils.moveFile(file, renamed);
} catch (IOException e) {
e.printStackTrace();
mc.displayGuiScreen(new GuiErrorScreen(
I18n.format("replaymod.gui.viewer.delete.failed1"),
I18n.format("replaymod.gui.viewer.delete.failed2")
));
return;
}
this.mc.displayGuiScreen(this.parent);
}
}
}
@Override
protected void keyTyped(char typedChar, int keyCode) throws IOException {
this.replayNameInput.textboxKeyTyped(typedChar, keyCode);
((GuiButton) this.buttonList.get(0)).enabled = this.replayNameInput.getText().trim().length() > 0;
if(keyCode == 28 || keyCode == 156) {
this.actionPerformed((GuiButton) this.buttonList.get(0));
}
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton);
this.replayNameInput.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
this.drawDefaultBackground();
this.drawCenteredString(this.fontRendererObj, I18n.format("replaymod.gui.viewer.rename.title"), this.width / 2, 20, 16777215);
this.drawString(this.fontRendererObj, I18n.format("replaymod.gui.viewer.rename.name"), this.width / 2 - 100, 47, 10526880);
this.replayNameInput.drawTextBox();
super.drawScreen(mouseX, mouseY, partialTicks);
}
}

View File

@@ -1,351 +0,0 @@
package eu.crushedpixel.replaymod.gui.replayviewer;
import com.mojang.realmsclient.util.Pair;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.api.replay.holders.FileInfo;
import eu.crushedpixel.replaymod.gui.GuiReplaySettings;
import eu.crushedpixel.replaymod.gui.elements.GuiLoadingListEntry;
import eu.crushedpixel.replaymod.gui.elements.GuiReplayListEntry;
import eu.crushedpixel.replaymod.gui.elements.GuiReplayListExtended;
import eu.crushedpixel.replaymod.gui.online.GuiUploadFile;
import eu.crushedpixel.replaymod.recording.ReplayMetaData;
import eu.crushedpixel.replaymod.registry.ResourceHelper;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.ImageUtils;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.GuiYesNo;
import net.minecraft.client.gui.GuiYesNoCallback;
import net.minecraft.client.resources.I18n;
import net.minecraft.util.Util;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.lwjgl.Sys;
import org.lwjgl.input.Keyboard;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
public class GuiReplayViewer extends GuiScreen implements GuiYesNoCallback {
private static final int LOAD_BUTTON_ID = 9001;
private static final int UPLOAD_BUTTON_ID = 9002;
private static final int FOLDER_BUTTON_ID = 9003;
private static final int RENAME_BUTTON_ID = 9004;
private static final int DELETE_BUTTON_ID = 9005;
private static final int SETTINGS_BUTTON_ID = 9006;
private static final int CANCEL_BUTTON_ID = 9007;
private boolean initialized;
private GuiReplayListExtended replayGuiList;
private List<Pair<Pair<File, ReplayMetaData>, File>> replayFileList = new ArrayList<Pair<Pair<File, ReplayMetaData>, File>>();
private GuiButton loadButton;
private GuiButton uploadButton;
private GuiButton renameButton;
private GuiButton deleteButton;
private boolean delete_file = false;
private Queue<Runnable> loadedReplaysQueue = new ConcurrentLinkedQueue<Runnable>();
private Thread fileReloader;
private class FileReloaderThread extends Thread {
private final GuiLoadingListEntry loadingListEntry = new GuiLoadingListEntry();
@Override
public synchronized void start() {
replayFileList = new ArrayList<Pair<Pair<File, ReplayMetaData>, File>>();
replayGuiList.clearEntries();
replayGuiList.addEntry(loadingListEntry);
super.start();
}
@Override
public void run() {
for(final File file : ReplayFileIO.getAllReplayFiles()) {
if(interrupted()) break;
try {
ReplayFile replayFile = new ReplayFile(file);
final ReplayMetaData metaData = replayFile.metadata().get();
BufferedImage img = replayFile.thumb().get();
replayFile.close();
File tmp = null;
if(img != null) {
img = ImageUtils.scaleImage(img, new Dimension(1280, 720));
tmp = File.createTempFile(FilenameUtils.getBaseName(file.getAbsolutePath())+"_THUMBNAIL", "jpg");
tmp.deleteOnExit();
ImageIO.write(img, "jpg", tmp);
}
final File thumb = tmp;
loadedReplaysQueue.offer(new Runnable() {
@Override
public void run() {
addEntry(file, metaData, thumb);
}
});
} catch(Exception e) {
FMLLog.getLogger().error("Could not load Replay File "+file.getName(), e);
}
}
loadedReplaysQueue.offer(new Runnable() {
@Override
public void run() {
replayGuiList.removeEntry(loadingListEntry);
}
});
}
}
public static GuiYesNo getYesNoGui(GuiYesNoCallback p_152129_0_, String file, int p_152129_2_) {
String s1 = I18n.format("replaymod.gui.viewer.delete.linea");
String s2 = "\'" + file + "\' " + I18n.format("replaymod.gui.viewer.delete.lineb");
String s3 = I18n.format("replaymod.gui.delete");
String s4 = I18n.format("replaymod.gui.cancel");
return new GuiYesNo(p_152129_0_, s1, s2, s3, s4, p_152129_2_);
}
@Override
public void onGuiClosed() {
ResourceHelper.freeAllResources();
super.onGuiClosed();
}
@Override
@SuppressWarnings("deprecation")
public void initGui() {
Keyboard.enableRepeatEvents(true);
if(!this.initialized) {
replayGuiList = new ReplayList(this, this.mc, this.width, this.height, 32, this.height - 64, 36);
this.initialized = true;
} else {
this.replayGuiList.setDimensions(this.width, this.height, 32, this.height - 64);
}
try {
if(fileReloader != null) {
fileReloader.interrupt();
fileReloader.join();
}
fileReloader = new FileReloaderThread();
fileReloader.start();
} catch(Exception e) {
e.printStackTrace();
}
this.createButtons();
}
private void createButtons() {
@SuppressWarnings("unchecked")
List<GuiButton> buttonList = this.buttonList;
buttonList.add(loadButton = new GuiButton(LOAD_BUTTON_ID, this.width / 2 - 154, this.height - 52, 73, 20, I18n.format("replaymod.gui.load")));
buttonList.add(uploadButton = new GuiButton(UPLOAD_BUTTON_ID, this.width / 2 - 154 + 78, this.height - 52, 73, 20, I18n.format("replaymod.gui.upload")));
buttonList.add(new GuiButton(FOLDER_BUTTON_ID, this.width / 2 + 4, this.height - 52, 150, 20, I18n.format("replaymod.gui.viewer.replayfolder")));
buttonList.add(renameButton = new GuiButton(RENAME_BUTTON_ID, this.width / 2 - 154, this.height - 28, 72, 20, I18n.format("replaymod.gui.rename")));
buttonList.add(deleteButton = new GuiButton(DELETE_BUTTON_ID, this.width / 2 - 76, this.height - 28, 72, 20, I18n.format("replaymod.gui.delete")));
buttonList.add(new GuiButton(SETTINGS_BUTTON_ID, this.width / 2 + 4, this.height - 28, 72, 20, I18n.format("replaymod.gui.settings")));
buttonList.add(new GuiButton(CANCEL_BUTTON_ID, this.width / 2 + 4 + 78, this.height - 28, 72, 20, I18n.format("replaymod.gui.cancel")));
setButtonsEnabled(false);
}
@Override
public void handleMouseInput() throws IOException {
super.handleMouseInput();
this.replayGuiList.handleMouseInput();
}
@Override
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
super.mouseClicked(mouseX, mouseY, mouseButton);
this.replayGuiList.mouseClicked(mouseX, mouseY, mouseButton);
}
@Override
protected void mouseReleased(int mouseX, int mouseY, int state) {
super.mouseReleased(mouseX, mouseY, state);
this.replayGuiList.mouseReleased(mouseX, mouseY, state);
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
this.drawDefaultBackground();
this.replayGuiList.drawScreen(mouseX, mouseY, partialTicks);
this.drawCenteredString(this.fontRendererObj, I18n.format("replaymod.gui.replayviewer"), this.width / 2, 20, 16777215);
super.drawScreen(mouseX, mouseY, partialTicks);
if(uploadButton.isMouseOver() && !uploadButton.enabled && loadButton.enabled) {
if(currentFileUploaded) {
ReplayMod.tooltipRenderer.drawTooltip(mouseX, mouseY, I18n.format("replaymod.gui.viewer.alreadyuploaded"), this, Color.RED);
}
}
}
@Override
protected void actionPerformed(GuiButton button) throws IOException {
if(button.enabled) {
if(button.id == LOAD_BUTTON_ID) {
loadReplay(replayGuiList.selected);
} else if(button.id == CANCEL_BUTTON_ID) {
mc.displayGuiScreen(null);
} else if(button.id == DELETE_BUTTON_ID) {
String s = ((GuiReplayListEntry)replayGuiList.getListEntry(replayGuiList.selected)).getFileInfo().getName();
if(s != null) {
delete_file = true;
GuiYesNo guiyesno = getYesNoGui(this, s, 1);
this.mc.displayGuiScreen(guiyesno);
}
} else if(button.id == SETTINGS_BUTTON_ID) {
this.mc.displayGuiScreen(new GuiReplaySettings(this));
} else if(button.id == RENAME_BUTTON_ID) {
File file = replayFileList.get(replayGuiList.selected).first().first();
this.mc.displayGuiScreen(new GuiRenameReplay(this, file));
} else if(button.id == UPLOAD_BUTTON_ID) {
File file = replayFileList.get(replayGuiList.selected).first().first();
this.mc.displayGuiScreen(new GuiUploadFile(file, this));
} else if(button.id == FOLDER_BUTTON_ID) {
File file1 = ReplayFileIO.getReplayFolder();
String s = file1.getAbsolutePath();
if(Util.getOSType() == Util.EnumOS.OSX) {
try {
Runtime.getRuntime().exec(new String[]{"/usr/bin/open", s});
return;
} catch (IOException e) {
LogManager.getLogger().error("Cannot open file", e);
}
} else if(Util.getOSType() == Util.EnumOS.WINDOWS) {
String s1 = String.format("cmd.exe /C start \"Open file\" \"%s\"", s);
try {
Runtime.getRuntime().exec(s1);
return;
} catch(IOException e) {
LogManager.getLogger().error("Cannot open file", e);
}
}
boolean flag = false;
try {
Desktop.getDesktop().browse(file1.toURI());
} catch(Throwable throwable) {
flag = true;
}
if(flag) {
Sys.openURL("file://" + s);
}
}
}
}
@Override
public void confirmClicked(boolean result, int id) {
if(this.delete_file) {
this.delete_file = false;
if(result) {
try {
FileUtils.forceDelete(replayFileList.get(replayGuiList.selected).first().first());
} catch (IOException e) {
e.printStackTrace();
}
replayFileList.remove(replayGuiList.selected);
replayGuiList.selected = -1;
}
this.mc.displayGuiScreen(this);
}
}
@Override
public void updateScreen() {
super.updateScreen();
while (!loadedReplaysQueue.isEmpty()) {
loadedReplaysQueue.poll().run();
}
}
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;
}
public void loadReplay(int id) {
mc.displayGuiScreen(null);
try {
ReplayHandler.startReplay(replayFileList.get(id).first().first());
} catch(Exception e) {
e.printStackTrace();
}
}
private void addEntry(File file, ReplayMetaData metaData, File thumb) {
final Pair<Pair<File, ReplayMetaData>, File> p = Pair.of(Pair.of(file, metaData), thumb);
final int index = getInsertionIndex(p, replayFileList);
replayFileList.add(index, p);
final FileInfo fileInfo = new FileInfo(-1, p.first().second(), null, null,
-1, -1, -1, FilenameUtils.getBaseName(p.first().first().getName()), true, -1);
replayGuiList.addEntry(index, new GuiReplayListEntry(replayGuiList, fileInfo, p.second()));
}
private static FileAgeComparator fileAgeComparator = new FileAgeComparator();
public static class FileAgeComparator implements Comparator<Pair<Pair<File, ReplayMetaData>, File>> {
@Override
public int compare(Pair<Pair<File, ReplayMetaData>, File> o1, Pair<Pair<File, ReplayMetaData>, File> o2) {
try {
return new Date(o2.first().second().getDate()).compareTo(new Date(o1.first().second().getDate()));
} catch(Exception e) {
return 0;
}
}
}
private int getInsertionIndex(Pair<Pair<File, ReplayMetaData>, File> p, List<Pair<Pair<File, ReplayMetaData>, File>> list) {
List<Pair<Pair<File, ReplayMetaData>, File>> nl = new ArrayList<Pair<Pair<File, ReplayMetaData>, File>>(list);
nl.add(p);
Collections.sort(nl, fileAgeComparator);
return nl.indexOf(p);
}
}

View File

@@ -1,29 +0,0 @@
package eu.crushedpixel.replaymod.gui.replayviewer;
import eu.crushedpixel.replaymod.gui.elements.GuiReplayListExtended;
import net.minecraft.client.Minecraft;
public class ReplayList extends GuiReplayListExtended {
private GuiReplayViewer parent;
public ReplayList(GuiReplayViewer parent, Minecraft mcIn,
int p_i45010_2_, int p_i45010_3_, int p_i45010_4_, int p_i45010_5_,
int p_i45010_6_) {
super(mcIn, p_i45010_2_, p_i45010_3_, p_i45010_4_, p_i45010_5_,
p_i45010_6_);
this.parent = parent;
}
@Override
protected void elementClicked(int slotIndex, boolean isDoubleClick,
int mouseX, int mouseY) {
super.elementClicked(slotIndex, isDoubleClick, mouseX, mouseY);
parent.setButtonsEnabled(true);
if(isDoubleClick) {
parent.loadReplay(slotIndex);
}
}
}

View File

@@ -1,33 +0,0 @@
package eu.crushedpixel.replaymod.holders;
import eu.crushedpixel.replaymod.interpolation.GenericLinearInterpolation;
import eu.crushedpixel.replaymod.interpolation.GenericSplineInterpolation;
import eu.crushedpixel.replaymod.interpolation.Interpolation;
import eu.crushedpixel.replaymod.interpolation.KeyframeValue;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Marker implements KeyframeValue {
private String name;
private AdvancedPosition position;
@Override
public KeyframeValue newInstance() {
return new Marker();
}
@Override
public Interpolation getLinearInterpolator() {
return new GenericLinearInterpolation<Marker>();
}
@Override
public Interpolation getCubicInterpolator() {
return new GenericSplineInterpolation<Marker>();
}
}

View File

@@ -1,12 +0,0 @@
package eu.crushedpixel.replaymod.holders;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.UUID;
@Data
@AllArgsConstructor
public class PlayerVisibility {
private UUID[] hidden;
}

View File

@@ -3,8 +3,6 @@ package eu.crushedpixel.replaymod.interpolation;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.SpectatorData;
import eu.crushedpixel.replaymod.holders.TimestampValue;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import lombok.NoArgsConstructor;
import java.util.ListIterator;
@@ -56,17 +54,18 @@ public class AdvancedPositionKeyframeList extends KeyframeList<AdvancedPosition>
spectatorInterpolation = new SpectatorDataInterpolation(linear);
}
int keyframeTimestamp = keyframe.getRealTimestamp();
TimestampValue timestampValue = ReplayHandler.getTimeKeyframes().getInterpolatedValueForTimestamp(keyframeTimestamp, true);
int replayTimestamp = timestampValue == null ? 0 : timestampValue.asInt();
if(firstTimestamp == -1) firstTimestamp = replayTimestamp;
spectatorInterpolation.addPoint(keyframe, replayTimestamp);
if(iterator.hasNext()) {
keyframe = iterator.next();
found = keyframe.getValue() instanceof SpectatorData;
if(!found) completedKeyframes.add(keyframe);
} else {
found = false;
}
// TODO
// TimestampValue timestampValue = ReplayHandler.getTimeKeyframes().getInterpolatedValueForTimestamp(keyframeTimestamp, true);
// int replayTimestamp = timestampValue == null ? 0 : timestampValue.asInt();
// if(firstTimestamp == -1) firstTimestamp = replayTimestamp;
// spectatorInterpolation.addPoint(keyframe, replayTimestamp);
// if(iterator.hasNext()) {
// keyframe = iterator.next();
// found = keyframe.getValue() instanceof SpectatorData;
// if(!found) completedKeyframes.add(keyframe);
// } else {
// found = false;
// }
}
if(spectatorInterpolation != null && spectatorInterpolation.size() > 1) {

View File

@@ -4,7 +4,6 @@ import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.SpectatorData;
import eu.crushedpixel.replaymod.holders.SpectatorDataThirdPersonInfo;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
@@ -58,20 +57,21 @@ public class SpectatorDataInterpolation {
//updating the spectator keyframe's position in the world to smoothly continue the path
//with non-spectator position keyframes
for(Pair<Integer, Keyframe<AdvancedPosition>> pair : points) {
AdvancedPosition entityPosition = ReplayHandler.getEntityPositionTracker().getEntityPositionAtTimestamp(entityID, pair.getKey());
if(entityPosition == null) continue;
//transform the entity position (sry for no dry code :x )
SpectatorDataThirdPersonInfo thirdPersonInfo = ((SpectatorData)pair.getValue().getValue()).getThirdPersonInfo();
//first, rotate the camera pitch and yaw according to the settings
entityPosition.setYaw(entityPosition.getYaw() + thirdPersonInfo.shoulderCamYawOffset);
entityPosition.setPitch(entityPosition.getPitch() + thirdPersonInfo.shoulderCamPitchOffset);
//next, move the camera point to fulfill the specified distance to the entity
entityPosition = entityPosition.getDestination(-1 * thirdPersonInfo.shoulderCamDistance);
pair.getValue().getValue().apply(entityPosition);
// TODO
// AdvancedPosition entityPosition = ReplayHandler.getEntityPositionTracker().getEntityPositionAtTimestamp(entityID, pair.getKey());
// if(entityPosition == null) continue;
//
// //transform the entity position (sry for no dry code :x )
// SpectatorDataThirdPersonInfo thirdPersonInfo = ((SpectatorData)pair.getValue().getValue()).getThirdPersonInfo();
//
// //first, rotate the camera pitch and yaw according to the settings
// entityPosition.setYaw(entityPosition.getYaw() + thirdPersonInfo.shoulderCamYawOffset);
// entityPosition.setPitch(entityPosition.getPitch() + thirdPersonInfo.shoulderCamPitchOffset);
//
// //next, move the camera point to fulfill the specified distance to the entity
// entityPosition = entityPosition.getDestination(-1 * thirdPersonInfo.shoulderCamDistance);
//
// pair.getValue().getValue().apply(entityPosition);
}
//feed the underlying keyframe list with AdvancedPosition Keyframes that are derived from the Spectator Keyframes
@@ -116,17 +116,18 @@ public class SpectatorDataInterpolation {
smoothness = (int)(thirdPersonInfo.shoulderCamSmoothness*1000);
//calculate the Position relative to the Entity
AdvancedPosition entityPosition = ReplayHandler.getEntityPositionTracker().getEntityPositionAtTimestamp(entityID, currentTimestamp);
if(entityPosition == null) continue;
//first, rotate the camera pitch and yaw according to the settings
entityPosition.setYaw(entityPosition.getYaw() + thirdPersonInfo.shoulderCamYawOffset);
entityPosition.setPitch(entityPosition.getPitch() + thirdPersonInfo.shoulderCamPitchOffset);
//next, move the camera point to fulfill the specified distance to the entity
entityPosition = entityPosition.getDestination(-1 * thirdPersonInfo.shoulderCamDistance);
underlyingKeyframes.add(new Keyframe<AdvancedPosition>(interpolatedRealTimestamp, entityPosition));
// TODO
// AdvancedPosition entityPosition = ReplayHandler.getEntityPositionTracker().getEntityPositionAtTimestamp(entityID, currentTimestamp);
// if(entityPosition == null) continue;
//
// //first, rotate the camera pitch and yaw according to the settings
// entityPosition.setYaw(entityPosition.getYaw() + thirdPersonInfo.shoulderCamYawOffset);
// entityPosition.setPitch(entityPosition.getPitch() + thirdPersonInfo.shoulderCamPitchOffset);
//
// //next, move the camera point to fulfill the specified distance to the entity
// entityPosition = entityPosition.getDestination(-1 * thirdPersonInfo.shoulderCamDistance);
//
// underlyingKeyframes.add(new Keyframe<AdvancedPosition>(interpolatedRealTimestamp, entityPosition));
}
i++;

View File

@@ -2,7 +2,7 @@ package eu.crushedpixel.replaymod.localization;
import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableSet;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.api.ApiException;
import net.minecraft.client.resources.IResourcePack;
import net.minecraft.client.resources.data.IMetadataSection;

View File

@@ -1,7 +1,7 @@
package eu.crushedpixel.replaymod.mixin;
import com.replaymod.replay.CameraEntity;
import eu.crushedpixel.replaymod.renderer.SpectatorRenderer;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.settings.RenderOptions;
import eu.crushedpixel.replaymod.video.EntityRendererHandler;
import eu.crushedpixel.replaymod.video.capturer.CubicOpenGlFrameCapturer;
@@ -18,6 +18,7 @@ import net.minecraft.util.MovingObjectPosition;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.glu.Project;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
@@ -25,6 +26,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(EntityRenderer.class)
public abstract class MixinEntityRenderer implements EntityRendererHandler.IEntityRenderer, EntityRendererHandler.GluPerspective {
@Shadow
public Minecraft mc;
private EntityRendererHandler handler;
private SpectatorRenderer spectatorRenderer = new SpectatorRenderer();
@@ -65,8 +69,8 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
if (options.getIgnoreCameraRotation()[1]) {
entity.prevRotationPitch = entity.rotationPitch = 0;
}
if (options.getIgnoreCameraRotation()[2]) {
ReplayHandler.setCameraTilt(0);
if (options.getIgnoreCameraRotation()[2] && entity instanceof CameraEntity) {
((CameraEntity) entity).roll = 0;
}
}
}
@@ -85,7 +89,7 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
orgPitch = entity.rotationPitch;
orgPrevYaw = entity.prevRotationYaw;
orgPrevPitch = entity.prevRotationPitch;
orgRoll = ReplayHandler.getCameraTilt();
orgRoll = entity instanceof CameraEntity ? ((CameraEntity) entity).roll : 0;
}
}
@@ -97,28 +101,31 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
entity.rotationPitch = orgPitch;
entity.prevRotationYaw = orgPrevYaw;
entity.prevRotationPitch = orgPrevPitch;
ReplayHandler.setCameraTilt(orgRoll);
if (entity instanceof CameraEntity) {
((CameraEntity) entity).roll = orgRoll;
}
}
}
@Inject(method = "renderHand", at = @At("HEAD"), cancellable = true)
private void renderSpectatorHand(float partialTicks, int renderPass, CallbackInfo ci) {
if (handler != null) {
if (handler.data instanceof CubicOpenGlFrameCapturer.Data) {
ci.cancel();
return; // No spectator hands during 360° view, we wouldn't even know where to put it
}
Entity currentEntity = Minecraft.getMinecraft().getRenderViewEntity();
if (!ReplayHandler.isCamera() && currentEntity instanceof EntityPlayer) {
renderPass = handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0;
spectatorRenderer.renderSpectatorHand((EntityPlayer) currentEntity, partialTicks, renderPass);
}
} else if (ReplayHandler.isInReplay() && !ReplayHandler.isCamera()) {
Entity currentEntity = Minecraft.getMinecraft().getRenderViewEntity();
if (!ReplayHandler.isCamera() && currentEntity instanceof EntityPlayer) {
spectatorRenderer.renderSpectatorHand((EntityPlayer) currentEntity, partialTicks, renderPass);
}
}
// TODO
// if (handler != null) {
// if (handler.data instanceof CubicOpenGlFrameCapturer.Data) {
// ci.cancel();
// return; // No spectator hands during 360° view, we wouldn't even know where to put it
// }
// Entity currentEntity = Minecraft.getMinecraft().getRenderViewEntity();
// if (!ReplayHandler.isCameraView() && currentEntity instanceof EntityPlayer) {
// renderPass = handler.data == StereoscopicOpenGlFrameCapturer.Data.LEFT_EYE ? 1 : 0;
// spectatorRenderer.renderSpectatorHand((EntityPlayer) currentEntity, partialTicks, renderPass);
// }
// } else if (ReplayHandler.isInReplay() && !ReplayHandler.isCameraView()) {
// Entity currentEntity = Minecraft.getMinecraft().getRenderViewEntity();
// if (!ReplayHandler.isCameraView() && currentEntity instanceof EntityPlayer) {
// spectatorRenderer.renderSpectatorHand((EntityPlayer) currentEntity, partialTicks, renderPass);
// }
// }
}
@Redirect(method = "renderWorldPass", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/RenderGlobal;drawSelectionBox(Lnet/minecraft/entity/player/EntityPlayer;Lnet/minecraft/util/MovingObjectPosition;IF)V"))
@@ -242,8 +249,8 @@ public abstract class MixinEntityRenderer implements EntityRendererHandler.IEnti
@Inject(method = "orientCamera", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/GlStateManager;translate(FFF)V", shift = At.Shift.AFTER, ordinal = 3))
private void setupCameraRoll(float partialTicks, CallbackInfo ci) {
if (ReplayHandler.isInReplay()) {
GL11.glRotated(ReplayHandler.getCameraTilt(), 0D, 0D, 1D);
if (mc.getRenderViewEntity() instanceof CameraEntity) {
GL11.glRotated(((CameraEntity) mc.getRenderViewEntity()).roll, 0D, 0D, 1D);
}
}
}

View File

@@ -1,17 +1,22 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import com.replaymod.replay.CameraEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiSpectator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(GuiSpectator.class)
public abstract class MixinGuiSpectator {
@Shadow
private Minecraft field_175268_g;
@Inject(method = "func_175260_a", at = @At("HEAD"), cancellable = true)
public void isInReplay(int i, CallbackInfo ci) {
if (ReplayHandler.isInReplay()) {
if (field_175268_g.thePlayer instanceof CameraEntity) {
ci.cancel();
}
}

View File

@@ -1,6 +1,5 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundHandler;
import net.minecraft.entity.player.EntityPlayer;
@@ -12,6 +11,7 @@ import org.spongepowered.asm.mixin.injection.Redirect;
public class MixinMinecraft {
@Redirect(method = "runGameLoop", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/audio/SoundHandler;setListener(Lnet/minecraft/entity/player/EntityPlayer;F)V"))
public void setSoundSystemListener(SoundHandler soundHandler, EntityPlayer listener, float renderPartialTicks) {
soundHandler.setListener(ReplayHandler.isInReplay() ? ReplayHandler.getCameraEntity() : listener, renderPartialTicks);
//TODO might no longer be necessary?
// soundHandler.setListener(ReplayHandler.isInReplay() ? ReplayHandler.getCameraEntity() : listener, renderPartialTicks);
}
}

View File

@@ -1,52 +0,0 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.play.server.S07PacketRespawn;
import net.minecraft.network.play.server.S38PacketPlayerListItem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
@Mixin(NetHandlerPlayClient.class)
public abstract class MixinNetHandlerPlayClient {
/**
* Record the own player entity joining the world.
* We cannot use the {@link net.minecraftforge.event.entity.EntityJoinWorldEvent} because the entity id
* of the player is set afterwards and the tablist entry might not yet be sent.
* @param packet The packet
* @param ci Callback info
*/
@Inject(method = "handlePlayerListItem", at=@At("RETURN"))
public void recordOwnJoin(S38PacketPlayerListItem packet, CallbackInfo ci) {
if (ConnectionEventHandler.isRecording() && packet.func_179768_b() == S38PacketPlayerListItem.Action.ADD_PLAYER) {
@SuppressWarnings("unchecked")
List<S38PacketPlayerListItem.AddPlayerData> dataList = packet.func_179767_a();
for (S38PacketPlayerListItem.AddPlayerData data : dataList) {
if (data.func_179962_a().getId().equals(Minecraft.getMinecraft().thePlayer.getGameProfile().getId())) {
ReplayMod.recordingHandler.onPlayerJoin();
}
}
}
}
/**
* Record the own player entity respawning.
* We cannot use the {@link net.minecraftforge.event.entity.EntityJoinWorldEvent} because that would also include
* the first spawn which is already handled by {@link #recordOwnJoin(S38PacketPlayerListItem, CallbackInfo)}.
* @param packet The packet
* @param ci Callback info
*/
@Inject(method = "handleRespawn", at=@At("RETURN"))
public void recordOwnRespawn(S07PacketRespawn packet, CallbackInfo ci) {
if (ConnectionEventHandler.isRecording()) {
ReplayMod.recordingHandler.onPlayerRespawn();
}
}
}

View File

@@ -1,7 +1,7 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.entities.CameraEntity;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import com.replaymod.replay.CameraEntity;
import com.replaymod.replay.ReplayModReplay;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.multiplayer.PlayerControllerMP;
@@ -25,7 +25,7 @@ public abstract class MixinPlayerControllerMP {
@Inject(method = "func_178892_a", at=@At("HEAD"), cancellable = true)
public void createReplayCamera(World worldIn, StatFileWriter statFileWriter, CallbackInfoReturnable<EntityPlayerSP> ci) {
if (ReplayHandler.isInReplay()) {
if (ReplayModReplay.instance.getReplayHandler() != null) {
ci.setReturnValue(new CameraEntity(mc, worldIn, netClientHandler, statFileWriter));
ci.cancel();
}

View File

@@ -1,11 +1,8 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.renderer.culling.ICamera;
import net.minecraft.client.renderer.entity.Render;
import net.minecraft.client.renderer.entity.RenderArrow;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(RenderArrow.class)
@@ -14,8 +11,9 @@ public abstract class MixinRenderArrow extends Render {
super(renderManager);
}
@Override
public boolean shouldRender(Entity entity, ICamera camera, double camX, double camY, double camZ) {
return ReplayHandler.isInReplay() || super.shouldRender(entity, camera, camX, camY, camZ);
}
// TODO
// @Override
// public boolean shouldRender(Entity entity, ICamera camera, double camX, double camY, double camZ) {
// return ReplayHandler.isInReplay() || super.shouldRender(entity, camera, camX, camY, camZ);
// }
}

View File

@@ -1,32 +0,0 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.recording.ConnectionEventHandler;
import eu.crushedpixel.replaymod.timer.EnchantmentTimer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.network.play.server.S25PacketBlockBreakAnim;
import net.minecraft.util.BlockPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(RenderGlobal.class)
public abstract class MixinRenderGlobal {
@Inject(method = "sendBlockBreakProgress", at = @At("HEAD"))
public void saveBlockBreakProgressPacket(int breakerId, BlockPos pos, int progress, CallbackInfo info) {
if(ConnectionEventHandler.isRecording()) {
EntityPlayer thePlayer = Minecraft.getMinecraft().thePlayer;
if(thePlayer != null && breakerId == thePlayer.getEntityId()) {
ConnectionEventHandler.insertPacket(new S25PacketBlockBreakAnim(breakerId, pos, progress));
}
}
}
@Redirect(method = "renderWorldBorder", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;getSystemTime()J"))
private long getEnchantmentTime() {
return EnchantmentTimer.getEnchantmentTime();
}
}

View File

@@ -1,7 +1,5 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.settings.ReplaySettings;
import eu.crushedpixel.replaymod.video.EntityRendererHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.entity.RendererLivingEntity;
@@ -22,17 +20,19 @@ public abstract class MixinRendererLivingEntity {
ci.setReturnValue(false); //this calls the cancel method
}
if(ReplayHandler.isInReplay() && entity.isInvisible()
&& ReplaySettings.ReplayOptions.renderInvisible.getValue() == Boolean.FALSE) {
ci.setReturnValue(false);
}
// TODO
// if(ReplayHandler.isInReplay() && entity.isInvisible()
// && ReplaySettings.ReplayOptions.renderInvisible.getValue() == Boolean.FALSE) {
// ci.setReturnValue(false);
// }
}
@Redirect(method = "renderModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/EntityLivingBase;isInvisibleToPlayer(Lnet/minecraft/entity/player/EntityPlayer;)Z"))
private boolean shouldInvisibleNotBeRendered(EntityLivingBase entity, EntityPlayer thePlayer) {
if(ReplaySettings.ReplayOptions.renderInvisible.getValue() == Boolean.TRUE|| !ReplayHandler.isInReplay()) {
return entity.isInvisibleToPlayer(thePlayer);
}
// TODO
// if(ReplaySettings.ReplayOptions.renderInvisible.getValue() == Boolean.TRUE|| !ReplayHandler.isInReplay()) {
// return entity.isInvisibleToPlayer(thePlayer);
// }
return true; //the original method inverts the return value
}
}

View File

@@ -1,6 +1,5 @@
package eu.crushedpixel.replaymod.mixin;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.renderer.RenderGlobal;
import net.minecraft.client.renderer.ViewFrustum;
import net.minecraft.client.renderer.chunk.IRenderChunkFactory;
@@ -39,9 +38,10 @@ public abstract class MixinViewFrustum {
*/
@Inject(method = "updateChunkPositions", at = @At("HEAD"), cancellable = true)
public void fixedUpdateChunkPositions(double viewEntityX, double viewEntityZ, CallbackInfo ci) {
if (!ReplayHandler.isInReplay()) {
return;
}
// TODO
// if (!ReplayHandler.isInReplay()) {
// return;
// }
int i = MathHelper.floor_double(viewEntityX) - 8;
int j = MathHelper.floor_double(viewEntityZ) - 8;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.online.urischeme;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.StringBuilderWriter;

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.online.urischeme;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.StringBuilderWriter;

View File

@@ -1,130 +0,0 @@
package eu.crushedpixel.replaymod.recording;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.chat.ChatMessageHandler.ChatMessageType;
import eu.crushedpixel.replaymod.gui.overlay.GuiRecordingOverlay;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import io.netty.channel.Channel;
import io.netty.channel.ChannelPipeline;
import net.minecraft.client.Minecraft;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.WorldType;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientConnectedToServerEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientDisconnectionFromServerEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class ConnectionEventHandler {
private static final String packetHandlerKey = "packet_handler";
private static final String DATE_FORMAT = "yyyy_MM_dd_HH_mm_ss";
private static final SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
private static PacketListener packetListener = null;
private static boolean isRecording = false;
private final GuiRecordingOverlay guiOverlay = new GuiRecordingOverlay(Minecraft.getMinecraft());
private static final Logger logger = LogManager.getLogger();
public static boolean isRecording() {
return isRecording;
}
public static void notifyServerPaused() {
if (packetListener != null) {
packetListener.serverWasPaused = true;
}
}
public static void insertPacket(Packet packet) {
if(!isRecording || packetListener == null) {
String reason = isRecording ? " (recording)" : " (null)";
logger.error("Invalid attempt to insert Packet!" + reason);
return;
}
try {
packetListener.saveOnly(packet);
} catch(Exception e) {
e.printStackTrace();
}
}
public static void addMarker() {
if(!isRecording || packetListener == null) {
String reason = isRecording ? " (recording)" : " (null)";
logger.error("Invalid attempt to insert MarkerKeyframe!" + reason);
return;
}
try {
packetListener.addMarker();
} catch(Exception e) {
e.printStackTrace();
}
}
@SubscribeEvent
public void onConnectedToServerEvent(ClientConnectedToServerEvent event) {
ReplayMod.chatMessageHandler.initialize();
ReplayMod.recordingHandler.resetVars();
try {
if(event.isLocal) {
if (MinecraftServer.getServer().getEntityWorld().getWorldType() == WorldType.DEBUG_WORLD) {
logger.info("Debug World recording is not supported.");
return;
}
if(!ReplayMod.replaySettings.isEnableRecordingSingleplayer()) {
logger.info("Singleplayer Recording is disabled");
return;
}
} else {
if(!ReplayMod.replaySettings.isEnableRecordingServer()) {
logger.info("Multiplayer Recording is disabled");
return;
}
}
NetworkManager nm = event.manager;
String worldName;
if(event.isLocal) {
worldName = MinecraftServer.getServer().getWorldName();
} else {
worldName = Minecraft.getMinecraft().getCurrentServerData().serverIP;
}
Channel channel = nm.channel();
ChannelPipeline pipeline = channel.pipeline();
File folder = ReplayFileIO.getReplayFolder();
String fileName = sdf.format(Calendar.getInstance().getTime());
File currentFile = new File(folder, fileName + ReplayFile.TEMP_FILE_EXTENSION);
pipeline.addBefore(packetHandlerKey, "replay_recorder", packetListener = new PacketListener
(currentFile, fileName, worldName, System.currentTimeMillis(), event.isLocal));
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.recordingstarted", ChatMessageType.INFORMATION);
isRecording = true;
MinecraftForge.EVENT_BUS.register(guiOverlay);
} catch(Exception e) {
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.recordingfailed", ChatMessageType.WARNING);
e.printStackTrace();
}
}
@SubscribeEvent
public void onDisconnectedFromServerEvent(ClientDisconnectionFromServerEvent event) {
if (isRecording) {
isRecording = false;
MinecraftForge.EVENT_BUS.unregister(guiOverlay);
packetListener = null;
ReplayMod.chatMessageHandler.stop();
}
}
}

View File

@@ -1,197 +0,0 @@
package eu.crushedpixel.replaymod.recording;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.Marker;
import eu.crushedpixel.replaymod.holders.PacketData;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.*;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public abstract class DataListener extends ChannelInboundHandlerAdapter {
private static final Logger logger = LogManager.getLogger();
protected File file;
protected Long startTime = null;
protected String name;
protected String worldName;
protected boolean serverWasPaused;
protected long lastSentPacket = 0;
protected boolean alive = true;
protected DataWriter dataWriter;
protected Set<String> players = new HashSet<String>();
protected Set<Keyframe<Marker>> markers = new HashSet<Keyframe<Marker>>();
private boolean singleplayer;
private int saveState = 0; //0: Idle, 1: Saving, 2: Saved
private final File tempResourcePacksFolder = Files.createTempDir();
private final Map<Integer, String> requestToHash = new ConcurrentHashMap<Integer, String>();
private final Map<String, File> resourcePacks = new HashMap<String, File>();
public DataListener(File file, String name, String worldName, long startTime, boolean singleplayer) throws FileNotFoundException {
this.file = file;
this.startTime = startTime;
this.name = name;
this.worldName = worldName;
this.singleplayer = singleplayer;
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
DataOutputStream out = new DataOutputStream(bos);
dataWriter = new DataWriter(out);
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
try {
if(saveState == 0) {
System.out.println("Saving Replay File to prevent Corruption");
DataListener.this.channelInactive(null);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}, "shutdown-hook-data-listener"));
}
@Override
public void channelInactive(ChannelHandlerContext ctx) {
dataWriter.requestFinish(players, markers);
}
protected void recordResourcePack(File file, int requestId) {
try {
String hash = Hashing.sha1().hashBytes(Files.toByteArray(file)).toString();
requestToHash.put(requestId, hash);
synchronized (resourcePacks) {
if (!resourcePacks.containsKey(hash)) {
File tempFile = new File(tempResourcePacksFolder, hash);
FileUtils.copyFile(file, tempFile);
resourcePacks.put(hash, tempFile);
}
}
} catch (IOException e) {
logger.warn("Failed to save resource pack.", e);
}
}
public class DataWriter {
private boolean active = true;
private long paused;
private ConcurrentLinkedQueue<PacketData> queue = new ConcurrentLinkedQueue<PacketData>();
private DataOutputStream stream;
Thread outputThread = new Thread(new Runnable() {
@Override
public void run() {
while(active) {
PacketData dataReciever = queue.poll();
if(dataReciever != null) {
//write the ByteBuf to the given OutputStream
byte[] array = dataReciever.getByteArray();
if(array != null) {
try {
ReplayFileIO.writePacket(dataReciever, stream);
stream.flush();
} catch(Exception e) {
e.printStackTrace();
}
}
} else {
try {
//let the Thread sleep for 1/4 second and queue up new Packets
Thread.sleep(250L);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
}
try {
stream.flush();
stream.close();
} catch(Exception e) {
e.printStackTrace();
}
}
}, "replaymod-packet-writer");
public DataWriter(DataOutputStream stream) {
this.stream = stream;
outputThread.start();
}
public synchronized void writePacket(byte[] bytes) {
long now = System.currentTimeMillis();
if(startTime == null) {
startTime = now;
}
if (serverWasPaused) {
paused = now - startTime - lastSentPacket;
serverWasPaused = false;
}
int timestamp = (int) (now - startTime - paused);
lastSentPacket = timestamp;
queue.add(new PacketData(bytes, timestamp));
}
public void requestFinish(Set<String> players, Set<Keyframe<Marker>> markers) {
active = false;
try {
ReplayMod.replayFileAppender.startNewReplayFileWriting();
saveState = 1;
String mcversion = ReplayMod.getMinecraftVersion();
String[] pl = players.toArray(new String[players.size()]);
String generator = "ReplayMod v" + ReplayMod.getContainer().getVersion();
ReplayMetaData metaData = new ReplayMetaData(singleplayer, worldName, generator, (int) lastSentPacket, startTime, pl, mcversion);
File folder = ReplayFileIO.getReplayFolder();
File archive = new File(folder, name + ReplayFile.ZIP_FILE_EXTENSION);
ReplayFileIO.writeReplayFile(archive, file, metaData, markers, resourcePacks, requestToHash);
FileUtils.forceDelete(file);
FileUtils.deleteDirectory(tempResourcePacksFolder);
} catch(Exception e) {
e.printStackTrace();
} finally {
ReplayMod.replayFileAppender.replayFileWritingFinished();
saveState = 2;
}
}
}
}

View File

@@ -1,314 +0,0 @@
package eu.crushedpixel.replaymod.recording;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.chat.ChatMessageHandler;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.Marker;
import eu.crushedpixel.replaymod.replay.Restrictions;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreenWorking;
import net.minecraft.client.gui.GuiYesNo;
import net.minecraft.client.gui.GuiYesNoCallback;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.client.multiplayer.ServerList;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.client.resources.I18n;
import net.minecraft.client.resources.ResourcePackRepository;
import net.minecraft.entity.DataWatcher;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.client.C19PacketResourcePackStatus;
import net.minecraft.network.play.server.*;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.HttpUtil;
import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.UUID;
public class PacketListener extends DataListener {
private static final Minecraft mc = Minecraft.getMinecraft();
private static final Logger logger = LogManager.getLogger();
private ChannelHandlerContext context = null;
private int nextRequestId;
public PacketListener(File file, String name, String worldName, long startTime, boolean singleplayer) throws FileNotFoundException {
super(file, name, worldName, startTime, singleplayer);
}
public void saveOnly(Packet packet) {
try {
if(packet instanceof S0CPacketSpawnPlayer) {
UUID uuid = ((S0CPacketSpawnPlayer) packet).func_179819_c();
players.add(uuid.toString());
}
dataWriter.writePacket(getPacketData(packet));
} catch(Exception e) {
e.printStackTrace();
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if(ctx == null) {
if(context == null) {
return;
} else {
ctx = context;
}
}
this.context = ctx;
if(!alive) {
super.channelRead(ctx, msg);
return;
}
if(msg instanceof Packet) {
try {
Packet packet = (Packet) msg;
if(packet instanceof S0DPacketCollectItem) {
if(mc.thePlayer != null ||
((S0DPacketCollectItem) packet).func_149353_d() == mc.thePlayer.getEntityId()) {
super.channelRead(ctx, msg);
return;
}
}
if(packet instanceof S0CPacketSpawnPlayer) {
UUID uuid = ((S0CPacketSpawnPlayer) packet).func_179819_c();
players.add(uuid.toString());
}
if (packet instanceof S48PacketResourcePackSend) {
S48PacketResourcePackSend p = (S48PacketResourcePackSend) packet;
int requestId = handleResourcePack(p);
saveOnly(new S48PacketResourcePackSend("replay://" + requestId, ""));
return;
}
dataWriter.writePacket(getPacketData(packet));
if (packet instanceof S3FPacketCustomPayload) {
S3FPacketCustomPayload p = (S3FPacketCustomPayload) packet;
if (Restrictions.PLUGIN_CHANNEL.equals(p.getChannelName())) {
packet = new S40PacketDisconnect(new ChatComponentText("Please update to view this replay."));
dataWriter.writePacket(getPacketData(packet));
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
super.channelRead(ctx, msg);
}
@SuppressWarnings("unchecked")
private byte[] getPacketData(Packet packet) {
if(packet instanceof S0FPacketSpawnMob) {
S0FPacketSpawnMob p = (S0FPacketSpawnMob) packet;
if (p.field_149043_l == null) {
p.field_149043_l = new DataWatcher(null);
if(p.func_149027_c() != null) {
for(DataWatcher.WatchableObject wo : (List<DataWatcher.WatchableObject>) p.func_149027_c()) {
p.field_149043_l.addObject(wo.getDataValueId(), wo.getObject());
}
}
}
}
if(packet instanceof S0CPacketSpawnPlayer) {
S0CPacketSpawnPlayer p = (S0CPacketSpawnPlayer) packet;
if (p.field_148960_i == null) {
p.field_148960_i = new DataWatcher(null);
if(p.func_148944_c() != null) {
for(DataWatcher.WatchableObject wo : (List<DataWatcher.WatchableObject>) p.func_148944_c()) {
p.field_148960_i.addObject(wo.getDataValueId(), wo.getObject());
}
}
}
}
return ReplayFileIO.serializePacket(packet);
}
public synchronized int handleResourcePack(S48PacketResourcePackSend packet) {
final int requestId = nextRequestId++;
final NetHandlerPlayClient netHandler = mc.getNetHandler();
final NetworkManager netManager = netHandler.getNetworkManager();
final String url = packet.func_179783_a();
final String hash = packet.func_179784_b();
if (url.startsWith("level://")) {
String levelName = url.substring("level://".length());
File savesDir = new File(mc.mcDataDir, "saves");
final File levelDir = new File(savesDir, levelName);
if (levelDir.isFile()) {
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.ACCEPTED));
Futures.addCallback(mc.getResourcePackRepository().func_177319_a(levelDir), new FutureCallback() {
@Override
public void onSuccess(Object result) {
recordResourcePack(levelDir, requestId);
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.SUCCESSFULLY_LOADED));
}
@Override
public void onFailure(@Nonnull Throwable throwable) {
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.FAILED_DOWNLOAD));
}
});
} else {
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.FAILED_DOWNLOAD));
}
} else {
final ServerData serverData = mc.getCurrentServerData();
if (serverData != null && serverData.getResourceMode() == ServerData.ServerResourceMode.ENABLED) {
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.ACCEPTED));
downloadResourcePackFuture(requestId, url, hash);
} else if (serverData != null && serverData.getResourceMode() != ServerData.ServerResourceMode.PROMPT) {
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.DECLINED));
} else {
mc.addScheduledTask(new Runnable() {
@Override
public void run() {
mc.displayGuiScreen(new GuiYesNo(new GuiYesNoCallback() {
@Override
public void confirmClicked(boolean result, int id) {
if (serverData != null) {
serverData.setResourceMode(result ? ServerData.ServerResourceMode.ENABLED : ServerData.ServerResourceMode.DISABLED);
}
if (result) {
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.ACCEPTED));
downloadResourcePackFuture(requestId, url, hash);
} else {
netManager.sendPacket(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.DECLINED));
}
ServerList.func_147414_b(serverData);
mc.displayGuiScreen(null);
}
}, I18n.format("multiplayer.texturePrompt.line1"), I18n.format("multiplayer.texturePrompt.line2"), 0));
}
});
}
}
return requestId;
}
public void addMarker() {
AdvancedPosition pos = new AdvancedPosition(Minecraft.getMinecraft().getRenderViewEntity());
int timestamp = (int) (System.currentTimeMillis() - startTime);
Keyframe<Marker> marker = new Keyframe<Marker>(timestamp, new Marker(null, pos));
markers.add(marker);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.addedmarker", ChatMessageHandler.ChatMessageType.INFORMATION);
}
private void downloadResourcePackFuture(int requestId, String url, final String hash) {
Futures.addCallback(downloadResourcePack(requestId, url, hash), new FutureCallback() {
@Override
public void onSuccess(Object result) {
mc.getNetHandler().addToSendQueue(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.SUCCESSFULLY_LOADED));
}
@Override
public void onFailure(@Nonnull Throwable throwable) {
mc.getNetHandler().addToSendQueue(new C19PacketResourcePackStatus(hash, C19PacketResourcePackStatus.Action.FAILED_DOWNLOAD));
}
});
}
private ListenableFuture downloadResourcePack(final int requestId, String url, String hash) {
final ResourcePackRepository repo = mc.mcResourcePackRepository;
String fileName;
if (hash.matches("^[a-f0-9]{40}$")) {
fileName = hash;
} else {
fileName = url.substring(url.lastIndexOf("/") + 1);
if (fileName.contains("?")) {
fileName = fileName.substring(0, fileName.indexOf("?"));
}
if (!fileName.endsWith(".zip")) {
return Futures.immediateFailedFuture(new IllegalArgumentException("Invalid filename; must end in .zip"));
}
fileName = "legacy_" + fileName.replaceAll("\\W", "");
}
final File file = new File(repo.dirServerResourcepacks, fileName);
repo.field_177321_h.lock();
try {
repo.func_148529_f();
if (file.exists() && hash.length() == 40) {
try {
String fileHash = Hashing.sha1().hashBytes(Files.toByteArray(file)).toString();
if (fileHash.equals(hash)) {
recordResourcePack(file, requestId);
return repo.func_177319_a(file);
}
logger.warn("File " + file + " had wrong hash (expected " + hash + ", found " + fileHash + "). Deleting it.");
FileUtils.deleteQuietly(file);
} catch (IOException ioexception) {
logger.warn("File " + file + " couldn\'t be hashed. Deleting it.", ioexception);
FileUtils.deleteQuietly(file);
}
}
final GuiScreenWorking guiScreen = new GuiScreenWorking();
final Minecraft mc = Minecraft.getMinecraft();
Futures.getUnchecked(mc.addScheduledTask(new Runnable() {
@Override
public void run() {
mc.displayGuiScreen(guiScreen);
}
}));
Map sessionInfo = Minecraft.getSessionInfo();
repo.field_177322_i = HttpUtil.func_180192_a(file, url, sessionInfo, 50 * 1024 * 1024, guiScreen, mc.getProxy());
Futures.addCallback(repo.field_177322_i, new FutureCallback() {
@Override
public void onSuccess(Object value) {
recordResourcePack(file, requestId);
repo.func_177319_a(file);
}
@Override
public void onFailure(@Nonnull Throwable throwable) {
throwable.printStackTrace();
}
});
return repo.field_177322_i;
} finally {
repo.field_177321_h.unlock();
}
}
}

View File

@@ -1,38 +0,0 @@
package eu.crushedpixel.replaymod.recording;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.network.*;
import net.minecraft.util.MessageSerializer;
import java.io.IOException;
public class PacketSerializer extends MessageSerializer {
public PacketSerializer(EnumPacketDirection direction) {
super(direction);
}
@Override
public void encode(ChannelHandlerContext ctx, Packet packet, ByteBuf byteBuf) throws IOException {
EnumConnectionState state = ((EnumConnectionState) ctx.channel().attr(NetworkManager.attrKeyConnectionState).get());
encode(state, packet, byteBuf);
}
public void encode(EnumConnectionState state, Packet packet, ByteBuf byteBuf) {
Integer integer = state.getPacketId(EnumPacketDirection.CLIENTBOUND, packet);
if (integer != null) {
PacketBuffer packetbuffer = new PacketBuffer(byteBuf);
packetbuffer.writeVarIntToBuffer(integer);
try {
packet.writePacketData(packetbuffer);
} catch(Throwable throwable) {
throwable.printStackTrace();
}
}
}
}

View File

@@ -1,24 +0,0 @@
package eu.crushedpixel.replaymod.recording;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ReplayMetaData {
private boolean singleplayer;
private String serverName;
private String generator;
private int duration;
private long date;
private String[] players;
private String mcversion;
public ReplayMetaData copy() {
return new ReplayMetaData(this.singleplayer, this.serverName, this.generator,
this.duration, this.date, this.players, this.mcversion);
}
public void removeServer() { this.serverName = null; }
}

View File

@@ -1,8 +1,7 @@
package eu.crushedpixel.replaymod.registry;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.gui.elements.listeners.ProgressUpdateListener;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
@@ -35,7 +34,7 @@ public class DownloadedFileHandler {
}
private File generateFileForID(int id) {
return new File(downloadFolder, id+ReplayFile.ZIP_FILE_EXTENSION);
return new File(downloadFolder, id+ ".zip");
}
public void addToIndex(int id) {

View File

@@ -1,7 +1,7 @@
package eu.crushedpixel.replaymod.registry;
import com.google.common.primitives.Ints;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.api.ApiException;
import java.io.IOException;

View File

@@ -45,7 +45,6 @@ public class KeybindRegistry {
replayModKeyBindings.add(new KeyBinding(KEY_KEYFRAME_PRESETS, Keyboard.KEY_X, "replaymod.title"));
replayModKeyBindings.add(new KeyBinding(KEY_PATH_PREVIEW, Keyboard.KEY_H, "replaymod.title"));
replayModKeyBindings.add(new KeyBinding(KEY_ADD_MARKER, Keyboard.KEY_M, "replaymod.title"));
replayModKeyBindings.add(new KeyBinding(KEY_SYNC_TIMELINE, Keyboard.KEY_V, "replaymod.title"));
replayModKeyBindings.add(new KeyBinding(KEY_THUMBNAIL, Keyboard.KEY_N, "replaymod.title"));

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.registry;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.GameSettings.Options;

View File

@@ -1,71 +0,0 @@
package eu.crushedpixel.replaymod.registry;
import com.google.common.base.Predicate;
import eu.crushedpixel.replaymod.entities.CameraEntity;
import eu.crushedpixel.replaymod.gui.GuiPlayerOverview;
import eu.crushedpixel.replaymod.holders.PlayerVisibility;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import java.util.*;
public class PlayerHandler {
private static Minecraft mc = Minecraft.getMinecraft();
private static Predicate<EntityPlayer> playerPredicate = new Predicate<EntityPlayer>() {
@Override
public boolean apply(EntityPlayer input) {
return !(input instanceof CameraEntity || input == mc.thePlayer);
}
};
private static Set<UUID> hidden = new HashSet<UUID>();
public static void hidePlayer(EntityPlayer player) {
hidden.remove(player.getUniqueID());
hidden.add(player.getUniqueID());
}
public static void showPlayer(EntityPlayer player) {
hidden.remove(player.getUniqueID());
}
public static void setIsVisible(EntityPlayer player, boolean visible) {
if(visible) showPlayer(player);
else hidePlayer(player);
}
public static void loadPlayerVisibilityConfiguration(PlayerVisibility visibility) {
resetHiddenPlayers();
if(visibility != null) {
GuiPlayerOverview.defaultSave = true;
Collections.addAll(hidden, visibility.getHidden());
} else {
GuiPlayerOverview.defaultSave = false;
}
}
public static Set<UUID> getHiddenPlayers() {
return hidden;
}
public static boolean isHidden(UUID uuid) {
return hidden.contains(uuid);
}
public static void resetHiddenPlayers() {
hidden.clear();
}
public static void openPlayerOverview() {
if(!ReplayHandler.isInReplay()) {
return;
}
@SuppressWarnings("unchecked")
List<EntityPlayer> players = mc.theWorld.getEntities(EntityPlayer.class, playerPredicate);
mc.displayGuiScreen(new GuiPlayerOverview(players));
}
}

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.registry;
import eu.crushedpixel.replaymod.ReplayMod;
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;

View File

@@ -2,7 +2,7 @@ package eu.crushedpixel.replaymod.registry;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import eu.crushedpixel.replaymod.events.ReplayExitEvent;
import com.replaymod.replay.events.ReplayCloseEvent;
import eu.crushedpixel.replaymod.gui.GuiReplaySaving;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import net.minecraft.client.Minecraft;
@@ -91,7 +91,7 @@ public class ReplayFileAppender {
}
@SubscribeEvent
public void onReplayExit(ReplayExitEvent event) {
public void onReplayExit(ReplayCloseEvent.Post event) {
if(!filesToRewrite.isEmpty()) {
openGuiSavingScreen();
writeFiles();

View File

@@ -1,19 +1,8 @@
package eu.crushedpixel.replaymod.renderer;
import eu.crushedpixel.replaymod.assets.CustomImageObject;
import eu.crushedpixel.replaymod.gui.GuiObjectManager;
import eu.crushedpixel.replaymod.holders.Position;
import eu.crushedpixel.replaymod.holders.Transformation;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplayProcess;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.opengl.GL11;
/**
* Allows users to render custom images in the World.
@@ -24,91 +13,92 @@ public class CustomObjectRenderer {
@SubscribeEvent
public void renderCustomObjects(RenderWorldLastEvent event) {
if(!ReplayHandler.isInReplay() || mc.getRenderViewEntity() == null || ReplayHandler.getCustomImageObjects().isEmpty()) return;
double dX = mc.getRenderViewEntity().lastTickPosX + (mc.getRenderViewEntity().posX - mc.getRenderViewEntity().lastTickPosX) * (double)event.partialTicks;
double dY = mc.getRenderViewEntity().lastTickPosY + (mc.getRenderViewEntity().posY - mc.getRenderViewEntity().lastTickPosY) * (double)event.partialTicks;
double dZ = mc.getRenderViewEntity().lastTickPosZ + (mc.getRenderViewEntity().posZ - mc.getRenderViewEntity().lastTickPosZ) * (double)event.partialTicks;
GlStateManager.enableTexture2D();
GlStateManager.enableBlend();
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
for(CustomImageObject object : ReplayHandler.getCustomImageObjects()) {
drawCustomImageObject(dX, dY, dZ, object);
}
}
private void drawCustomImageObject(double playerX, double playerY, double playerZ, CustomImageObject customImageObject) {
ResourceLocation resourceLocation = customImageObject.getResourceLocation();
if(customImageObject.getLinkedAsset() == null
|| ReplayHandler.getAssetRepository().getAssetByUUID(customImageObject.getLinkedAsset()) == null
|| resourceLocation == null) return;
GlStateManager.pushMatrix();
GlStateManager.pushAttrib();
Tessellator tessellator = Tessellator.getInstance();
WorldRenderer renderer = tessellator.getWorldRenderer();
mc.renderEngine.bindTexture(resourceLocation);
int renderTimestamp;
if(mc.currentScreen instanceof GuiObjectManager) {
renderTimestamp = ((GuiObjectManager) mc.currentScreen).getObjectKeyframeTimeline().cursorPosition;
} else if(ReplayProcess.isVideoRecording()) {
renderTimestamp = ReplayProcess.getVideoRenderer().getVideoTime();
} else {
renderTimestamp = ReplayHandler.getRealTimelineCursor();
}
Transformation transformation = customImageObject.getTransformations().getTransformationForTimestamp(renderTimestamp);
Position objectAnchor = transformation.getAnchor();
Position objectPosition = transformation.getPosition();
Position objectOrientation = transformation.getOrientation();
double x = objectPosition.getX() - playerX;
double y = objectPosition.getY() - playerY;
double z = objectPosition.getZ() - playerZ;
GL11.glNormal3f(0, 1, 0);
GlStateManager.translate(x, y + 1.4, z);
GlStateManager.rotate((float) -objectOrientation.getX(), 0, 1, 0);
GlStateManager.rotate((float) objectOrientation.getY(), 0, 0, 1);
GlStateManager.rotate((float) objectOrientation.getZ(), 1, 0, 0);
float opacity = (float)transformation.getOpacity() / 100;
GlStateManager.color(1, 1, 1, opacity);
float width = (float)(customImageObject.getWidth() * transformation.getScale().getX() / 100f);
float height = (float)(customImageObject.getHeight() * transformation.getScale().getY() / 100f);
float minX = (float)(-width/2 + objectAnchor.getX());
float maxX = (float)(width/2 + objectAnchor.getX());
float minY = (float)(-height/2 + objectAnchor.getY());
float maxY = (float)(height/2 + objectAnchor.getY());
renderer.startDrawingQuads();
renderer.addVertexWithUV(minX, minY, 0, 1, 1);
renderer.addVertexWithUV(minX, maxY, 0, 1, 0);
renderer.addVertexWithUV(maxX, maxY, 0, 0, 0);
renderer.addVertexWithUV(maxX, minY, 0, 0, 1);
renderer.addVertexWithUV(maxX, maxY, 0, 0, 0);
renderer.addVertexWithUV(minX, maxY, 0, 1, 0);
renderer.addVertexWithUV(minX, minY, 0, 1, 1);
renderer.addVertexWithUV(maxX, minY, 0, 0, 1);
tessellator.draw();
renderer.setTranslation(0, 0, 0);
GlStateManager.popAttrib();
GlStateManager.popMatrix();
// TODO
// if(!ReplayHandler.isInReplay() || mc.getRenderViewEntity() == null || ReplayHandler.getCustomImageObjects().isEmpty()) return;
//
// double dX = mc.getRenderViewEntity().lastTickPosX + (mc.getRenderViewEntity().posX - mc.getRenderViewEntity().lastTickPosX) * (double)event.partialTicks;
// double dY = mc.getRenderViewEntity().lastTickPosY + (mc.getRenderViewEntity().posY - mc.getRenderViewEntity().lastTickPosY) * (double)event.partialTicks;
// double dZ = mc.getRenderViewEntity().lastTickPosZ + (mc.getRenderViewEntity().posZ - mc.getRenderViewEntity().lastTickPosZ) * (double)event.partialTicks;
//
// GlStateManager.enableTexture2D();
//
// GlStateManager.enableBlend();
// GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
//
// for(CustomImageObject object : ReplayHandler.getCustomImageObjects()) {
// drawCustomImageObject(dX, dY, dZ, object);
// }
// }
//
// private void drawCustomImageObject(double playerX, double playerY, double playerZ, CustomImageObject customImageObject) {
// ResourceLocation resourceLocation = customImageObject.getResourceLocation();
//
// if(customImageObject.getLinkedAsset() == null
// || ReplayHandler.getAssetRepository().getAssetByUUID(customImageObject.getLinkedAsset()) == null
// || resourceLocation == null) return;
//
// GlStateManager.pushMatrix();
// GlStateManager.pushAttrib();
//
// Tessellator tessellator = Tessellator.getInstance();
// WorldRenderer renderer = tessellator.getWorldRenderer();
//
// mc.renderEngine.bindTexture(resourceLocation);
//
// int renderTimestamp;
// if(mc.currentScreen instanceof GuiObjectManager) {
// renderTimestamp = ((GuiObjectManager) mc.currentScreen).getObjectKeyframeTimeline().cursorPosition;
// } else if(ReplayProcess.isVideoRecording()) {
// renderTimestamp = ReplayProcess.getVideoRenderer().getVideoTime();
// } else {
// renderTimestamp = ReplayHandler.getRealTimelineCursor();
// }
//
// Transformation transformation = customImageObject.getTransformations().getTransformationForTimestamp(renderTimestamp);
//
// Position objectAnchor = transformation.getAnchor();
// Position objectPosition = transformation.getPosition();
// Position objectOrientation = transformation.getOrientation();
//
// double x = objectPosition.getX() - playerX;
// double y = objectPosition.getY() - playerY;
// double z = objectPosition.getZ() - playerZ;
//
// GL11.glNormal3f(0, 1, 0);
//
// GlStateManager.translate(x, y + 1.4, z);
//
// GlStateManager.rotate((float) -objectOrientation.getX(), 0, 1, 0);
// GlStateManager.rotate((float) objectOrientation.getY(), 0, 0, 1);
// GlStateManager.rotate((float) objectOrientation.getZ(), 1, 0, 0);
//
// float opacity = (float)transformation.getOpacity() / 100;
// GlStateManager.color(1, 1, 1, opacity);
//
// float width = (float)(customImageObject.getWidth() * transformation.getScale().getX() / 100f);
// float height = (float)(customImageObject.getHeight() * transformation.getScale().getY() / 100f);
//
// float minX = (float)(-width/2 + objectAnchor.getX());
// float maxX = (float)(width/2 + objectAnchor.getX());
// float minY = (float)(-height/2 + objectAnchor.getY());
// float maxY = (float)(height/2 + objectAnchor.getY());
//
// renderer.startDrawingQuads();
//
// renderer.addVertexWithUV(minX, minY, 0, 1, 1);
// renderer.addVertexWithUV(minX, maxY, 0, 1, 0);
// renderer.addVertexWithUV(maxX, maxY, 0, 0, 0);
// renderer.addVertexWithUV(maxX, minY, 0, 0, 1);
//
// renderer.addVertexWithUV(maxX, maxY, 0, 0, 0);
// renderer.addVertexWithUV(minX, maxY, 0, 1, 0);
// renderer.addVertexWithUV(minX, minY, 0, 1, 1);
// renderer.addVertexWithUV(maxX, minY, 0, 0, 1);
//
// tessellator.draw();
// renderer.setTranslation(0, 0, 0);
//
// GlStateManager.popAttrib();
// GlStateManager.popMatrix();
}
}

View File

@@ -1,8 +1,5 @@
package eu.crushedpixel.replaymod.renderer;
import eu.crushedpixel.replaymod.registry.PlayerHandler;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.culling.ICamera;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.client.renderer.entity.RenderPlayer;
@@ -20,8 +17,10 @@ public class InvisibilityRender extends RenderPlayer {
@Override
public boolean shouldRender(Entity entity, ICamera camera, double camX, double camY, double camZ) {
return !(PlayerHandler.isHidden(entity.getUniqueID()) || (ReplayHandler.isInReplay()
&& entity == Minecraft.getMinecraft().thePlayer))
&& super.shouldRender(entity, camera, camX, camY, camZ);
// TODO
return false;
// return !(PlayerHandler.isHidden(entity.getUniqueID()) || (ReplayHandler.isInReplay()
// && entity == Minecraft.getMinecraft().thePlayer))
// && super.shouldRender(entity, camera, camX, camY, camZ);
}
}

View File

@@ -1,28 +1,23 @@
package eu.crushedpixel.replaymod.renderer;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.events.KeyframesModifyEvent;
import eu.crushedpixel.replaymod.gui.overlay.GuiReplayOverlay;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.SpectatorData;
import eu.crushedpixel.replaymod.interpolation.AdvancedPositionKeyframeList;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldRenderer;
import net.minecraft.entity.Entity;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static com.replaymod.core.ReplayMod.TEXTURE;
public class PathPreviewRenderer {
@@ -38,83 +33,85 @@ public class PathPreviewRenderer {
@SubscribeEvent
public void renderCameraPath(RenderWorldLastEvent event) {
if(!ReplayHandler.isInReplay() || ReplayHandler.isInPath() || !ReplayMod.replaySettings.showPathPreview() || mc.gameSettings.hideGUI) return;
GlStateManager.pushAttrib();
int renderDistanceSquared = mc.gameSettings.renderDistanceChunks*16 * mc.gameSettings.renderDistanceChunks*16;
Entity entity = ReplayHandler.getCameraEntity();
if(entity == null) return;
double doubleX = entity.posX;
double doubleY = entity.posY;
double doubleZ = entity.posZ;
GlStateManager.disableLighting();
GlStateManager.disableTexture2D();
GlStateManager.enableBlend();
if(keyframes.size() > 1) {
AdvancedPosition previousPosition = null;
int i = 0;
for(Keyframe<AdvancedPosition> keyframe : keyframes) {
int timestamp = keyframe.getRealTimestamp();
int nextTimestamp = timestamp;
if(i+1 < keyframes.size()) {
nextTimestamp = keyframes.get(i+1).getRealTimestamp();
}
int diff = nextTimestamp-timestamp;
int step = diff/100;
for(int currentTimestamp = timestamp; currentTimestamp < nextTimestamp; currentTimestamp += step) {
AdvancedPosition position = keyframes.getInterpolatedValueForTimestamp(currentTimestamp, ReplayMod.replaySettings.isLinearMovement());
if(previousPosition != null) {
drawConnection(doubleX, doubleY, doubleZ, previousPosition, position, DEFAULT_PATH_COLOR, renderDistanceSquared);
}
previousPosition = position;
}
i++;
}
}
distanceComparator.setPlayerPos(doubleX, doubleY + 1.4, doubleZ);
List<Keyframe<AdvancedPosition>> distanceSorted = new ArrayList<Keyframe<AdvancedPosition>>(keyframes);
Collections.sort(distanceSorted, distanceComparator);
GlStateManager.enableTexture2D();
GlStateManager.blendFunc(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR);
GlStateManager.disableDepth();
for(Keyframe<AdvancedPosition> kf : distanceSorted) {
if(kf.getValue().distanceSquared(entity.posX, entity.posY, entity.posZ) < renderDistanceSquared) {
drawPoint(doubleX, doubleY, doubleZ, kf);
}
}
if(ReplayHandler.getPositionKeyframes().size() > 1) {
AdvancedPosition cameraPosition = ReplayHandler.getPositionKeyframes().getInterpolatedValueForTimestamp(ReplayHandler.getRealTimelineCursor(),
ReplayMod.replaySettings.isLinearMovement());
if(cameraPosition != null) {
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
drawCamera(doubleX, doubleY, doubleZ, cameraPosition);
}
}
GlStateManager.disableBlend();
GlStateManager.popAttrib();
// TODO
// if(!ReplayHandler.isInReplay() || ReplayHandler.isInPath() || !ReplayMod.replaySettings.showPathPreview() || mc.gameSettings.hideGUI) return;
//
// GlStateManager.pushAttrib();
//
// int renderDistanceSquared = mc.gameSettings.renderDistanceChunks*16 * mc.gameSettings.renderDistanceChunks*16;
//
// Entity entity = ReplayHandler.getCameraEntity();
// if(entity == null) return;
//
// double doubleX = entity.posX;
// double doubleY = entity.posY;
// double doubleZ = entity.posZ;
//
// GlStateManager.disableLighting();
// GlStateManager.disableTexture2D();
// GlStateManager.enableBlend();
//
// if(keyframes.size() > 1) {
// AdvancedPosition previousPosition = null;
//
// int i = 0;
// for(Keyframe<AdvancedPosition> keyframe : keyframes) {
// int timestamp = keyframe.getRealTimestamp();
// int nextTimestamp = timestamp;
//
// if(i+1 < keyframes.size()) {
// nextTimestamp = keyframes.get(i+1).getRealTimestamp();
// }
//
// int diff = nextTimestamp-timestamp;
// int step = diff/100;
//
// for(int currentTimestamp = timestamp; currentTimestamp < nextTimestamp; currentTimestamp += step) {
// AdvancedPosition position = keyframes.getInterpolatedValueForTimestamp(currentTimestamp, ReplayMod.replaySettings.isLinearMovement());
// if(previousPosition != null) {
// drawConnection(doubleX, doubleY, doubleZ, previousPosition, position, DEFAULT_PATH_COLOR, renderDistanceSquared);
// }
// previousPosition = position;
// }
//
// i++;
// }
// }
//
// distanceComparator.setPlayerPos(doubleX, doubleY + 1.4, doubleZ);
//
// List<Keyframe<AdvancedPosition>> distanceSorted = new ArrayList<Keyframe<AdvancedPosition>>(keyframes);
// Collections.sort(distanceSorted, distanceComparator);
//
// GlStateManager.enableTexture2D();
// GlStateManager.blendFunc(GL11.GL_DST_COLOR, GL11.GL_SRC_COLOR);
//
// GlStateManager.disableDepth();
//
// for(Keyframe<AdvancedPosition> kf : distanceSorted) {
// if(kf.getValue().distanceSquared(entity.posX, entity.posY, entity.posZ) < renderDistanceSquared) {
// drawPoint(doubleX, doubleY, doubleZ, kf);
// }
// }
//
// if(ReplayHandler.getPositionKeyframes().size() > 1) {
// AdvancedPosition cameraPosition = ReplayHandler.getPositionKeyframes().getInterpolatedValueForTimestamp(ReplayHandler.getRealTimelineCursor(),
// ReplayMod.replaySettings.isLinearMovement());
// if(cameraPosition != null) {
// GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
// drawCamera(doubleX, doubleY, doubleZ, cameraPosition);
// }
// }
//
// GlStateManager.disableBlend();
//
// GlStateManager.popAttrib();
}
@SubscribeEvent
public void recalcSpline(KeyframesModifyEvent event) {
keyframes = ReplayHandler.getPositionKeyframes();
// TODO
// keyframes = ReplayHandler.getPositionKeyframes();
}
private class DistanceComparator implements Comparator<Keyframe<AdvancedPosition>> {
@@ -172,7 +169,7 @@ public class PathPreviewRenderer {
Tessellator tessellator = Tessellator.getInstance();
WorldRenderer renderer = tessellator.getWorldRenderer();
mc.renderEngine.bindTexture(GuiReplayOverlay.replay_gui);
mc.renderEngine.bindTexture(TEXTURE);
AdvancedPosition pos1 = kf.getValue();
@@ -197,9 +194,10 @@ public class PathPreviewRenderer {
float size = 10/128f;
if(kf.equals(ReplayHandler.getSelectedKeyframe())) {
posY += size;
}
// TODO
// if(kf.equals(ReplayHandler.getSelectedKeyframe())) {
// posY += size;
// }
if(pos1 instanceof SpectatorData) {
posX += size;

View File

@@ -1,318 +0,0 @@
package eu.crushedpixel.replaymod.replay;
import com.google.common.collect.Maps;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.chat.ChatMessageHandler.ChatMessageType;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.SpectatorData;
import eu.crushedpixel.replaymod.holders.TimestampValue;
import eu.crushedpixel.replaymod.interpolation.KeyframeList;
import eu.crushedpixel.replaymod.settings.RenderOptions;
import eu.crushedpixel.replaymod.timer.EnchantmentTimer;
import eu.crushedpixel.replaymod.timer.ReplayTimer;
import eu.crushedpixel.replaymod.utils.CameraPathValidator;
import eu.crushedpixel.replaymod.video.VideoRenderer;
import lombok.Getter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.SoundCategory;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.chunk.RenderChunk;
import net.minecraft.client.resources.I18n;
import net.minecraft.crash.CrashReport;
import net.minecraft.entity.Entity;
import net.minecraft.util.ReportedException;
import org.lwjgl.opengl.Display;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class ReplayProcess {
private static Minecraft mc = Minecraft.getMinecraft();
private static int lastRealReplayTime;
private static long lastRealTime = 0;
private static boolean linear = false;
private static int initialTimestamp = 0;
private static double previousReplaySpeed = 0;
@Getter
private static VideoRenderer videoRenderer = null;
private static boolean isVideoRecording = false;
private static boolean requestFinish = false;
private static boolean firstTime = false;
public static boolean isVideoRecording() {
return isVideoRecording;
}
//a copy of the initial sound settings,
//which we will modify to prevent game sounds from annoying us while rendering
@SuppressWarnings("unchecked") //I, too, blame Forge for not re-adding generics to that Map.
private static Map<SoundCategory, Float> mapSoundLevelsBefore = null;
private static void resetProcess() {
firstTime = true;
requestFinish = false;
lastRealTime = System.currentTimeMillis();
lastRealReplayTime = 0;
linear = ReplayMod.replaySettings.isLinearMovement();
previousReplaySpeed = ReplayMod.replaySender.getReplaySpeed();
EnchantmentTimer.resetRecordingTime();
}
public static void startReplayProcess(RenderOptions renderOptions, boolean fromStart) {
mc.displayGuiScreen(null);
ReplayHandler.selectKeyframe(null);
resetProcess();
isVideoRecording = renderOptions != null;
ReplayMod.chatMessageHandler.initialize();
try {
CameraPathValidator.validateCameraPath(ReplayHandler.getPositionKeyframes(), ReplayHandler.getTimeKeyframes());
} catch(CameraPathValidator.InvalidCameraPathException e) {
e.printToChat();
return;
}
ReplayHandler.setInPath(true);
ReplayMod.replaySender.setAsyncMode(false);
//default camera path, no rendering
if (renderOptions == null) {
initialTimestamp = fromStart ? 0 : ReplayHandler.getRealTimelineCursor();
//if the cursor is at (or very near) the end, play from the beginning as well
if(initialTimestamp + 50 >= Math.max(ReplayHandler.getTimeKeyframes().last().getRealTimestamp(),
ReplayHandler.getPositionKeyframes().last().getRealTimestamp())) {
initialTimestamp = 0;
}
lastRealReplayTime = initialTimestamp;
int ts = ReplayHandler.getTimeKeyframes().getInterpolatedValueForTimestamp(initialTimestamp, true).asInt();
if (ts < ReplayMod.replaySender.currentTimeStamp()) {
mc.displayGuiScreen(null);
}
ReplayMod.replaySender.sendPacketsTill(ts);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.pathstarted", ChatMessageType.INFORMATION);
mc.timer.timerSpeed = 1;
//set the sound level map to null
//so a previous map doesn't override the current game settings after a camera path
mapSoundLevelsBefore = null;
} else {
//if FBOs are not enabled/supported, prevent the user from resizing the MC window
if(!OpenGlHelper.isFramebufferEnabled()) {
Display.setResizable(false);
}
//if rendering, disable all game sounds except for gui sounds
@SuppressWarnings("unchecked") //I, too, blame Forge for not re-adding generics to that Map.
Map<SoundCategory, Float> orgMap = (Map<SoundCategory, Float>)mc.gameSettings.mapSoundLevels;
if(orgMap != null) {
mapSoundLevelsBefore = new HashMap<SoundCategory, Float>(orgMap);
} else {
orgMap = Maps.newEnumMap(SoundCategory.class);
}
//turn down for what? to mute all sound of course!
//the GUI sounds (button clicks etc) are not muted this way.
for(SoundCategory category : SoundCategory.values()) {
if(category == SoundCategory.MASTER) continue;
orgMap.put(category, 0f);
}
mc.gameSettings.mapSoundLevels = orgMap;
initialTimestamp = 0;
boolean success = false;
try {
isVideoRecording = true;
videoRenderer = new VideoRenderer(renderOptions);
success = videoRenderer.renderVideo();
} catch (IOException e) {
e.printStackTrace();
GuiErrorScreen errorScreen = new GuiErrorScreen(I18n.format("replaymod.gui.rendering.error.title"),
I18n.format("replaymod.gui.rendering.error.message"));
mc.displayGuiScreen(errorScreen);
} catch (Throwable t) {
CrashReport crashReport = CrashReport.makeCrashReport(t, "Rendering video");
throw new ReportedException(crashReport);
} finally {
isVideoRecording = false;
stopReplayProcess(success);
}
}
}
public static void stopReplayProcess(boolean finished) {
if(!ReplayHandler.isInPath()) return;
//if canceled, display a different chat message
if(finished) ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.pathfinished", ChatMessageType.INFORMATION);
else {
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.pathinterrupted", ChatMessageType.INFORMATION);
}
ReplayHandler.setInPath(false);
ReplayMod.replaySender.setAsyncMode(true);
ReplayMod.replaySender.stopHurrying();
ReplayTimer.get(mc).passive = false;
ReplayMod.replaySender.setReplaySpeed(previousReplaySpeed);
ReplayMod.replaySender.setReplaySpeed(0);
//re-enable window resizing after rendering
Display.setResizable(true);
//restore the sound settings
if (mapSoundLevelsBefore != null) {
mc.gameSettings.mapSoundLevels = mapSoundLevelsBefore;
}
}
//if justCheck is true, no Screenshot will be taken, it will only be checked
//whether all chunks have been rendered. This is necessary because no Render ticks
//are called if the Timer speed is set to 0, leading to this method never being
//called from the RenderWorldLastEvent handlers.
public static void tickReplay(boolean justCheck) {
final long curTime = System.currentTimeMillis();
KeyframeList<AdvancedPosition> positionKeyframes = ReplayHandler.getPositionKeyframes();
KeyframeList<TimestampValue> timeKeyframes = ReplayHandler.getTimeKeyframes();
int curRealReplayTime;
if (isVideoRecording) {
return;
}
if(ReplayMod.replaySender.isHurrying()) {
lastRealTime = curTime;
return;
}
if(firstTime) {
if(RenderChunk.renderChunksUpdated != 0 || mc.currentScreen != null) {
return;
}
lastRealTime = curTime;
firstTime = false;
mc.timer.renderPartialTicks = 100;
mc.timer.elapsedPartialTicks = 100;
mc.timer.elapsedTicks = 100;
curRealReplayTime = lastRealReplayTime = initialTimestamp;
} else {
long timeStep = curTime - lastRealTime;
curRealReplayTime = (int) (lastRealReplayTime + timeStep);
}
if(justCheck) return;
Keyframe<AdvancedPosition> lastPos = positionKeyframes.getPreviousKeyframe(curRealReplayTime, true);
Keyframe<AdvancedPosition> nextPos = positionKeyframes.getNextKeyframe(curRealReplayTime, true);
boolean spectateCamera = true;
//check whether between two First Person Spectator Keyframes
if(lastPos != null && nextPos != null) {
if(lastPos.getValue() instanceof SpectatorData && nextPos.getValue() instanceof SpectatorData) {
SpectatorData previousSpectatorData = (SpectatorData)lastPos.getValue();
SpectatorData nextSpectatorData = (SpectatorData)nextPos.getValue();
if(previousSpectatorData.getSpectatedEntityID() == nextSpectatorData.getSpectatedEntityID()) {
if(previousSpectatorData.getSpectatingMethod() == SpectatorData.SpectatingMethod.FIRST_PERSON
&& nextSpectatorData.getSpectatingMethod() == SpectatorData.SpectatingMethod.FIRST_PERSON) {
spectateCamera = false;
}
}
}
}
ReplayHandler.setRealTimelineCursor(curRealReplayTime);
Keyframe<TimestampValue> lastTime = timeKeyframes.getPreviousKeyframe(curRealReplayTime, true);
Keyframe<TimestampValue> nextTime = timeKeyframes.getNextKeyframe(curRealReplayTime, true);
int lastTimeStamp;
int nextTimeStamp;
double curSpeed = 0;
if(nextTime != null && lastTime != null && nextTime.getRealTimestamp() == lastTime.getRealTimestamp()) {
curSpeed = 0;
} else {
if(nextTime != null) {
nextTimeStamp = nextTime.getRealTimestamp();
} else {
nextTimeStamp = lastTime.getRealTimestamp();
}
if(lastTime != null) {
lastTimeStamp = lastTime.getRealTimestamp();
} else {
lastTimeStamp = nextTime.getRealTimestamp();
}
if(!(nextTime == null || lastTime == null)) {
curSpeed = ((double) (((int)nextTime.getValue().value - (int)lastTime.getValue().value))) / ((double) ((nextTimeStamp - lastTimeStamp)));
}
if(lastTimeStamp == nextTimeStamp) {
curSpeed = 0f;
}
}
AdvancedPosition cameraPosition = null;
if(spectateCamera) {
cameraPosition = positionKeyframes.getInterpolatedValueForTimestamp(curRealReplayTime, linear);
ReplayHandler.spectateCamera();
} else {
Entity toSpectate = mc.theWorld.getEntityByID(((SpectatorData) lastPos.getValue()).getSpectatedEntityID());
ReplayHandler.spectateEntity(toSpectate);
}
if(cameraPosition != null) {
ReplayHandler.setCameraTilt((float)cameraPosition.getRoll());
ReplayHandler.getCameraEntity().movePath(cameraPosition);
}
Integer curTimestamp = timeKeyframes.getInterpolatedValueForTimestamp(curRealReplayTime, true).asInt();
if(!isVideoRecording()) ReplayMod.replaySender.setReplaySpeed(curSpeed);
ReplayMod.replaySender.sendPacketsTill(curTimestamp);
lastRealReplayTime = curRealReplayTime;
lastRealTime = curTime;
if(requestFinish) {
stopReplayProcess(true);
requestFinish = false;
}
if(curRealReplayTime > timeKeyframes.last().getRealTimestamp()
&& curRealReplayTime > positionKeyframes.last().getRealTimestamp()) {
requestFinish = true;
}
}
}

View File

@@ -1,817 +0,0 @@
package eu.crushedpixel.replaymod.replay;
import com.google.common.base.Preconditions;
import com.google.common.io.Files;
import com.google.common.util.concurrent.ListenableFutureTask;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.entities.CameraEntity;
import eu.crushedpixel.replaymod.holders.PacketData;
import eu.crushedpixel.replaymod.settings.ReplaySettings;
import eu.crushedpixel.replaymod.utils.ReplayFile;
import eu.crushedpixel.replaymod.utils.ReplayFileIO;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiDownloadTerrain;
import net.minecraft.client.gui.GuiErrorScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.Entity;
import net.minecraft.network.EnumConnectionState;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.*;
import net.minecraft.util.IChatComponent;
import net.minecraft.world.EnumDifficulty;
import net.minecraft.world.World;
import net.minecraft.world.WorldSettings.GameType;
import net.minecraft.world.WorldType;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* Sends replay packets to netty channels.
* Even though {@link Sharable}, this should never be added to multiple pipes at once, it may however be re-added when
* the replay restart from the beginning.
*/
@Sharable
public class ReplaySender extends ChannelInboundHandlerAdapter {
/**
* Previously packets for the client player were inserted using one fixed entity id (this one).
* This is no longer the case however to provide backwards compatibility, we have to convert
* these old packets to use the normal entity id.
* Need to punch someone? -> CrushedPixel
*/
public static final int LEGACY_ENTITY_ID = Integer.MIN_VALUE + 9001;
/**
* These packets are ignored completely during replay.
*/
private static final List<Class> BAD_PACKETS = Arrays.<Class>asList(
S06PacketUpdateHealth.class,
S2DPacketOpenWindow.class,
S2EPacketCloseWindow.class,
S2FPacketSetSlot.class,
S30PacketWindowItems.class,
S36PacketSignEditorOpen.class,
S37PacketStatistics.class,
S1FPacketSetExperience.class,
S43PacketCamera.class,
S39PacketPlayerAbilities.class,
S45PacketTitle.class);
/**
* Whether to work in async mode.
*
* When in async mode, a separate thread send packets and waits according to their delays.
* This is default in normal playback mode.
*
* When in sync mode, no packets will be sent until {@link #sendPacketsTill(int)} is called.
* This is used during path playback and video rendering.
*/
protected boolean asyncMode;
/**
* Timestamp of the last packet sent in milliseconds since the start.
*/
protected int lastTimeStamp;
/**
* The replay file.
*/
protected ReplayFile replayFile;
/**
* The channel handler context used to send packets to minecraft.
*/
protected ChannelHandlerContext ctx;
/**
* The data input stream from which new packets are read.
* When accessing this stream make sure to synchronize on {@code this} as it's used from multiple threads.
*/
protected DataInputStream dis;
/**
* The next packet that should be sent.
* This is required as some actions such as jumping to a specified timestamp have to peek at the next packet.
*/
protected PacketData nextPacket;
/**
* Whether we need to restart the current replay. E.g. when jumping backwards in time
*/
protected boolean startFromBeginning = true;
/**
* Whether to terminate the replay. This only has an effect on the async mode and is {@code true} during sync mode.
*/
protected boolean terminate;
/**
* The speed of the replay. 1 is normal, 2 is twice as fast, 0.5 is half speed and 0 is frozen
*/
protected double replaySpeed = 1f;
/**
* Whether the world has been loaded and the dirt-screen should go away.
*/
protected boolean hasWorldLoaded;
/**
* The minecraft instance.
*/
protected Minecraft mc = Minecraft.getMinecraft();
/**
* The total length of this replay in milliseconds.
*/
protected final int replayLength;
/**
* Our actual entity id that the server gave to us.
*/
protected int actualID = -1;
/**
* Whether to allow (process) the next player movement packet.
*/
protected boolean allowMovement;
/**
* Directory to which resource packs are extracted.
*/
private final File tempResourcePackFolder = Files.createTempDir();
/**
* Create a new replay sender.
* @param file The replay file
* @param asyncMode {@code true} for async mode, {@code false} otherwise
* @see #asyncMode
*/
public ReplaySender(ReplayFile file, boolean asyncMode) {
this.replayFile = file;
this.asyncMode = asyncMode;
this.replayLength = file.metadata().get().getDuration();
if (asyncMode) {
new Thread(asyncSender, "replaymod-async-sender").start();
}
}
/**
* Set whether this replay sender operates in async mode.
* When in async mode, it will send packets timed from a separate thread.
* When not in async mode, it will send packets when {@link #sendPacketsTill(int)} is called.
* @param asyncMode {@code true} to enable async mode
*/
public void setAsyncMode(boolean asyncMode) {
if (this.asyncMode == asyncMode) return;
this.asyncMode = asyncMode;
if (asyncMode) {
this.terminate = false;
new Thread(asyncSender, "replaymod-async-sender").start();
} else {
this.terminate = true;
}
}
/**
* Set whether this replay sender to operate in sync mode.
* When in sync mode, it will send packets when {@link #sendPacketsTill(int)} is called.
* This call will block until the async worker thread has stopped.
*/
public void setSyncModeAndWait() {
if (!this.asyncMode) return;
this.asyncMode = false;
this.terminate = true;
synchronized (this) {
// This will wait for the worker thread to leave the synchronized code part
}
}
/**
* Return the timestamp of the last packet sent.
* @return The timestamp in milliseconds since the start of the replay
*/
public int currentTimeStamp() {
return lastTimeStamp;
}
/**
* Return the total length of the replay played.
* @return Total length in milliseconds
*/
public int replayLength() {
return replayLength;
}
/**
* Terminate this replay sender.
*/
public void terminateReplay() {
terminate = true;
try {
channelInactive(ctx);
ctx.channel().pipeline().close();
} catch(Exception e) {
e.printStackTrace();
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
throws Exception {
// When in async mode and the replay sender shut down, then don't send packets
if(terminate && asyncMode) {
return;
}
// When a packet is sent directly, perform no filtering
if(msg instanceof Packet) {
super.channelRead(ctx, msg);
}
if (msg instanceof byte[]) {
try {
Packet p = ReplayFileIO.deserializePacket((byte[]) msg);
if (p != null) {
p = processPacket(p);
if (p != null) {
super.channelRead(ctx, p);
}
// If we do not give minecraft time to tick, there will be dead entity artifacts left in the world
// Therefore we have to remove all loaded, dead entities manually if we are in sync mode.
// We do this after every SpawnX packet and after the destroy entities packet.
if (!asyncMode && mc.theWorld != null) {
if (p instanceof S0CPacketSpawnPlayer
|| p instanceof S0EPacketSpawnObject
|| p instanceof S0FPacketSpawnMob
|| p instanceof S2CPacketSpawnGlobalEntity
|| p instanceof S10PacketSpawnPainting
|| p instanceof S11PacketSpawnExperienceOrb
|| p instanceof S13PacketDestroyEntities) {
World world = mc.theWorld;
for (int i = 0; i < world.loadedEntityList.size(); ++i) {
Entity entity = (Entity) world.loadedEntityList.get(i);
if (entity.isDead) {
int chunkX = entity.chunkCoordX;
int chunkY = entity.chunkCoordZ;
if (entity.addedToChunk && world.getChunkProvider().chunkExists(chunkX, chunkY)) {
world.getChunkFromChunkCoords(chunkX, chunkY).removeEntity(entity);
}
world.loadedEntityList.remove(i--);
world.onEntityRemoved(entity);
}
}
}
}
}
} catch (Exception e) {
// We'd rather not have a failure parsing one packet screw up the whole replay process
e.printStackTrace();
}
}
}
/**
* Process a packet and return the result.
* @param p The packet to process
* @return The processed packet or {@code null} if no packet shall be sent
*/
protected Packet processPacket(Packet p) throws Exception {
if (p instanceof S3FPacketCustomPayload) {
S3FPacketCustomPayload packet = (S3FPacketCustomPayload) p;
if (Restrictions.PLUGIN_CHANNEL.equals(packet.getChannelName())) {
final String unknown = ReplayHandler.getRestrictions().handle(packet);
if (unknown == null) {
return null;
} else {
// Failed to parse options, make sure that under no circumstances further packets are parsed
terminateReplay();
// Then end replay and show error GUI
mc.addScheduledTask(new Runnable() {
@Override
public void run() {
ReplayHandler.endReplay();
mc.displayGuiScreen(new GuiErrorScreen(
I18n.format("replaymod.error.unknownrestriction1"),
I18n.format("replaymod.error.unknownrestriction2", unknown)
));
}
});
}
}
}
if (p instanceof S40PacketDisconnect) {
IChatComponent reason = ((S40PacketDisconnect) p).func_149165_c();
if ("Please update to view this replay.".equals(reason.getUnformattedText())) {
// This version of the mod supports replay restrictions so we are allowed
// to remove this packet.
return null;
}
}
if(BAD_PACKETS.contains(p.getClass())) return null;
if(ReplayProcess.isVideoRecording() && ReplayHandler.isInPath()) {
if(p instanceof S29PacketSoundEffect) {
return null;
}
}
convertLegacyEntityIds(p);
if(p instanceof S48PacketResourcePackSend) {
S48PacketResourcePackSend packet = (S48PacketResourcePackSend) p;
String url = packet.func_179783_a();
if (url.startsWith("replay://")) {
int id = Integer.parseInt(url.substring("replay://".length()));
Map<Integer, String> index = replayFile.resourcePackIndex().get();
if (index != null) {
String hash = index.get(id);
if (hash != null) {
File file = new File(tempResourcePackFolder, hash + ".zip");
if (!file.exists()) {
IOUtils.copy(replayFile.resourcePack(hash).get(), new FileOutputStream(file));
}
mc.getResourcePackRepository().func_177319_a(file);
}
}
return null;
}
}
if(p instanceof S01PacketJoinGame) {
S01PacketJoinGame packet = (S01PacketJoinGame) p;
allowMovement = true;
int entId = packet.getEntityId();
actualID = entId;
entId = -1789435; // Camera entity id should be negative which is an invalid id and can't be used by servers
int dimension = packet.getDimension();
EnumDifficulty difficulty = packet.getDifficulty();
int maxPlayers = packet.getMaxPlayers();
WorldType worldType = packet.getWorldType();
p = new S01PacketJoinGame(entId, GameType.SPECTATOR, false, dimension,
difficulty, maxPlayers, worldType, false);
}
if(p instanceof S07PacketRespawn) {
S07PacketRespawn respawn = (S07PacketRespawn) p;
p = new S07PacketRespawn(respawn.func_149082_c(),
respawn.func_149081_d(), respawn.func_149080_f(), GameType.SPECTATOR);
allowMovement = true;
}
if(p instanceof S08PacketPlayerPosLook) {
if(!hasWorldLoaded) hasWorldLoaded = true;
final S08PacketPlayerPosLook ppl = (S08PacketPlayerPosLook) p;
if (mc.currentScreen instanceof GuiDownloadTerrain) {
// Close the world loading screen manually in case we swallow the packet
mc.displayGuiScreen(null);
}
if(ReplayHandler.isInPath()) return null;
CameraEntity cent = ReplayHandler.getCameraEntity();
for (Object relative : ppl.func_179834_f()) {
if (relative == S08PacketPlayerPosLook.EnumFlags.X
|| relative == S08PacketPlayerPosLook.EnumFlags.Y
|| relative == S08PacketPlayerPosLook.EnumFlags.Z) {
return null; // At least one of the coordinates is relative, so we don't care
}
}
if(cent != null) {
if(!allowMovement && !((Math.abs(cent.posX - ppl.func_148932_c()) > ReplayMod.TP_DISTANCE_LIMIT) ||
(Math.abs(cent.posZ - ppl.func_148933_e()) > ReplayMod.TP_DISTANCE_LIMIT))) {
return null;
} else {
allowMovement = false;
}
}
new Callable<Void>() {
@Override
@SuppressWarnings("unchecked")
public Void call() {
if (mc.theWorld == null || !mc.isCallingFromMinecraftThread()) {
synchronized(mc.scheduledTasks) {
mc.scheduledTasks.add(ListenableFutureTask.create(this));
}
return null;
}
CameraEntity cent = ReplayHandler.getCameraEntity();
cent.moveAbsolute(ppl.func_148932_c(), ppl.func_148928_d(), ppl.func_148933_e());
return null;
}
}.call();
}
if(p instanceof S2BPacketChangeGameState) {
S2BPacketChangeGameState pg = (S2BPacketChangeGameState)p;
int reason = pg.func_149138_c();
// only allow the following packets:
// 1 - End raining
// 2 - Begin raining
//
// The following values are to control sky color (e.g. if thunderstorm)
// 7 - Fade value
// 8 - Fade time
if(!(reason == 1 || reason == 2 || reason == 7 || reason == 8)) {
return null;
}
}
if (p instanceof S02PacketChat) {
if (ReplaySettings.ReplayOptions.showChat.getValue() != Boolean.TRUE) {
return null;
}
}
return asyncMode ? processPacketAsync(p) : processPacketSync(p);
}
@Override
@SuppressWarnings("unchecked")
public void channelActive(ChannelHandlerContext ctx) throws Exception {
this.ctx = ctx;
ctx.attr(NetworkManager.attrKeyConnectionState).set(EnumConnectionState.PLAY);
super.channelActive(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
replayFile.close();
FileUtils.deleteDirectory(tempResourcePackFolder);
super.channelInactive(ctx);
}
/**
* Whether the replay is currently paused.
* @return {@code true} if it is paused, {@code false} otherwise
*/
public boolean paused() {
return mc.timer.timerSpeed == 0;
}
/**
* Returns the speed of the replay. 1 being normal speed, 0.5 half and 2 twice as fast.
* If 0 is returned, the replay is paused.
* @return speed multiplier
*/
public double getReplaySpeed() {
if(!paused()) return replaySpeed;
else return 0;
}
/**
* Set the speed of the replay. 1 being normal speed, 0.5 half and 2 twice as fast.
* The speed may not be set to 0 nor to negative values.
* @param d Speed multiplier
*/
public void setReplaySpeed(final double d) {
if(d != 0) this.replaySpeed = d;
mc.timer.timerSpeed = (float) d;
}
/////////////////////////////////////////////////////////
// Asynchronous packet processing //
/////////////////////////////////////////////////////////
/**
* The real time at which the last packet was sent in milliseconds.
*/
private long lastPacketSent;
/**
* There is no waiting performed until a packet with at least this timestamp is reached (but not yet sent).
* If this is -1, then timing is normal.
*/
private long desiredTimeStamp = -1;
/**
* Runnable which performs timed dispatching of packets from the input stream.
*/
private Runnable asyncSender = new Runnable() {
public void run() {
try {
while (ctx == null && !terminate) {
Thread.sleep(10);
}
REPLAY_LOOP:
while (!terminate) {
synchronized (ReplaySender.this) {
if (dis == null) {
dis = new DataInputStream(replayFile.recording().get());
}
// Packet loop
while (true) {
try {
// When playback is paused and the world has loaded (we don't want any dirt-screens) we sleep
while (paused() && hasWorldLoaded) {
// Unless we are going to terminate, restart or jump
if (terminate || startFromBeginning || desiredTimeStamp != -1) {
break;
}
Thread.sleep(10);
}
if (terminate) {
break REPLAY_LOOP;
}
if (startFromBeginning) {
// In case we need to restart from the beginning
// break out of the loop sending all packets which will
// cause the replay to be restarted by the outer loop
break;
}
// Read the next packet if we don't already have one
if (nextPacket == null) {
nextPacket = ReplayFileIO.readPacketData(dis);
}
int nextTimeStamp = nextPacket.getTimestamp();
// If we aren't jumping and the world has already been loaded (no dirt-screens) then wait
// the required amount to get proper packet timing
if (!isHurrying() && hasWorldLoaded) {
// How much time should have passed
int timeWait = (int) Math.round((nextTimeStamp - lastTimeStamp) / replaySpeed);
// How much time did pass
long timeDiff = System.currentTimeMillis() - lastPacketSent;
// How much time we need to wait to make up for the difference
long timeToSleep = Math.max(0, timeWait - timeDiff);
Thread.sleep(timeToSleep);
lastPacketSent = System.currentTimeMillis();
}
// Process packet
channelRead(ctx, nextPacket.getByteArray());
nextPacket = null;
lastTimeStamp = nextTimeStamp;
// In case we finished jumping
// We need to check that we aren't planing to restart so we don't accidentally run this
// code before we actually restarted
if (isHurrying() && lastTimeStamp > desiredTimeStamp && !startFromBeginning) {
desiredTimeStamp = -1;
ReplayHandler.moveCameraToLastPosition();
// Pause after jumping
setReplaySpeed(0);
}
} catch (EOFException eof) {
// Reached end of file
// Pause the replay which will cause it to freeze before getting restarted
setReplaySpeed(0);
// Then wait until the user tells us to continue
while (paused() && hasWorldLoaded && desiredTimeStamp == -1 && !terminate) {
Thread.sleep(10);
}
break;
} catch (IOException e) {
e.printStackTrace();
}
}
// Restart the replay.
hasWorldLoaded = false;
lastTimeStamp = 0;
startFromBeginning = false;
nextPacket = null;
lastPacketSent = System.currentTimeMillis();
ReplayHandler.restartReplay();
if (dis != null) {
dis.close();
dis = null;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
/**
* Return whether this replay sender is currently rushing. When rushing, all packets are sent without waiting until
* a specified timestamp is passed.
* @return {@code true} if currently rushing, {@code false} otherwise
*/
public boolean isHurrying() {
return desiredTimeStamp != -1;
}
/**
* Cancels the hurrying.
*/
public void stopHurrying() {
desiredTimeStamp = -1;
}
/**
* Return the timestamp to which this replay sender is currently rushing. All packets with an lower or equal
* timestamp will be sent out without any sleeping.
* @return The timestamp in milliseconds since the start of the replay
*/
public long getDesiredTimestamp() {
return desiredTimeStamp;
}
/**
* Jumps to the specified timestamp when in async mode by rushing all packets until one with a timestamp greater
* than the specified timestamp is found.
* If the timestamp has already passed, this causes the replay to restart and then rush all packets.
* @param millis Timestamp in milliseconds since the start of the replay
*/
public void jumpToTime(int millis) {
Preconditions.checkState(asyncMode, "Can only jump in async mode. Use sendPacketsTill(int) instead.");
if(millis < lastTimeStamp && !isHurrying()) {
startFromBeginning = true;
}
desiredTimeStamp = millis;
}
protected Packet processPacketAsync(Packet p) {
//If hurrying, ignore some packets, unless during Replay Path and *not* in short hurries
if(!ReplayHandler.isInPath() && desiredTimeStamp - lastTimeStamp > 1000) {
if(p instanceof S2APacketParticles) return null;
if(p instanceof S0EPacketSpawnObject) {
S0EPacketSpawnObject pso = (S0EPacketSpawnObject)p;
int type = pso.func_148993_l();
if(type == 76) { // Firework rocket
return null;
}
}
}
return p;
}
/////////////////////////////////////////////////////////
// Synchronous packet processing //
/////////////////////////////////////////////////////////
/**
* Sends all packets until the specified timestamp is reached (inclusive).
* If the timestamp is smaller than the last packet sent, the replay is restarted from the beginning.
* @param timestamp The timestamp in milliseconds since the beginning of this replay
*/
public void sendPacketsTill(int timestamp) {
Preconditions.checkState(!asyncMode, "This method cannot be used in async mode. Use jumpToTime(int) instead.");
try {
while (ctx == null && !terminate) { // Make sure channel is ready
Thread.sleep(10);
}
synchronized (this) {
if (timestamp < lastTimeStamp) { // Restart the replay if we need to go backwards in time
hasWorldLoaded = false;
lastTimeStamp = 0;
if (dis != null) {
dis.close();
dis = null;
}
startFromBeginning = false;
nextPacket = null;
ReplayHandler.restartReplay();
}
if (dis == null) {
dis = new DataInputStream(replayFile.recording().get());
}
while (true) { // Send packets
try {
PacketData pd;
if (nextPacket != null) {
// If there is still a packet left from before, use it first
pd = nextPacket;
nextPacket = null;
} else {
// Otherwise read one from the input stream
pd = ReplayFileIO.readPacketData(dis);
}
int nextTimeStamp = pd.getTimestamp();
if (nextTimeStamp > timestamp) {
// We are done sending all packets
nextPacket = pd;
break;
}
// Process packet
channelRead(ctx, pd.getByteArray());
// Store last timestamp
lastTimeStamp = nextTimeStamp;
} catch (EOFException eof) {
// Shit! We hit the end before finishing our job! What shall we do now?
// well, let's just pretend we're done...
dis = null;
break;
} catch (IOException e) {
e.printStackTrace();
}
}
// This might be required if we change to async mode anytime soon
lastPacketSent = System.currentTimeMillis();
}
} catch (Exception e) {
e.printStackTrace();
}
}
protected Packet processPacketSync(Packet p) {
return p; // During synchronous playback everything is sent normally
}
/**
* This is necessary to convert packets from old replays to new replays.
* @param packet The packet to be transformed.
* @see #LEGACY_ENTITY_ID
*/
private void convertLegacyEntityIds(Packet packet) {
if (packet instanceof S0CPacketSpawnPlayer) {
S0CPacketSpawnPlayer p = (S0CPacketSpawnPlayer) packet;
if (p.field_148957_a == LEGACY_ENTITY_ID) {
p.field_148957_a = actualID;
}
} else if (packet instanceof S18PacketEntityTeleport) {
S18PacketEntityTeleport p = (S18PacketEntityTeleport) packet;
if (p.field_149458_a == LEGACY_ENTITY_ID) {
p.field_149458_a = actualID;
}
} else if (packet instanceof S14PacketEntity.S17PacketEntityLookMove) {
S14PacketEntity.S17PacketEntityLookMove p = (S14PacketEntity.S17PacketEntityLookMove) packet;
if (p.field_149074_a == LEGACY_ENTITY_ID) {
p.field_149074_a = actualID;
}
} else if (packet instanceof S19PacketEntityHeadLook) {
S19PacketEntityHeadLook p = (S19PacketEntityHeadLook) packet;
if (p.field_149384_a == LEGACY_ENTITY_ID) {
p.field_149384_a = actualID;
}
} else if (packet instanceof S12PacketEntityVelocity) {
S12PacketEntityVelocity p = (S12PacketEntityVelocity) packet;
if (p.field_149417_a == LEGACY_ENTITY_ID) {
p.field_149417_a = actualID;
}
} else if (packet instanceof S0BPacketAnimation) {
S0BPacketAnimation p = (S0BPacketAnimation) packet;
if (p.entityId == LEGACY_ENTITY_ID) {
p.entityId = actualID;
}
} else if (packet instanceof S04PacketEntityEquipment) {
S04PacketEntityEquipment p = (S04PacketEntityEquipment) packet;
if (p.field_149394_a == LEGACY_ENTITY_ID) {
p.field_149394_a = actualID;
}
} else if (packet instanceof S1BPacketEntityAttach) {
S1BPacketEntityAttach p = (S1BPacketEntityAttach) packet;
if (p.field_149408_a == LEGACY_ENTITY_ID) {
p.field_149408_a = actualID;
}
if (p.field_149406_b == LEGACY_ENTITY_ID) {
p.field_149406_b = actualID;
}
} else if (packet instanceof S0DPacketCollectItem) {
S0DPacketCollectItem p = (S0DPacketCollectItem) packet;
if (p.field_149356_b == LEGACY_ENTITY_ID) {
p.field_149356_b = actualID;
}
} else if (packet instanceof S13PacketDestroyEntities) {
S13PacketDestroyEntities p = (S13PacketDestroyEntities) packet;
if (p.field_149100_a.length == 1 && p.field_149100_a[0] == LEGACY_ENTITY_ID) {
p.field_149100_a[0] = actualID;
}
}
}
}

View File

@@ -1,6 +1,5 @@
package eu.crushedpixel.replaymod.settings;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.registry.LightingHandler;
import net.minecraft.client.resources.I18n;
import net.minecraftforge.common.config.Configuration;
@@ -10,34 +9,6 @@ public class ReplaySettings {
private static final String[] CATEGORIES = new String[]{"recording", "replay", "render", "advanced"};
public void readValues() {
Configuration config = ReplayMod.config;
config.load();
for(RecordingOptions o : RecordingOptions.values()) {
Property p = getConfigSetting(config, o.name(), o.getValue(), "recording", false);
o.setValue(getValueObject(p));
}
for(ReplayOptions o : ReplayOptions.values()) {
Property p = getConfigSetting(config, o.name(), o.getValue(), "replay", false);
o.setValue(getValueObject(p));
}
for(RenderOptions o : RenderOptions.values()) {
Property p = getConfigSetting(config, o.name(), o.getValue(), "render", false);
o.setValue(getValueObject(p));
}
for(AdvancedOptions o : AdvancedOptions.values()) {
Property p = getConfigSetting(config, o.name(), o.getValue(), "advanced", true);
o.setValue(getValueObject(p));
}
config.save();
}
public String getRecordingPath() {
return (String) AdvancedOptions.recordingPath.getValue();
}
@@ -54,12 +25,10 @@ public class ReplaySettings {
public void setVideoFramerate(int framerate) {
RenderOptions.videoFramerate.setValue(Math.min(120, Math.max(10, framerate)));
rewriteSettings();
}
public void toggleInterpolation() {
ReplayOptions.linear.setValue(!((Boolean)ReplayOptions.linear.getValue()));
rewriteSettings();
}
public boolean showRecordingIndicator() {
@@ -89,46 +58,18 @@ public class ReplaySettings {
public void setLightingEnabled(boolean enabled) {
ReplayOptions.lighting.setValue(enabled);
LightingHandler.setLighting(enabled);
rewriteSettings();
}
public boolean showPathPreview() { return (Boolean) ReplayOptions.previewPath.getValue(); }
public void setShowPathPreview(boolean show) {
ReplayOptions.previewPath.setValue(show);
rewriteSettings();
}
public boolean showClearKeyframesCallback() {
return (Boolean) ReplayOptions.keyframeCleanCallback.getValue();
}
public void rewriteSettings() {
ReplayMod.config.load();
for(String cat : CATEGORIES) {
ReplayMod.config.removeCategory(ReplayMod.config.getCategory(cat));
}
for(RecordingOptions o : RecordingOptions.values()) {
getConfigSetting(ReplayMod.config, o.name(), o.getValue(), "recording", false);
}
for(ReplayOptions o : ReplayOptions.values()) {
getConfigSetting(ReplayMod.config, o.name(), o.getValue(), "replay", false);
}
for(RenderOptions o : RenderOptions.values()) {
getConfigSetting(ReplayMod.config, o.name(), o.getValue(), "render", false);
}
for(AdvancedOptions o : AdvancedOptions.values()) {
getConfigSetting(ReplayMod.config, o.name(), o.getValue(), "advanced", false);
}
ReplayMod.config.save();
}
private Property getConfigSetting(Configuration config, String name, Object value, String category, boolean warning) {
if(warning) {
String warningMsg = "Please be careful when modifying this setting, as setting it to an invalid value might harm your computer.";
@@ -174,7 +115,7 @@ public class ReplaySettings {
public enum RecordingOptions implements ValueEnum {
recordServer(true, "replaymod.gui.settings.recordserver"),
recordSingleplayer(true, "replaymod.gui.settings.recordsingleplayer"),
notifications(true, "replaymod.gui.settings.notifications"),
notifications(true, "replaymod.gui.settings.notifications"), // TODO
indicator(true, "replaymod.gui.settings.indicator");
private Object value;

View File

@@ -8,7 +8,7 @@ import de.johni0702.replaystudio.filter.StreamFilter;
import de.johni0702.replaystudio.replay.ReplayFile;
import de.johni0702.replaystudio.replay.ReplayMetaData;
import de.johni0702.replaystudio.stream.PacketStream;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import org.apache.commons.io.IOUtils;
import org.spacehq.mc.protocol.packet.ingame.server.ServerResourcePackSendPacket;
import org.spacehq.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket;

View File

@@ -90,9 +90,9 @@ public class StudioImplementation {
}
private static void shiftPaths(ReplayFile replayFile, int beginning, int ending) throws IOException {
Optional<InputStream> in = replayFile.get(eu.crushedpixel.replaymod.utils.ReplayFile.ENTRY_PATHS);
Optional<InputStream> in = replayFile.get("paths.json");
if (!in.isPresent()) {
in = replayFile.get(eu.crushedpixel.replaymod.utils.ReplayFile.ENTRY_PATHS_OLD);
in = replayFile.get("paths");
if (!in.isPresent()) {
return;
}
@@ -126,7 +126,7 @@ public class StudioImplementation {
}
}
Writer out = new OutputStreamWriter(replayFile.write(eu.crushedpixel.replaymod.utils.ReplayFile.ENTRY_PATHS));
Writer out = new OutputStreamWriter(replayFile.write("paths.json"));
new Gson().toJson(resultSets.toArray(new KeyframeSet[resultSets.size()]), out);
out.flush();
out.close();

View File

@@ -1,9 +1,5 @@
package eu.crushedpixel.replaymod.timer;
import eu.crushedpixel.replaymod.ReplayMod;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplayProcess;
public class EnchantmentTimer {
private static long lastRealTime = System.currentTimeMillis();
@@ -20,17 +16,18 @@ public class EnchantmentTimer {
}
public static long getEnchantmentTime() {
if(!(ReplayHandler.isInPath() && ReplayProcess.isVideoRecording())) {
if(ReplayHandler.isInReplay()) {
long timeDiff = System.currentTimeMillis() - lastRealTime;
double toAdd = timeDiff * ReplayMod.replaySender.getReplaySpeed();
lastFakeTime = Math.round(lastFakeTime + toAdd);
lastRealTime = System.currentTimeMillis();
return lastFakeTime;
}
lastFakeTime = lastRealTime = System.currentTimeMillis();
return lastRealTime;
}
// TODO
// if(!(ReplayHandler.isInPath() && ReplayProcess.isVideoRecording())) {
// if(ReplayHandler.isInReplay()) {
// long timeDiff = System.currentTimeMillis() - lastRealTime;
// double toAdd = timeDiff * ReplayMod.replaySender.getReplaySpeed();
// lastFakeTime = Math.round(lastFakeTime + toAdd);
// lastRealTime = System.currentTimeMillis();
// return lastFakeTime;
// }
// lastFakeTime = lastRealTime = System.currentTimeMillis();
// return lastRealTime;
// }
return recordingTime;
}
}

View File

@@ -1,6 +1,6 @@
package eu.crushedpixel.replaymod.utils;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.chat.ChatMessageHandler;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;

View File

@@ -1,269 +0,0 @@
package eu.crushedpixel.replaymod.utils;
import com.google.common.base.Supplier;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import eu.crushedpixel.replaymod.assets.AssetRepository;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.KeyframeSet;
import eu.crushedpixel.replaymod.holders.Marker;
import eu.crushedpixel.replaymod.holders.PlayerVisibility;
import eu.crushedpixel.replaymod.recording.ReplayMetaData;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.reflect.Type;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ReplayFile extends ZipFile {
public static final String TEMP_FILE_EXTENSION = ".tmcpr";
public static final String JSON_FILE_EXTENSION = ".json";
public static final String ZIP_FILE_EXTENSION = ".mcpr";
public static final String ENTRY_RECORDING = "recording" + TEMP_FILE_EXTENSION;
public static final String ENTRY_METADATA = "metaData" + JSON_FILE_EXTENSION;
public static final String ENTRY_PATHS_OLD = "paths";
public static final String ENTRY_PATHS = "paths" + JSON_FILE_EXTENSION;
public static final String ENTRY_THUMB = "thumb";
public static final String ENTRY_RESOURCE_PACK = "resourcepack/%s.zip";
public static final String ENTRY_RESOURCE_PACK_INDEX = "resourcepack/index"+JSON_FILE_EXTENSION;
public static final String ENTRY_VISIBILITY_OLD = "visibility";
public static final String ENTRY_VISIBILITY = "visibility" + JSON_FILE_EXTENSION;
public static final String ENTRY_MARKERS = "markers" + JSON_FILE_EXTENSION;
public static final String ENTRY_ASSET_FOLDER = "asset/";
private final File file;
public ReplayFile(File f) throws IOException {
super(f);
this.file = f;
}
public File getFile() {
return file;
}
public ZipEntry recordingEntry() {
return getEntry(ENTRY_RECORDING);
}
public Supplier<InputStream> recording() {
return new Supplier<InputStream>() {
@Override
public InputStream get() {
try {
return getInputStream(recordingEntry());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public ZipEntry metadataEntry() {
return getEntry(ENTRY_METADATA);
}
public Supplier<ReplayMetaData> metadata() {
return new Supplier<ReplayMetaData>() {
@Override
public ReplayMetaData get() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(getInputStream(metadataEntry())));
return new Gson().fromJson(reader, ReplayMetaData.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public ZipEntry pathsEntry() {
ZipEntry newEntry = getEntry(ENTRY_PATHS);
return newEntry != null ? newEntry : getEntry(ENTRY_PATHS_OLD);
}
public Supplier<KeyframeSet[]> paths() {
return new Supplier<KeyframeSet[]>() {
@Override
public KeyframeSet[] get() {
try {
ZipEntry entry = pathsEntry();
if (entry == null) {
return null;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(getInputStream(entry)));
GsonBuilder gsonBuilder = new GsonBuilder().registerTypeAdapter(KeyframeSet[].class, new LegacyKeyframeSetAdapter());
Gson gson = gsonBuilder.create();
return gson.fromJson(reader, KeyframeSet[].class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public ZipEntry visibilityEntry() {
ZipEntry newEntry = getEntry(ENTRY_VISIBILITY);
return newEntry != null ? newEntry : getEntry(ENTRY_VISIBILITY_OLD);
}
public Supplier<PlayerVisibility> visibility() {
return new Supplier<PlayerVisibility>() {
@Override
public PlayerVisibility get() {
try {
ZipEntry entry = visibilityEntry();
if (entry == null) {
return null;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(getInputStream(entry)));
return new Gson().fromJson(reader, PlayerVisibility.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public ZipEntry markersEntry() {
return getEntry(ENTRY_MARKERS);
}
public Supplier<List<Keyframe<Marker>>> markers() {
return new Supplier<List<Keyframe<Marker>>>() {
@Override
public List<Keyframe<Marker>> get() {
try {
ZipEntry entry = markersEntry();
if (entry == null) {
return null;
}
BufferedReader reader = new BufferedReader(new InputStreamReader(getInputStream(entry)));
Type keyframeType = new TypeToken<ArrayList<Keyframe<Marker>>>(){}.getType();
return new Gson().fromJson(reader, keyframeType);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public ZipEntry thumbEntry() {
return getEntry(ENTRY_THUMB);
}
public Supplier<BufferedImage> thumb() {
return new Supplier<BufferedImage>() {
@Override
public BufferedImage get() {
try {
ZipEntry entry = thumbEntry();
if (entry == null) {
return null;
}
InputStream is = getInputStream(entry);
int i = 7;
while (i > 0) {
i -= is.skip(i); // Security through obscurity \o/
}
return ImageIO.read(is);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public ZipEntry resourcePackIndexEntry() {
return getEntry(ENTRY_RESOURCE_PACK_INDEX);
}
public Supplier<Map<Integer, String>> resourcePackIndex() {
return new Supplier<Map<Integer, String>>() {
@Override
@SuppressWarnings("unchecked")
public Map<Integer, String> get() {
try {
ZipEntry entry = resourcePackIndexEntry();
if (entry == null) {
return null;
}
Map<Integer, String> index = new HashMap<Integer, String>();
JsonObject json = new Gson().fromJson(new InputStreamReader(getInputStream(entry)), JsonObject.class);
for (Map.Entry<String, JsonElement> e : json.entrySet()) {
index.put(Integer.parseInt(e.getKey()), e.getValue().getAsString());
}
return index;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public ZipEntry resourcePackEntry(String hash) {
return getEntry(String.format(ENTRY_RESOURCE_PACK, hash));
}
public Supplier<InputStream> resourcePack(final String hash) {
return new Supplier<InputStream>() {
@Override
public InputStream get() {
try {
ZipEntry entry = resourcePackEntry(hash);
if (entry == null) {
return null;
}
return getInputStream(entry);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public Supplier<AssetRepository> assetRepository() {
return new Supplier<AssetRepository>() {
@Override
@SuppressWarnings("unchecked")
public AssetRepository get() {
AssetRepository assetRepository = new AssetRepository();
Enumeration<? extends ZipEntry> entries = entries();
while(entries.hasMoreElements()) {
try {
ZipEntry entry = entries.nextElement();
String entryName = entry.getName();
if(entryName.startsWith(ENTRY_ASSET_FOLDER)) {
String name = entry.getName().substring(ENTRY_ASSET_FOLDER.length());
String[] split = name.split("_");
UUID uuid = UUID.fromString(split[0]);
assetRepository.addAsset(name, getInputStream(entry), uuid);
}
} catch(Exception e) {
e.printStackTrace();
}
}
return assetRepository;
}
};
}
}

View File

@@ -1,12 +1,12 @@
package eu.crushedpixel.replaymod.utils;
import com.google.gson.Gson;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.recording.packet.PacketSerializer;
import de.johni0702.replaystudio.replay.ReplayMetaData;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.assets.CustomObjectRepository;
import eu.crushedpixel.replaymod.holders.*;
import eu.crushedpixel.replaymod.interpolation.KeyframeList;
import eu.crushedpixel.replaymod.recording.PacketSerializer;
import eu.crushedpixel.replaymod.recording.ReplayMetaData;
import eu.crushedpixel.replaymod.holders.KeyframeSet;
import eu.crushedpixel.replaymod.holders.PacketData;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.network.EnumConnectionState;
@@ -15,10 +15,12 @@ import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import java.io.*;
import java.util.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -72,57 +74,6 @@ public class ReplayFileIO {
return files;
}
public static void writeReplayFile(File replayFile, File tempFile, ReplayMetaData metaData, Set<Keyframe<Marker>> markers,
Map<String, File> resourcePacks, Map<Integer, String> resourcePackRequests) throws IOException {
byte[] buffer = new byte[1024];
FileOutputStream fos = new FileOutputStream(replayFile);
ZipOutputStream zos = new ZipOutputStream(fos);
String json = new Gson().toJson(metaData);
zos.putNextEntry(new ZipEntry(ReplayFile.ENTRY_METADATA));
PrintWriter pw = new PrintWriter(zos);
pw.write(json);
pw.flush();
zos.closeEntry();
zos.putNextEntry(new ZipEntry(ReplayFile.ENTRY_RECORDING));
FileInputStream fis = new FileInputStream(tempFile);
int len;
while((len = fis.read(buffer)) > 0) {
zos.write(buffer, 0, len);
}
fis.close();
zos.closeEntry();
if(!markers.isEmpty()) {
zos.putNextEntry(new ZipEntry(ReplayFile.ENTRY_MARKERS));
pw = new PrintWriter(zos);
pw.write(new Gson().toJson(markers.toArray(new Keyframe[markers.size()])));
pw.flush();
zos.closeEntry();
}
if(!resourcePackRequests.isEmpty()) {
zos.putNextEntry(new ZipEntry(ReplayFile.ENTRY_RESOURCE_PACK_INDEX));
pw = new PrintWriter(zos);
pw.write(new Gson().toJson(resourcePackRequests));
pw.flush();
zos.closeEntry();
for(Map.Entry<String, File> entry : resourcePacks.entrySet()) {
zos.putNextEntry(new ZipEntry(String.format(ReplayFile.ENTRY_RESOURCE_PACK, entry.getKey())));
IOUtils.copy(new FileInputStream(entry.getValue()), zos);
zos.closeEntry();
}
}
zos.close();
}
public static PacketData readPacketData(DataInputStream dis) throws IOException {
int timestamp = dis.readInt();
int bytes = dis.readInt();
@@ -160,12 +111,6 @@ public class ReplayFileIO {
return array;
}
public static void writePacket(PacketData pd, DataOutput out) throws IOException {
out.writeInt(pd.getTimestamp());
out.writeInt(pd.getByteArray().length);
out.write(pd.getByteArray());
}
private static final Gson gson = new Gson();
private static void write(Object obj, File file) throws IOException {
@@ -177,18 +122,10 @@ public class ReplayFileIO {
write((Object) keyframeRegistry, file);
}
public static void write(PlayerVisibility visibility, File file) throws IOException {
write((Object) visibility, file);
}
public static void write(ReplayMetaData metaData, File file) throws IOException {
write((Object) metaData, file);
}
public static void write(KeyframeList<Marker> markers, File file) throws IOException {
write((Object) markers, file);
}
public static void write(CustomObjectRepository repository, File file) throws IOException {
write((Object) repository, file);
}

View File

@@ -1,17 +1,14 @@
package eu.crushedpixel.replaymod.video;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import eu.crushedpixel.replaymod.chat.ChatMessageHandler.ChatMessageType;
import eu.crushedpixel.replaymod.events.handlers.TickAndRenderListener;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.utils.ImageUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
public class ReplayScreenshot {
@@ -67,20 +64,13 @@ public class ReplayScreenshot {
final BufferedImage nbi = ImageUtils.cropImage(fbi, rect);
File replayFile = ReplayHandler.getReplayFile();
File tempImage = File.createTempFile("thumb", null);
int h = 720;
int w = 1280;
BufferedImage img = ImageUtils.scaleImage(nbi, new Dimension(w, h));
ImageIO.write(img, "jpg", tempImage);
ReplayMod.replayFileAppender.registerModifiedFile(tempImage, "thumb", replayFile);
tempImage.deleteOnExit();
// TODO
// ReplayHandler.getReplayFile().writeThumb(img);
ReplayMod.chatMessageHandler.addLocalizedChatMessage("replaymod.chat.savedthumb", ChatMessageType.INFORMATION);
} catch(Exception e) {

View File

@@ -1,17 +1,13 @@
package eu.crushedpixel.replaymod.video;
import eu.crushedpixel.replaymod.ReplayMod;
import com.replaymod.core.ReplayMod;
import com.replaymod.replay.ReplaySender;
import eu.crushedpixel.replaymod.gui.GuiVideoRenderer;
import eu.crushedpixel.replaymod.holders.AdvancedPosition;
import eu.crushedpixel.replaymod.holders.Keyframe;
import eu.crushedpixel.replaymod.holders.SpectatorData;
import eu.crushedpixel.replaymod.holders.TimestampValue;
import eu.crushedpixel.replaymod.interpolation.KeyframeList;
import eu.crushedpixel.replaymod.renderer.ChunkLoadingRenderGlobal;
import eu.crushedpixel.replaymod.replay.ReplayHandler;
import eu.crushedpixel.replaymod.replay.ReplaySender;
import eu.crushedpixel.replaymod.settings.RenderOptions;
import eu.crushedpixel.replaymod.timer.EnchantmentTimer;
import eu.crushedpixel.replaymod.timer.ReplayTimer;
import eu.crushedpixel.replaymod.video.capturer.RenderInfo;
import eu.crushedpixel.replaymod.video.frame.RGBFrame;
@@ -148,8 +144,9 @@ public class VideoRenderer implements RenderInfo {
fps = options.getFps();
positionKeyframes = ReplayHandler.getPositionKeyframes();
timeKeyframes = ReplayHandler.getTimeKeyframes();
// TODO
// positionKeyframes = ReplayHandler.getPositionKeyframes();
// timeKeyframes = ReplayHandler.getTimeKeyframes();
int duration = Math.max(timeKeyframes.last().getRealTimestamp(), positionKeyframes.last().getRealTimestamp());
@@ -179,128 +176,130 @@ public class VideoRenderer implements RenderInfo {
}
private void updateCam() {
KeyframeList<AdvancedPosition> positionKeyframes = ReplayHandler.getPositionKeyframes();
if (mc.thePlayer == null) {
return; // Not ready yet
}
int videoTime = framesDone * 1000 / fps;
int posCount = ReplayHandler.getPositionKeyframes().size();
AdvancedPosition pos = new AdvancedPosition();
Keyframe<AdvancedPosition> lastPos = positionKeyframes.getPreviousKeyframe(videoTime, true);
Keyframe<AdvancedPosition> nextPos = null;
// Position interpolation
nextPos = positionKeyframes.getNextKeyframe(videoTime, true);
int lastPosStamp = lastPos.getRealTimestamp();
int nextPosStamp = (nextPos == null ? lastPos : nextPos).getRealTimestamp();
int diffLength = nextPosStamp - lastPosStamp;
float diffPct = (float) (videoTime - lastPosStamp) / diffLength;
if(Float.isInfinite(diffPct) || Float.isNaN(diffPct)) diffPct = 0;
float totalPct = (positionKeyframes.indexOf(lastPos) + diffPct) / (posCount-1);
pos = positionKeyframes.getInterpolatedValueForPathPosition(Math.max(0, Math.min(1, totalPct)), ReplayMod.replaySettings.isLinearMovement());
boolean spectateCamera = true;
//check whether between two First Person Spectator Keyframes
if(lastPos != null && nextPos != null) {
if(lastPos.getValue() instanceof SpectatorData && nextPos.getValue() instanceof SpectatorData) {
SpectatorData previousSpectatorData = (SpectatorData)lastPos.getValue();
SpectatorData nextSpectatorData = (SpectatorData)nextPos.getValue();
if(previousSpectatorData.getSpectatedEntityID() == nextSpectatorData.getSpectatedEntityID()) {
if(previousSpectatorData.getSpectatingMethod() == SpectatorData.SpectatingMethod.FIRST_PERSON
&& nextSpectatorData.getSpectatingMethod() == SpectatorData.SpectatingMethod.FIRST_PERSON) {
spectateCamera = false;
}
}
}
}
if(spectateCamera) {
// Make sure we're spectating the camera entity
// We do not use .spectateCamera() as that method sets the position of the camera to the previous
// entity, overriding our calculations
ReplayHandler.spectateEntity(ReplayHandler.getCameraEntity());
if(pos != null) {
ReplayHandler.setCameraTilt((float)pos.getRoll());
ReplayHandler.getCameraEntity().movePath(pos);
mc.entityRenderer.fovModifierHand = mc.entityRenderer.fovModifierHandPrev = 1;
}
} else {
ReplayHandler.spectateEntity(mc.theWorld.getEntityByID(((SpectatorData)lastPos.getValue()).getSpectatedEntityID()));
}
//TODO
// KeyframeList<AdvancedPosition> positionKeyframes = ReplayHandler.getPositionKeyframes();
//
// if (mc.thePlayer == null) {
// return; // Not ready yet
// }
// int videoTime = framesDone * 1000 / fps;
// int posCount = ReplayHandler.getPositionKeyframes().size();
//
// AdvancedPosition pos = new AdvancedPosition();
// Keyframe<AdvancedPosition> lastPos = positionKeyframes.getPreviousKeyframe(videoTime, true);
// Keyframe<AdvancedPosition> nextPos = null;
//
// // Position interpolation
// nextPos = positionKeyframes.getNextKeyframe(videoTime, true);
//
// int lastPosStamp = lastPos.getRealTimestamp();
// int nextPosStamp = (nextPos == null ? lastPos : nextPos).getRealTimestamp();
//
// int diffLength = nextPosStamp - lastPosStamp;
// float diffPct = (float) (videoTime - lastPosStamp) / diffLength;
// if(Float.isInfinite(diffPct) || Float.isNaN(diffPct)) diffPct = 0;
//
// float totalPct = (positionKeyframes.indexOf(lastPos) + diffPct) / (posCount-1);
// pos = positionKeyframes.getInterpolatedValueForPathPosition(Math.max(0, Math.min(1, totalPct)), ReplayMod.replaySettings.isLinearMovement());
//
// boolean spectateCamera = true;
//
// //check whether between two First Person Spectator Keyframes
// if(lastPos != null && nextPos != null) {
// if(lastPos.getValue() instanceof SpectatorData && nextPos.getValue() instanceof SpectatorData) {
// SpectatorData previousSpectatorData = (SpectatorData)lastPos.getValue();
// SpectatorData nextSpectatorData = (SpectatorData)nextPos.getValue();
// if(previousSpectatorData.getSpectatedEntityID() == nextSpectatorData.getSpectatedEntityID()) {
// if(previousSpectatorData.getSpectatingMethod() == SpectatorData.SpectatingMethod.FIRST_PERSON
// && nextSpectatorData.getSpectatingMethod() == SpectatorData.SpectatingMethod.FIRST_PERSON) {
// spectateCamera = false;
// }
// }
// }
// }
//
// if(spectateCamera) {
// // Make sure we're spectating the camera entity
// // We do not use .spectateCamera() as that method sets the position of the camera to the previous
// // entity, overriding our calculations
// ReplayHandler.spectateEntity(ReplayHandler.getCameraEntity());
//
// if(pos != null) {
// ReplayHandler.setCameraTilt((float)pos.getRoll());
// ReplayHandler.getCameraEntity().movePath(pos);
// mc.entityRenderer.fovModifierHand = mc.entityRenderer.fovModifierHandPrev = 1;
// }
// } else {
// ReplayHandler.spectateEntity(mc.theWorld.getEntityByID(((SpectatorData)lastPos.getValue()).getSpectatedEntityID()));
// }
}
private void updateTime(Timer timer, int framesDone) {
KeyframeList<TimestampValue> timeKeyframes = ReplayHandler.getTimeKeyframes();
int videoTime = framesDone * 1000 / fps;
int timeCount = timeKeyframes.size();
// WARNING: The rest of this method contains some magic for which Marius is responsible
// Time interpolation
Keyframe<TimestampValue> lastTime = timeKeyframes.getPreviousKeyframe(videoTime, true);
Keyframe<TimestampValue> nextTime = timeKeyframes.getNextKeyframe(videoTime, true);
int lastTimeStamp = 0;
int nextTimeStamp = 0;
double curSpeed = 0;
if(nextTime != null || lastTime != null) {
if(nextTime != null && lastTime != null && nextTime.getRealTimestamp() == lastTime.getRealTimestamp()) {
curSpeed = 0;
} else {
if(nextTime != null) {
nextTimeStamp = nextTime.getRealTimestamp();
} else {
nextTimeStamp = lastTime.getRealTimestamp();
}
if(lastTime != null) {
lastTimeStamp = lastTime.getRealTimestamp();
} else {
lastTimeStamp = nextTime.getRealTimestamp();
}
if(!(nextTime == null || lastTime == null)) {
curSpeed = ((double)(((int)nextTime.getValue().value-(int)lastTime.getValue().value)))/((double)((nextTimeStamp-lastTimeStamp)));
}
if(lastTimeStamp == nextTimeStamp) {
curSpeed = 0f;
}
}
}
int currentTimeDiff = nextTimeStamp - lastTimeStamp;
int currentTime = videoTime - lastTimeStamp;
float currentTimeStepPerc = (float)currentTime/(float)currentTimeDiff; //The percentage of the travelled path between the current timestamps
if(Float.isInfinite(currentTimeStepPerc) || Float.isNaN(currentTimeStepPerc)) currentTimeStepPerc = 0;
float timePos = (timeKeyframes.indexOf(lastTime) + currentTimeStepPerc) / (timeCount-1f);
Integer replayTime = timeKeyframes.getInterpolatedValueForPathPosition(Math.max(0, Math.min(1, timePos)), true).asInt();
replaySender.sendPacketsTill(replayTime);
if (curSpeed >= 0) {
replaySender.setReplaySpeed(curSpeed);
}
// Update Timer
EnchantmentTimer.increaseRecordingTime(1000 / fps);
timer.elapsedPartialTicks += timer.timerSpeed * 20 / fps;
timer.elapsedTicks = (int) timer.elapsedPartialTicks;
timer.elapsedPartialTicks -= timer.elapsedTicks;
timer.renderPartialTicks = timer.elapsedPartialTicks;
// TODO
// KeyframeList<TimestampValue> timeKeyframes = ReplayHandler.getTimeKeyframes();
//
// int videoTime = framesDone * 1000 / fps;
// int timeCount = timeKeyframes.size();
//
// // WARNING: The rest of this method contains some magic for which Marius is responsible
// // Time interpolation
// Keyframe<TimestampValue> lastTime = timeKeyframes.getPreviousKeyframe(videoTime, true);
// Keyframe<TimestampValue> nextTime = timeKeyframes.getNextKeyframe(videoTime, true);
//
// int lastTimeStamp = 0;
// int nextTimeStamp = 0;
//
// double curSpeed = 0;
//
// if(nextTime != null || lastTime != null) {
// if(nextTime != null && lastTime != null && nextTime.getRealTimestamp() == lastTime.getRealTimestamp()) {
// curSpeed = 0;
// } else {
// if(nextTime != null) {
// nextTimeStamp = nextTime.getRealTimestamp();
// } else {
// nextTimeStamp = lastTime.getRealTimestamp();
// }
//
// if(lastTime != null) {
// lastTimeStamp = lastTime.getRealTimestamp();
// } else {
// lastTimeStamp = nextTime.getRealTimestamp();
// }
//
// if(!(nextTime == null || lastTime == null)) {
// curSpeed = ((double)(((int)nextTime.getValue().value-(int)lastTime.getValue().value)))/((double)((nextTimeStamp-lastTimeStamp)));
// }
//
// if(lastTimeStamp == nextTimeStamp) {
// curSpeed = 0f;
// }
// }
// }
//
// int currentTimeDiff = nextTimeStamp - lastTimeStamp;
// int currentTime = videoTime - lastTimeStamp;
//
// float currentTimeStepPerc = (float)currentTime/(float)currentTimeDiff; //The percentage of the travelled path between the current timestamps
// if(Float.isInfinite(currentTimeStepPerc) || Float.isNaN(currentTimeStepPerc)) currentTimeStepPerc = 0;
//
// float timePos = (timeKeyframes.indexOf(lastTime) + currentTimeStepPerc) / (timeCount-1f);
//
// Integer replayTime = timeKeyframes.getInterpolatedValueForPathPosition(Math.max(0, Math.min(1, timePos)), true).asInt();
//
// replaySender.sendPacketsTill(replayTime);
//
// if (curSpeed >= 0) {
// replaySender.setReplaySpeed(curSpeed);
// }
//
// // Update Timer
// EnchantmentTimer.increaseRecordingTime(1000 / fps);
//
// timer.elapsedPartialTicks += timer.timerSpeed * 20 / fps;
// timer.elapsedTicks = (int) timer.elapsedPartialTicks;
// timer.elapsedPartialTicks -= timer.elapsedTicks;
// timer.renderPartialTicks = timer.elapsedPartialTicks;
}
private void tick() {