Java tutorial
/* * opsu!dance - fork of opsu! with cursordance auto * Copyright (C) 2017 yugecin * * opsu!dance is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * opsu!dance is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with opsu!dance. If not, see <http://www.gnu.org/licenses/>. */ package yugecin.opsudance.options; import com.sun.istack.internal.Nullable; import com.sun.jna.platform.win32.Advapi32Util; import com.sun.jna.platform.win32.Win32Exception; import com.sun.jna.platform.win32.WinReg; import itdelatrisu.opsu.audio.SoundController; import itdelatrisu.opsu.audio.SoundEffect; import itdelatrisu.opsu.beatmap.Beatmap; import itdelatrisu.opsu.beatmap.TimingPoint; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.Display; import org.lwjgl.opengl.GL11; import yugecin.opsudance.core.errorhandling.ErrorHandler; import yugecin.opsudance.core.events.EventBus; import yugecin.opsudance.events.BubbleNotificationEvent; import yugecin.opsudance.utils.ManifestWrapper; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.regex.Matcher; import java.util.regex.Pattern; import static yugecin.opsudance.options.Options.*; import static yugecin.opsudance.core.InstanceContainer.*; public class Configuration { public final boolean USE_XDG; public final File CONFIG_DIR; public final File DATA_DIR; public final File CACHE_DIR; public final File BEATMAP_DIR; public final File SKIN_ROOT_DIR; public final File BEATMAP_DB; public final File SCORE_DB; public final File NATIVE_DIR; public final File TEMP_DIR; public final File LOG_FILE; public final File OPTIONS_FILE; public final File osuInstallationDirectory; public final Beatmap themeBeatmap; public File beatmapDir; public File oszDir; public File screenshotDir; public File replayDir; public File replayImportDir; public File skinRootDir; public Configuration(ManifestWrapper jarmanifest) { USE_XDG = jarmanifest.valueOrDefault(null, "Use-XDG", "").equalsIgnoreCase("true"); CONFIG_DIR = getXDGBaseDir("XDG_CONFIG_HOME", ".config"); DATA_DIR = getXDGBaseDir("XDG_DATA_HOME", ".local/share"); CACHE_DIR = getXDGBaseDir("XDG_CACHE_HOME", ".cache"); BEATMAP_DIR = new File(DATA_DIR, "Songs/"); SKIN_ROOT_DIR = new File(DATA_DIR, "Skins/"); BEATMAP_DB = new File(DATA_DIR, ".opsu.db"); SCORE_DB = new File(DATA_DIR, ".opsu_scores.db"); NATIVE_DIR = new File(CACHE_DIR, "Natives/"); TEMP_DIR = new File(CACHE_DIR, "Temp/"); LOG_FILE = new File(CONFIG_DIR, ".opsu.log"); OPTIONS_FILE = new File(CONFIG_DIR, ".opsu.cfg"); osuInstallationDirectory = loadOsuInstallationDirectory(); themeBeatmap = createThemeBeatmap(); } private Beatmap createThemeBeatmap() { try { String[] tokens = { "theme.mp3", "Rainbows", "Kevin MacLeod", "219350" }; Beatmap beatmap = new Beatmap(null); beatmap.audioFilename = new File(tokens[0]); beatmap.title = tokens[1]; beatmap.artist = tokens[2]; beatmap.endTime = Integer.parseInt(tokens[3]); beatmap.timingPoints = new ArrayList<>(1); beatmap.timingPoints.add(new TimingPoint("1080,545.454545454545,4,1,0,100,0,0")); return beatmap; } catch (Exception e) { return null; } } private File loadOsuInstallationDirectory() { if (!System.getProperty("os.name").startsWith("Win")) { return null; } final WinReg.HKEY rootKey = WinReg.HKEY_CLASSES_ROOT; final String regKey = "osu\\DefaultIcon"; final String regValue = null; // default value final String regPathPattern = "\"(.+)\\\\[^\\/]+\\.exe\""; String value; try { value = Advapi32Util.registryGetStringValue(rootKey, regKey, regValue); } catch (Win32Exception ignored) { return null; } Pattern pattern = Pattern.compile(regPathPattern); Matcher m = pattern.matcher(value); if (!m.find()) { return null; } File dir = new File(m.group(1)); if (dir.isDirectory()) { return dir; } return null; } public void loadDirectories() { replayImportDir = loadDirectory(replayImportDir, new File(DATA_DIR, "ReplayImport"), "replay import"); oszDir = loadDirectory(oszDir, new File(DATA_DIR, "SongPacks"), "song packs"); screenshotDir = loadDirectory(screenshotDir, new File(DATA_DIR, "Screenshots"), "screenshots"); replayDir = loadDirectory(replayDir, new File(DATA_DIR, "Replays"), "replays"); beatmapDir = loadOsuDirectory(beatmapDir, BEATMAP_DIR, "beatmap"); skinRootDir = loadOsuDirectory(skinRootDir, SKIN_ROOT_DIR, "skin root"); } private File loadDirectory(File dir, File defaultDir, String kind) { if (dir != null && dir.exists() && dir.isDirectory()) { return dir; } if (!defaultDir.isDirectory() && !defaultDir.mkdir()) { String msg = String.format("Failed to create %s directory at '%s'.", kind, defaultDir.getAbsolutePath()); EventBus.post(new BubbleNotificationEvent(msg, BubbleNotificationEvent.COMMONCOLOR_RED)); } return defaultDir; } private File loadOsuDirectory(File dir, File defaultDir, String kind) { if (dir != null && dir.isDirectory()) { return dir; } if (osuInstallationDirectory != null) { dir = new File(osuInstallationDirectory, defaultDir.getName()); if (dir.isDirectory()) { return dir; } } return loadDirectory(dir, defaultDir, kind); } /** * Returns the directory based on the XDG base directory specification for * Unix-like operating systems, only if the "XDG" flag is enabled. * @param envvar the environment variable to check (XDG_*_*) * @param fallback the fallback directory relative to ~home * @return the XDG base directory, or the working directory if unavailable */ private File getXDGBaseDir(String envvar, String fallback) { if (!USE_XDG) { return env.workingdir; } String OS = System.getProperty("os.name").toLowerCase(); if (OS.indexOf("nix") == -1 && OS.indexOf("nux") == -1 && OS.indexOf("aix") == -1) { return env.workingdir; } String rootPath = System.getenv(envvar); if (rootPath == null) { String home = System.getProperty("user.home"); if (home == null) { return new File("./"); } rootPath = String.format("%s/%s", home, fallback); } File dir = new File(rootPath, "opsu"); if (!dir.isDirectory() && !dir.mkdir()) { ErrorHandler.error(String.format("Failed to create configuration folder at '%s/opsu'.", rootPath), new Exception("empty")).preventReport().show(); } return dir; } /** * @author http://wiki.lwjgl.org/index.php?title=Taking_Screen_Shots */ public void takeScreenShot() { // TODO: get a decent place for this // create the screenshot directory if (!screenshotDir.isDirectory() && !screenshotDir.mkdir()) { EventBus.post( new BubbleNotificationEvent(String.format("Failed to create screenshot directory at '%s'.", screenshotDir.getAbsolutePath()), BubbleNotificationEvent.COMMONCOLOR_RED)); return; } // create file name SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd_HHmmss"); final String fileName = String.format("screenshot_%s.%s", date.format(new Date()), OPTION_SCREENSHOT_FORMAT.getValueString().toLowerCase()); final File file = new File(screenshotDir, fileName); SoundController.playSound(SoundEffect.SHUTTER); // copy the screen to file final int width = Display.getWidth(); final int height = Display.getHeight(); final int bpp = 3; // assuming a 32-bit display with a byte each for red, green, blue, and alpha final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); GL11.glReadBuffer(GL11.GL_FRONT); GL11.glPixelStorei(GL11.GL_PACK_ALIGNMENT, 1); GL11.glReadPixels(0, 0, width, height, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, buffer); new Thread() { @Override public void run() { try { BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int i = (x + (width * y)) * bpp; int r = buffer.get(i) & 0xFF; int g = buffer.get(i + 1) & 0xFF; int b = buffer.get(i + 2) & 0xFF; image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); } } ImageIO.write(image, OPTION_SCREENSHOT_FORMAT.getValueString().toLowerCase(), file); EventBus.post(new BubbleNotificationEvent("Created " + fileName, BubbleNotificationEvent.COMMONCOLOR_PURPLE)); } catch (Exception e) { ErrorHandler.error("Failed to take a screenshot.", e).show(); } } }.start(); } }