diff --git a/build.gradle b/build.gradle index 7244c66e81..1e407527ca 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,6 @@ plugins { } repositories { - mavenLocal() maven { url = 'https://repo.runelite.net' } @@ -36,6 +35,11 @@ tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } +tasks.register('generateBuildInfo', GenerateBuildInfoTask); + +sourceSets.main.java.srcDir("$buildDir/generated/sources/buildinfo") +compileJava.dependsOn(generateBuildInfo) + //import groovy.json.JsonOutput // //import java.lang.reflect.Modifier diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 0000000000..975a502500 --- /dev/null +++ b/buildSrc/build.gradle @@ -0,0 +1,7 @@ +plugins { + id 'java' +} + +repositories { + mavenCentral() +} \ No newline at end of file diff --git a/buildSrc/src/main/java/GenerateBuildInfoTask.java b/buildSrc/src/main/java/GenerateBuildInfoTask.java new file mode 100644 index 0000000000..14ea2dddae --- /dev/null +++ b/buildSrc/src/main/java/GenerateBuildInfoTask.java @@ -0,0 +1,82 @@ +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.time.Instant; +import javax.inject.Inject; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.logging.Logger; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.TaskAction; + +public abstract class GenerateBuildInfoTask extends DefaultTask { + private static final String BUILD_INFO_CLASS_PATH = "rs117/hd/BuildInfo.java"; + private static final String BUILD_INFO_SRC = """ + package rs117.hd; + + public final class BuildInfo { + + public static final String VERSION = "%s"; + public static final String TIMESTAMP = "%s"; + public static final String BRANCH = "%s"; + public static final String COMMIT_HASH = "%s"; + public static final String ORIGIN = "%s"; + + private BuildInfo() {} + } + """; + + @Inject + public GenerateBuildInfoTask() { + getOutputDir().convention( + getProject() + .getLayout() + .getBuildDirectory() + .dir("generated/sources/buildinfo") + ); + } + + @OutputDirectory + public abstract DirectoryProperty getOutputDir(); + + @TaskAction + public void generate() throws IOException { + final Logger log = getLogger(); + + String[] gitBranchAndCommit = { "unknown", "unknown" }; + String origin = "unknown"; + try { + File gitDir = new File(getProject().getRootDir(), ".git"); + + gitBranchAndCommit = GitUtils.getGitBranchAndCommit(gitDir); + origin = GitUtils.getGitOrigin(gitDir); + } catch (IOException e) { + log.warn("Failed to read git info", e); + } + + File outputFile = new File(getOutputDir().get().getAsFile(), BUILD_INFO_CLASS_PATH); + File outputDir = outputFile.getParentFile(); + if(outputDir != null && !outputDir.exists()) { + log.info("Created directory: {}", outputDir.getAbsolutePath()); + outputDir.mkdirs(); + } + + String timestamp = Instant.now().toString(); + String content = BUILD_INFO_SRC + .formatted( + getProject().getVersion().toString(), + timestamp, + gitBranchAndCommit[0], + gitBranchAndCommit[1], + origin + ); + Files.writeString(outputFile.toPath(), content); + + log.info("Generated {}", BUILD_INFO_CLASS_PATH); + log.info(" * Version: {}", getProject().getVersion()); + log.info(" * Timestamp: {}", timestamp); + log.info(" * Branch: {}", gitBranchAndCommit[0]); + log.info(" * Commit: {}", gitBranchAndCommit[1]); + log.info(" * Origin: {}", origin); + } +} \ No newline at end of file diff --git a/buildSrc/src/main/java/GitUtils.java b/buildSrc/src/main/java/GitUtils.java new file mode 100644 index 0000000000..5e92d62dbf --- /dev/null +++ b/buildSrc/src/main/java/GitUtils.java @@ -0,0 +1,61 @@ +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GitUtils { + public static String[] getGitBranchAndCommit(File gitDir) throws IOException { + File headFile = new File(gitDir, "HEAD"); + if (!headFile.exists()) + return new String[] { "unknown", "unknown" }; + + String head = Files.readString(headFile.toPath()).trim(); + + if (head.startsWith("ref: ")) { + String refPath = head.substring(5); + String branch = refPath.substring(refPath.lastIndexOf('/') + 1); + String commit = readCommitFromRef(gitDir, refPath); + + return new String[] { branch, commit }; + } + + return new String[] { "detached", shortHash(head) }; + } + + public static String readCommitFromRef(File gitDir, String refPath) throws IOException { + File refFile = new File(gitDir, refPath); + if (refFile.exists()) + return shortHash(Files.readString(refFile.toPath()).trim()); + + File packedRefs = new File(gitDir, "packed-refs"); + + if (packedRefs.exists()) { + List lines = Files.readAllLines(packedRefs.toPath()); + + for (String line : lines) + if (!line.startsWith("#") && line.endsWith(refPath)) + return shortHash(line.split(" ")[0]); + } + + return "unknown"; + } + + public static String getGitOrigin(File gitDir) throws IOException { + File config = new File(gitDir, "config"); + if (!config.exists()) + return "unknown"; + + String text = Files.readString(config.toPath()); + Pattern pattern = Pattern.compile("\\[remote\\s+\"origin\"]([\\s\\S]*?)url\\s*=\\s*(.+)"); + Matcher matcher = pattern.matcher(text); + + if (matcher.find()) + return matcher.group(2).trim(); + + return "unknown"; + } + + public static String shortHash(String hash) { return hash.length() > 7 ? hash.substring(0, 7) : hash; } +} diff --git a/src/main/java/rs117/hd/HdPlugin.java b/src/main/java/rs117/hd/HdPlugin.java index 5a14d117b0..7161803243 100644 --- a/src/main/java/rs117/hd/HdPlugin.java +++ b/src/main/java/rs117/hd/HdPlugin.java @@ -132,7 +132,11 @@ import static net.runelite.api.Constants.*; import static org.lwjgl.opengl.GL33C.*; +import static org.lwjgl.opengl.NVXGPUMemoryInfo.GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX; import static rs117.hd.HdPluginConfig.*; +import static rs117.hd.utils.HDUtils.getCPUName; +import static rs117.hd.utils.HDUtils.getTotalPhysicalMemorySize; +import static rs117.hd.utils.HDUtils.humanReadableByteCountBin; import static rs117.hd.utils.MathUtils.*; import static rs117.hd.utils.ResourcePath.path; import static rs117.hd.utils.buffer.GLBuffer.MAP_WRITE; @@ -460,6 +464,7 @@ public class HdPlugin extends Plugin { @Getter public long garbageCollectionCount; + private int startupCount; public int frame; public double elapsedTime; public double elapsedClientTime; @@ -507,6 +512,7 @@ protected void startUp() { return false; isActive = true; + startupCount++; fboScene = 0; rboSceneColor = 0; @@ -547,20 +553,33 @@ protected void startUp() { GL_CAPS = GL.createCapabilities(); useLowMemoryMode = config.lowMemoryMode(); BUFFER_GROWTH_MULTIPLIER = useLowMemoryMode ? 1.333f : 2; - + + long startupTimeStamp = System.currentTimeMillis(); OSType osType = OSType.getOSType(); String arch = System.getProperty("os.arch", "Unknown"); String wordSize = System.getProperty("sun.arch.data.model", "Unknown"); - log.info("Operating system: {}", osType); - log.info("Architecture: {}", arch); - log.info("Client is {}-bit", wordSize); - APPLE = osType == OSType.MacOS; - APPLE_ARM = APPLE && arch.equals("aarch64"); - String glRenderer = Objects.requireNonNullElse(glGetString(GL_RENDERER), "Unknown"); String glVendor = Objects.requireNonNullElse(glGetString(GL_VENDOR), "Unknown"); - log.info("Using device: {} ({})", glRenderer, glVendor); - log.info("Using driver: {}", glGetString(GL_VERSION)); + String rlawt = Objects.requireNonNullElse(System.getProperty("runelite.rlawtpath"), "Release"); + + log.info("Starting RLHD (Launch Count: {})...", startupCount); + log.info("Build Version : {} - {} - {}", BuildInfo.VERSION, BuildInfo.COMMIT_HASH, BuildInfo.TIMESTAMP); + log.info("Build Repo : {} ({})", BuildInfo.ORIGIN, BuildInfo.BRANCH); + log.info("rlawt : {}", rlawt); + log.info("Operating system: {} {} ({}-bit)", osType, System.getProperty("os.version"), wordSize); + log.info("Architecture : {}", arch); + log.info("System CPU : {}", getCPUName()); + log.info("System Threads : {}", Runtime.getRuntime().availableProcessors()); + log.info("System Memory : {}", humanReadableByteCountBin(getTotalPhysicalMemorySize())); + log.info("Device : {} ({})", glRenderer, glVendor); + log.info("Device Driver : {}", glGetString(GL_VERSION)); + if (GL_CAPS.GL_NVX_gpu_memory_info) + log.info("Device Memory : {}", humanReadableByteCountBin(glGetInteger(GL_GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX) * 1024L)); + log.info("Java : {} ({})", System.getProperty("java.vm.name"), System.getProperty("java.version")); + log.info("Java Max Memory : {} (Avail: {})", humanReadableByteCountBin(Runtime.getRuntime().maxMemory()), humanReadableByteCountBin(Runtime.getRuntime().freeMemory())); + + APPLE = osType == OSType.MacOS; + APPLE_ARM = APPLE && arch.equals("aarch64"); AMD_GPU = glRenderer.contains("AMD") || glRenderer.contains("Radeon") || glVendor.contains("ATI"); INTEL_GPU = glRenderer.contains("Intel"); NVIDIA_GPU = glRenderer.toLowerCase().contains("nvidia"); @@ -570,9 +589,8 @@ protected void startUp() { renderer = config.legacyRenderer() ? injector.getInstance(LegacyRenderer.class) : injector.getInstance(ZoneRenderer.class); - log.info("Using renderer: {}", renderer.getClass().getSimpleName()); - - log.info("Low memory mode: {}", useLowMemoryMode); + log.info("Using renderer : {}", renderer.getClass().getSimpleName()); + log.info("Low memory mode : {}", useLowMemoryMode); if (!Props.has("rlhd.skipGpuChecks")) { List fallbackDevices = List.of( @@ -707,6 +725,8 @@ protected void startUp() { checkGLErrors(); clientThread.invokeLater(this::displayUpdateMessage); + + log.info("RLHD Finished Startup! Took {} ms", System.currentTimeMillis() - startupTimeStamp); } catch (Throwable err) { log.error("Error while starting 117 HD", err); stopPlugin(); diff --git a/src/main/java/rs117/hd/utils/HDUtils.java b/src/main/java/rs117/hd/utils/HDUtils.java index 0d9b1da7fe..3902fe0106 100644 --- a/src/main/java/rs117/hd/utils/HDUtils.java +++ b/src/main/java/rs117/hd/utils/HDUtils.java @@ -27,11 +27,16 @@ import java.awt.Canvas; import java.awt.Container; import java.awt.Frame; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Objects; import javax.annotation.Nullable; import javax.inject.Singleton; import javax.swing.JFrame; import lombok.extern.slf4j.Slf4j; import net.runelite.api.*; +import net.runelite.client.util.OSType; import rs117.hd.data.ObjectType; import rs117.hd.scene.areas.AABB; import rs117.hd.scene.areas.Area; @@ -48,6 +53,7 @@ @Slf4j @Singleton public final class HDUtils { + private static final String[] UNITS = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"}; public static final int HIDDEN_HSL = 12345678; public static final int UNDERWATER_HSL = 6676; @@ -508,4 +514,39 @@ public static JFrame getJFrame(Canvas canvas) { return null; } + + public static String humanReadableByteCountBin(long bytes) { + if (bytes == Long.MIN_VALUE) + bytes = Long.MAX_VALUE; + + double value = Math.abs((double) bytes); + int unitIndex = 0; + + while (value >= 1024 && unitIndex < UNITS.length - 1) { + value /= 1024; + unitIndex++; + } + + value = Math.copySign(value, bytes); + + return String.format("%.1f %s", value, UNITS[unitIndex]); + } + + public static String getCPUName() { + if(OSType.getOSType() == OSType.Linux) { + try (BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"))) { + String line; + while ((line = br.readLine()) != null) { + if (line.startsWith("model name")) + return line.split(":", 2)[1].trim(); + } + } catch (IOException ignored) {} + } + + return Objects.requireNonNullElse(System.getenv("PROCESSOR_IDENTIFIER"), "Unknown"); + } + + public static long getTotalPhysicalMemorySize() { + return ((com.sun.management.OperatingSystemMXBean) java.lang.management.ManagementFactory.getOperatingSystemMXBean()).getTotalPhysicalMemorySize(); + } }