You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
style(startup): add adaptive console colors
Add an auto-detected styled startup splash for terminals that support ANSI colors, including Windows Terminal, ANSICON, ConEmu ANSI, and common TERM-based consoles. Keep the default and redirected-output path plain text so legacy CMD, logs, and service wrappers remain readable. The style can also be forced with -Dhabbo.console.style=ansi or disabled with -Dhabbo.console.style=plain. Cover the styled splash, Windows Terminal detection, non-interactive fallback, and forced plain mode with startup console tests.
This commit is contained in:
@@ -38,6 +38,12 @@ public final class Emulator {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(Emulator.class);
|
||||
private static final String OS_NAME = (System.getProperty("os.name") != null ? System.getProperty("os.name") : "Unknown");
|
||||
private static final String CLASS_PATH = (System.getProperty("java.class.path") != null ? System.getProperty("java.class.path") : "Unknown");
|
||||
private static final String ANSI_RESET = "\u001B[0m";
|
||||
private static final String ANSI_BOLD = "\u001B[1m";
|
||||
private static final String ANSI_CYAN = "\u001B[36m";
|
||||
private static final String ANSI_GREEN = "\u001B[32m";
|
||||
private static final String ANSI_YELLOW = "\u001B[33m";
|
||||
private static final String ANSI_DIM = "\u001B[2m";
|
||||
|
||||
// Fallback version, only used when running outside a packaged jar (e.g. from
|
||||
// the IDE). In production the version comes from the jar manifest below.
|
||||
@@ -118,7 +124,11 @@ public final class Emulator {
|
||||
ConsoleCommand.load();
|
||||
Emulator.logging = new Logging();
|
||||
|
||||
System.out.println(startupHero());
|
||||
System.out.println(startupHero(shouldStyleConsole(
|
||||
System.getenv(),
|
||||
System.console() != null,
|
||||
OS_NAME,
|
||||
System.getProperty("habbo.console.style", "auto"))));
|
||||
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
@@ -316,6 +326,30 @@ public final class Emulator {
|
||||
}
|
||||
|
||||
static String startupHero() {
|
||||
return startupHero(false);
|
||||
}
|
||||
|
||||
static String startupHero(boolean styled) {
|
||||
if (styled) {
|
||||
return "\n" +
|
||||
ANSI_CYAN +
|
||||
" __ __ ___ ____ _ _ ___ _ _ ____ ____ _____ _ ____ \n" +
|
||||
" | \\/ |/ _ \\| _ \\| \\ | |_ _| \\ | |/ ___/ ___|_ _|/ \\ | _ \\ \n" +
|
||||
" | |\\/| | | | | |_) | \\| || || \\| | | _\\___ \\ | | / _ \\ | |_) |\n" +
|
||||
" | | | | |_| | _ <| |\\ || || |\\ | |_| |___) || |/ ___ \\| _ < \n" +
|
||||
" |_| |_|\\___/|_| \\_\\_| \\_|___|_| \\_|\\____|____/ |_/_/ \\_\\_| \\_\\\n" +
|
||||
ANSI_RESET +
|
||||
"\n" +
|
||||
ANSI_DIM + "+------------------------------------------------------------------------------+" + ANSI_RESET + "\n" +
|
||||
"| " + ANSI_BOLD + ANSI_GREEN + "[OK] MORNINGSTAR EXTENDED" + ANSI_RESET + fit("", 50) + " |\n" +
|
||||
"| " + ANSI_DIM + "Arcturus game server runtime" + ANSI_RESET + fit("", 48) + " |\n" +
|
||||
ANSI_DIM + "+------------------------------------------------------------------------------+" + ANSI_RESET + "\n" +
|
||||
"| " + ANSI_YELLOW + "[VER]" + ANSI_RESET + " Version : " + fit(version, 57) + " |\n" +
|
||||
"| " + ANSI_YELLOW + "[BLD]" + ANSI_RESET + " Build : " + fit(build.isBlank() ? "UNKNOWN" : build, 57) + " |\n" +
|
||||
"| " + ANSI_YELLOW + "[JVM]" + ANSI_RESET + " Runtime : " + fit("Java " + System.getProperty("java.version", "unknown") + " / styled console output", 57) + " |\n" +
|
||||
ANSI_DIM + "+------------------------------------------------------------------------------+" + ANSI_RESET + "\n";
|
||||
}
|
||||
|
||||
return "\n" +
|
||||
" __ __ ___ ____ _ _ ___ _ _ ____ ____ _____ _ ____ \n" +
|
||||
" | \\/ |/ _ \\| _ \\| \\ | |_ _| \\ | |/ ___/ ___|_ _|/ \\ | _ \\ \n" +
|
||||
@@ -333,6 +367,37 @@ public final class Emulator {
|
||||
"+------------------------------------------------------------------------------+\n";
|
||||
}
|
||||
|
||||
static boolean shouldStyleConsole(Map<String, String> environment, boolean interactiveConsole, String osName, String styleProperty) {
|
||||
String style = styleProperty == null ? "auto" : styleProperty.trim().toLowerCase(Locale.ROOT);
|
||||
if (style.equals("ansi") || style.equals("color") || style.equals("colours") || style.equals("colors")) {
|
||||
return true;
|
||||
}
|
||||
if (style.equals("plain") || style.equals("none") || style.equals("false") || style.equals("off")) {
|
||||
return false;
|
||||
}
|
||||
if (!interactiveConsole) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, String> env = environment == null ? Collections.emptyMap() : environment;
|
||||
if (env.containsKey("NO_COLOR")) {
|
||||
return false;
|
||||
}
|
||||
if (env.containsKey("WT_SESSION") || env.containsKey("ANSICON") || "ON".equalsIgnoreCase(env.get("ConEmuANSI"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String term = env.getOrDefault("TERM", "");
|
||||
if (term.equalsIgnoreCase("dumb")) {
|
||||
return false;
|
||||
}
|
||||
if (!term.isBlank() && (term.contains("xterm") || term.contains("ansi") || term.contains("screen") || term.contains("tmux"))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return osName == null || !osName.toLowerCase(Locale.ROOT).startsWith("windows");
|
||||
}
|
||||
|
||||
private static String fit(String value, int width) {
|
||||
String safe = value == null ? "" : value;
|
||||
if (safe.length() > width) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.eu.habbo;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@@ -16,4 +18,41 @@ class EmulatorStartupConsoleTest {
|
||||
assertTrue(hero.contains("Build"));
|
||||
assertFalse(hero.contains("\u001B["), "startup hero must not require ANSI support");
|
||||
}
|
||||
|
||||
@Test
|
||||
void startupHeroCanRenderStyledLayoutWhenAnsiIsAvailable() {
|
||||
String hero = Emulator.startupHero(true);
|
||||
|
||||
assertTrue(hero.contains("\u001B["), "styled hero should include ANSI colors");
|
||||
assertTrue(hero.contains("[OK] MORNINGSTAR EXTENDED"));
|
||||
assertTrue(hero.contains("[JVM]"));
|
||||
assertTrue(hero.endsWith("\u001B[0m\n"), "styled hero should reset terminal attributes");
|
||||
}
|
||||
|
||||
@Test
|
||||
void consoleStyleAutoDetectsWindowsTerminal() {
|
||||
assertTrue(Emulator.shouldStyleConsole(
|
||||
Map.of("WT_SESSION", "abc123"),
|
||||
true,
|
||||
"Windows 11",
|
||||
"auto"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void consoleStyleFallsBackWhenOutputIsNotInteractive() {
|
||||
assertFalse(Emulator.shouldStyleConsole(
|
||||
Map.of("WT_SESSION", "abc123"),
|
||||
false,
|
||||
"Windows 11",
|
||||
"auto"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void consoleStyleCanBeForcedOff() {
|
||||
assertFalse(Emulator.shouldStyleConsole(
|
||||
Map.of("WT_SESSION", "abc123"),
|
||||
true,
|
||||
"Windows 11",
|
||||
"plain"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user