// Copyright (c) 2015, Christopher "BlayTheNinth" Baker package net.blay09.mods.eirairc.client.screenshot; import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.stream.JsonWriter; import net.blay09.mods.eirairc.EiraIRC; import net.blay09.mods.eirairc.api.EiraIRCAPI; import net.blay09.mods.eirairc.api.event.ScreenshotUploadEvent; import net.blay09.mods.eirairc.api.irc.IRCChannel; import net.blay09.mods.eirairc.api.irc.IRCContext; import net.blay09.mods.eirairc.api.irc.IRCUser; import net.blay09.mods.eirairc.api.upload.UploadHoster; import net.blay09.mods.eirairc.client.UploadManager; import net.blay09.mods.eirairc.config.ClientGlobalConfig; import net.blay09.mods.eirairc.config.ScreenshotAction; import net.blay09.mods.eirairc.config.settings.BotSettings; import net.blay09.mods.eirairc.util.ConfigHelper; import net.blay09.mods.eirairc.util.MessageFormat; import net.blay09.mods.eirairc.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.EnumChatFormatting; import net.minecraft.util.IChatComponent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.nio.IntBuffer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.List; public class ScreenshotManager { private static final Logger logger = LogManager.getLogger(); private static ScreenshotManager instance; public static void create() { instance = new ScreenshotManager(); instance.load(); } public static ScreenshotManager getInstance() { return instance; } private static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss"); private static final Gson gson = new Gson(); private static IntBuffer intBuffer; private static int[] buffer; private final File screenshotDir = new File(Minecraft.getMinecraft().mcDataDir, "screenshots"); private final List<Screenshot> screenshots = Lists.newArrayList(); private final Comparator<Screenshot> comparator = (first, second) -> { long flm = first.getFile().lastModified(); long slm = second.getFile().lastModified(); if (flm < slm) { return 1; } else if(flm > slm) { return -1; } return 0; }; private final List<AsyncUploadScreenshot> uploadTasks = Lists.newArrayList(); private long lastScreenshotScan; public void load() { JsonObject metadataObject; try { Reader reader = new FileReader(new File(screenshotDir, "eirairc_metadata.json")); metadataObject = gson.fromJson(reader, JsonObject.class); } catch (FileNotFoundException e) { metadataObject = new JsonObject(); } File[] screenshotFiles = screenshotDir.listFiles((file, fileName) -> { return fileName.endsWith(".png"); }); if (screenshotFiles != null) { for(File screenshotFile : screenshotFiles) { screenshots.add(new Screenshot(screenshotFile, metadataObject.getAsJsonObject(screenshotFile.getName()))); } } lastScreenshotScan = System.currentTimeMillis(); Collections.sort(screenshots, comparator); } public void save() { JsonObject metadataObject = new JsonObject(); for(Screenshot screenshot : screenshots) { if (screenshot.getMetadata().entrySet().size() > 0) { metadataObject.add(screenshot.getFile().getName(), screenshot.getMetadata()); } } try { JsonWriter writer = new JsonWriter(new FileWriter(new File(screenshotDir, "eirairc_metadata.json"))); writer.setIndent(" "); gson.toJson(metadataObject, writer); writer.close(); } catch (IOException e) { e.printStackTrace(); } } public Screenshot takeScreenshot() { try { int width = Minecraft.getMinecraft().displayWidth; int height = Minecraft.getMinecraft().displayHeight; int k = width * height; if (intBuffer == null || intBuffer.capacity() < k) { intBuffer = BufferUtils.createIntBuffer(k); buffer = new int[k]; } GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1); GL11.glPixelStorei(GL11.GL_UNPACK_ALIGNMENT, 1); intBuffer.clear(); GL11.glReadPixels(0, 0, width, height, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, intBuffer); intBuffer.get(buffer); doSomeCrazyMagic(buffer, width, height); BufferedImage bufferedImage = new BufferedImage(width, height, 1); bufferedImage.setRGB(0, 0, width, height, buffer, 0, width); File screenshotFile = new File(screenshotDir, getScreenshotName(screenshotDir)); ImageIO.write(bufferedImage, "png", screenshotFile); Screenshot screenshot = new Screenshot(screenshotFile, null); screenshots.add(screenshot); Collections.sort(screenshots, comparator); return screenshot; } catch (Exception exception) { exception.printStackTrace(); return null; } } private static void doSomeCrazyMagic(int[] buffer, int width, int height) { int[] aint1 = new int[width]; int k = height / 2; for (int l = 0; l < k; ++l) { System.arraycopy(buffer, l * width, aint1, 0, width); System.arraycopy(buffer, (height - 1 - l) * width, buffer, l * width, width); System.arraycopy(aint1, 0, buffer, (height - 1 - l) * width, width); } } private static String getScreenshotName(File directory) { String s = dateFormat.format(new Date()); int i = 1; while (true) { File file = new File(directory, s + (i == 1 ? "" : "_" + i) + ".png"); if (!file.exists()) { return file.getName(); } i++; } } public List<Screenshot> getScreenshots() { return screenshots; } public void deleteScreenshot(Screenshot screenshot, boolean keepUploaded) { if(screenshot.getFile().delete()) { logger.error("Couldn't delete screenshot file {}", screenshot.getFile()); } if(!keepUploaded && screenshot.hasDeleteURL()) { Utils.openWebpage(screenshot.getDeleteURL()); } screenshots.remove(screenshot); } public void uploadScreenshot(Screenshot screenshot, ScreenshotAction followUpAction) { UploadHoster hoster = UploadManager.getUploadHoster(ClientGlobalConfig.screenshotHoster.get()); if (hoster != null) { uploadTasks.add(new AsyncUploadScreenshot(hoster, screenshot, followUpAction)); } } public void clientTick(ClientTickEvent event) { for(int i = uploadTasks.size() - 1; i >= 0; i--) { if(uploadTasks.get(i).isComplete()) { AsyncUploadScreenshot task = uploadTasks.remove(i); MinecraftForge.EVENT_BUS.post(new ScreenshotUploadEvent(task.getScreenshot().getFile(), task.getUploadedFile())); if(task.getScreenshot().isUploaded()) { ScreenshotAction action = task.getFollowUpAction(); if(action == ScreenshotAction.UploadClipboard) { Utils.setClipboardString(task.getScreenshot().getUploadURL()); } else if(action == ScreenshotAction.UploadShare) { shareScreenshot(task.getScreenshot()); } save(); } } } } public void shareScreenshot(Screenshot screenshot) { if(Minecraft.getMinecraft().thePlayer == null) { return; } IRCContext chatTarget = EiraIRC.instance.getChatSessionHandler().getChatTarget(); String screenshotURL = screenshot.getDirectURL() != null ? screenshot.getDirectURL() : screenshot.getUploadURL(); if(chatTarget == null) { String format = ConfigHelper.getBotSettings(null).getMessageFormat().ircScreenshotUpload; format = format.replace("{URL}", screenshotURL); format = format.replace("{NICK} ", ""); Minecraft.getMinecraft().thePlayer.sendChatMessage("/me " + format); } else { EntityPlayer sender = Minecraft.getMinecraft().thePlayer; String format; EnumChatFormatting emoteColor; IChatComponent chatComponent; IChatComponent chatComponentIRC; if (chatTarget instanceof IRCChannel) { BotSettings botSettings = ConfigHelper.getBotSettings(chatTarget); format = botSettings.getMessageFormat().ircScreenshotUpload.replace("{URL}", "{MESSAGE}"); emoteColor = ConfigHelper.getTheme(chatTarget).emoteTextColor.get(); chatComponent = MessageFormat.formatChatComponent(format, chatTarget, sender, screenshotURL, MessageFormat.Target.IRC, MessageFormat.Mode.Emote); format = format.replace("{NICK} ", ""); chatComponentIRC = MessageFormat.formatChatComponent(format, chatTarget, sender, screenshotURL, MessageFormat.Target.IRC, MessageFormat.Mode.Emote); } else if(chatTarget instanceof IRCUser) { BotSettings botSettings = ConfigHelper.getBotSettings(chatTarget); format = botSettings.getMessageFormat().ircScreenshotUpload.replace("{URL}", "{MESSAGE}"); emoteColor = ConfigHelper.getTheme(chatTarget).emoteTextColor.get(); chatComponent = MessageFormat.formatChatComponent(format, chatTarget, sender, screenshotURL, MessageFormat.Target.IRC, MessageFormat.Mode.Emote); format = format.replace("{NICK} ", ""); chatComponentIRC = MessageFormat.formatChatComponent(format, chatTarget, sender, screenshotURL, MessageFormat.Target.IRC, MessageFormat.Mode.Emote); } else { return; } if (emoteColor != null) { chatComponent.getChatStyle().setColor(emoteColor); } EiraIRCAPI.relayChat(sender, chatComponentIRC.getUnformattedText(), true, false, null); Utils.addMessageToChat(chatComponent); } } public void findNewScreenshots() { File[] screenshotFiles = screenshotDir.listFiles(file -> file.getName().endsWith(".png") && file.lastModified() > lastScreenshotScan); if (screenshotFiles != null) { for(File screenshotFile : screenshotFiles) { screenshots.add(new Screenshot(screenshotFile, null)); } } Collections.sort(screenshots, comparator); lastScreenshotScan = System.currentTimeMillis(); } }