mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-07-20 22:00:48 +00:00
d
d
This commit is contained in:
@@ -2,6 +2,7 @@ package art.arcane.iris.core.safeguard;
|
||||
|
||||
import art.arcane.iris.BuildConstants;
|
||||
import art.arcane.iris.core.IrisSettings;
|
||||
import art.arcane.iris.core.splash.IrisSplashRenderer;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.util.common.format.C;
|
||||
@@ -11,21 +12,12 @@ import org.bukkit.Bukkit;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public enum Mode {
|
||||
STABLE(C.IRIS, C.AQUA),
|
||||
WARNING(C.GOLD, C.YELLOW),
|
||||
UNSTABLE(C.RED, C.GOLD);
|
||||
|
||||
private static final int SPLASH_WIDTH = 53;
|
||||
private static final int SPLASH_HEIGHT = 11;
|
||||
private static final double SPLASH_CENTER_X = 26.0;
|
||||
private static final double SPLASH_CENTER_Y = 5.0;
|
||||
private static final double SPLASH_ASPECT = 2.15;
|
||||
private static final double SPLASH_EYE_A = 5.6;
|
||||
private static final double SPLASH_EYE_B = 4.6;
|
||||
|
||||
private final C color;
|
||||
private final C glow;
|
||||
private final String id;
|
||||
@@ -70,7 +62,7 @@ public enum Mode {
|
||||
String startupDate = getStartupDate();
|
||||
int javaVersion = getJavaVersion();
|
||||
|
||||
String[] splash = renderSplashLogo();
|
||||
String[] splash = IrisSplashRenderer.render(this::splashTone);
|
||||
|
||||
String[] info = new String[]{
|
||||
"",
|
||||
@@ -94,38 +86,6 @@ public enum Mode {
|
||||
IrisLogging.info(builder.toString());
|
||||
}
|
||||
|
||||
private String[] renderSplashLogo() {
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
double headThickness = 3.7 + random.nextDouble() * 0.6;
|
||||
double tipReach = 19.0 + random.nextDouble() * 4.0;
|
||||
double notchX = 3.5 + random.nextDouble() * 1.5;
|
||||
double[][][] spines = splashFinSpines(tipReach);
|
||||
double[][][] voids = splashNotchVoids(notchX);
|
||||
String[] lines = new String[SPLASH_HEIGHT];
|
||||
for (int y = 0; y < SPLASH_HEIGHT; y++) {
|
||||
StringBuilder line = new StringBuilder();
|
||||
String activeTone = null;
|
||||
for (int x = 0; x < SPLASH_WIDTH; x++) {
|
||||
char glyph = splashEyeGlyph(x, y);
|
||||
if (glyph == 0) {
|
||||
glyph = splashFinGlyph(x, y, spines, voids, headThickness);
|
||||
}
|
||||
if (glyph == 0 || glyph == ' ') {
|
||||
line.append(' ');
|
||||
continue;
|
||||
}
|
||||
String tone = splashTone(glyph);
|
||||
if (!tone.equals(activeTone)) {
|
||||
line.append(tone);
|
||||
activeTone = tone;
|
||||
}
|
||||
line.append(glyph);
|
||||
}
|
||||
lines[y] = line.toString();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
private String splashTone(char glyph) {
|
||||
return switch (glyph) {
|
||||
case '=' -> C.GRAY.toString();
|
||||
@@ -136,129 +96,6 @@ public enum Mode {
|
||||
};
|
||||
}
|
||||
|
||||
private char splashEyeGlyph(int x, int y) {
|
||||
if (y == 5 && Math.abs(x - 26) <= 1) {
|
||||
if (x == 25) {
|
||||
return '(';
|
||||
}
|
||||
if (x == 27) {
|
||||
return ')';
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
double radius = splashEyeRadius(x, y);
|
||||
if (radius <= 0.50) {
|
||||
return '@';
|
||||
}
|
||||
if (radius <= 0.72) {
|
||||
return '%';
|
||||
}
|
||||
if (radius <= 0.88) {
|
||||
return '*';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private char splashFinGlyph(int x, int y, double[][][] spines, double[][][] voids, double headThickness) {
|
||||
if (splashEyeRadius(x, y) <= 1.26) {
|
||||
return 0;
|
||||
}
|
||||
double voidDistance = Double.MAX_VALUE;
|
||||
for (double[][] notch : voids) {
|
||||
for (double[] sample : notch) {
|
||||
double voidRadius = Math.max(0.25, 0.95 - 0.65 * sample[2]);
|
||||
double dx = (x - sample[0]) / SPLASH_ASPECT;
|
||||
double dy = y - sample[1];
|
||||
double distance = Math.sqrt(dx * dx + dy * dy) / voidRadius;
|
||||
if (distance < voidDistance) {
|
||||
voidDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (voidDistance < 1.0) {
|
||||
return 0;
|
||||
}
|
||||
double best = Double.MAX_VALUE;
|
||||
double bestT = 0.0;
|
||||
for (double[][] spine : spines) {
|
||||
for (int i = 0; i < spine.length; i++) {
|
||||
double t = i / (double) (spine.length - 1);
|
||||
double thickness = headThickness * Math.pow(1.0 - t, 1.3) + 0.6;
|
||||
double dx = (x - spine[i][0]) / SPLASH_ASPECT;
|
||||
double dy = y - spine[i][1];
|
||||
double distance = Math.sqrt(dx * dx + dy * dy) / thickness;
|
||||
if (distance < best) {
|
||||
best = distance;
|
||||
bestT = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
double shade = best
|
||||
+ Math.max(0.0, 3.0 - Math.min(x, SPLASH_WIDTH - 1 - x)) * 0.12
|
||||
+ Math.max(0.0, 0.10 - bestT) * 1.5
|
||||
+ Math.max(0.0, 1.30 - voidDistance) * 0.15;
|
||||
if (shade > 1.0) {
|
||||
return 0;
|
||||
}
|
||||
int level = shade <= 0.70 ? 0 : shade <= 0.90 ? 1 : 2;
|
||||
if (bestT > 0.97) {
|
||||
level += 2;
|
||||
} else if (bestT > 0.88) {
|
||||
level += 1;
|
||||
}
|
||||
return switch (Math.min(level, 2)) {
|
||||
case 0 -> '#';
|
||||
case 1 -> '=';
|
||||
default -> '-';
|
||||
};
|
||||
}
|
||||
|
||||
private double splashEyeRadius(int x, int y) {
|
||||
double dx = (x - SPLASH_CENTER_X) / SPLASH_ASPECT;
|
||||
double dy = y - SPLASH_CENTER_Y;
|
||||
double nx = dx / SPLASH_EYE_A;
|
||||
double ny = dy / SPLASH_EYE_B;
|
||||
return Math.sqrt(nx * nx + ny * ny);
|
||||
}
|
||||
|
||||
private double[][][] splashNotchVoids(double notchX) {
|
||||
double[][] control = {{notchX + 0.8, 12.0}, {notchX, 9.6}, {notchX - 1.4, 7.8}};
|
||||
int samples = 31;
|
||||
double[][] left = new double[samples][3];
|
||||
double[][] right = new double[samples][3];
|
||||
for (int i = 0; i < samples; i++) {
|
||||
double t = i / (double) (samples - 1);
|
||||
double u = 1.0 - t;
|
||||
double bx = u * u * control[0][0] + 2.0 * u * t * control[1][0] + t * t * control[2][0];
|
||||
double by = u * u * control[0][1] + 2.0 * u * t * control[1][1] + t * t * control[2][1];
|
||||
left[i][0] = bx;
|
||||
left[i][1] = by;
|
||||
left[i][2] = t;
|
||||
right[i][0] = (SPLASH_WIDTH - 1.0) - bx;
|
||||
right[i][1] = (SPLASH_HEIGHT - 1.0) - by;
|
||||
right[i][2] = t;
|
||||
}
|
||||
return new double[][][]{left, right};
|
||||
}
|
||||
|
||||
private double[][][] splashFinSpines(double tipReach) {
|
||||
double[][] control = {{-1.5, 9.8}, {0.4, 4.4}, {5.2, 1.0}, {tipReach, 0.4}};
|
||||
int samples = 61;
|
||||
double[][] left = new double[samples][2];
|
||||
double[][] right = new double[samples][2];
|
||||
for (int i = 0; i < samples; i++) {
|
||||
double t = i / (double) (samples - 1);
|
||||
double u = 1.0 - t;
|
||||
double bx = u * u * u * control[0][0] + 3.0 * u * u * t * control[1][0] + 3.0 * u * t * t * control[2][0] + t * t * t * control[3][0];
|
||||
double by = u * u * u * control[0][1] + 3.0 * u * u * t * control[1][1] + 3.0 * u * t * t * control[2][1] + t * t * t * control[3][1];
|
||||
left[i][0] = bx;
|
||||
left[i][1] = by;
|
||||
right[i][0] = (SPLASH_WIDTH - 1.0) - bx;
|
||||
right[i][1] = (SPLASH_HEIGHT - 1.0) - by;
|
||||
}
|
||||
return new double[][][]{left, right};
|
||||
}
|
||||
|
||||
private String wrap(String tag) {
|
||||
return C.BOLD.toString() + C.DARK_GRAY + "[" + C.BOLD + color + tag + C.BOLD + C.DARK_GRAY + "]" + C.RESET;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package art.arcane.iris.core.splash;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public final class IrisSplashPackScanner {
|
||||
private IrisSplashPackScanner() {
|
||||
}
|
||||
|
||||
public static List<SplashPackMetadata> collect(File packFolder, SplashPackErrorReporter reporter) {
|
||||
if (packFolder == null || !packFolder.isDirectory()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
File[] folders = packFolder.listFiles(File::isDirectory);
|
||||
if (folders == null || folders.length == 0) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<SplashPackMetadata> packs = new ArrayList<>(folders.length);
|
||||
for (File folder : folders) {
|
||||
SplashPackMetadata metadata = read(folder, reporter);
|
||||
if (metadata != null) {
|
||||
packs.add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
packs.sort(Comparator.comparing(SplashPackMetadata::name));
|
||||
return packs;
|
||||
}
|
||||
|
||||
public static SplashPackMetadata read(File pack, SplashPackErrorReporter reporter) {
|
||||
if (pack == null || !pack.isDirectory()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String dimName = pack.getName();
|
||||
File dimensionFile = new File(pack, "dimensions/" + dimName + ".json");
|
||||
if (!dimensionFile.isFile()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try (FileReader reader = new FileReader(dimensionFile)) {
|
||||
JsonObject json = JsonParser.parseReader(reader).getAsJsonObject();
|
||||
if (!json.has("version")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SplashPackMetadata(dimName, json.get("version").getAsString());
|
||||
} catch (IOException | JsonParseException | IllegalStateException error) {
|
||||
report(reporter, "Failed to read splash metadata for dimension pack \"" + dimName + "\".", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void report(SplashPackErrorReporter reporter, String message, Throwable error) {
|
||||
if (reporter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
reporter.report(message, error);
|
||||
}
|
||||
|
||||
public record SplashPackMetadata(String name, String version) {
|
||||
}
|
||||
|
||||
public interface SplashPackErrorReporter {
|
||||
void report(String message, Throwable error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package art.arcane.iris.core.splash;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public final class IrisSplashRenderer {
|
||||
private static final int SPLASH_WIDTH = 53;
|
||||
private static final int SPLASH_HEIGHT = 11;
|
||||
private static final double SPLASH_CENTER_X = 26.0;
|
||||
private static final double SPLASH_CENTER_Y = 5.0;
|
||||
private static final double SPLASH_ASPECT = 2.15;
|
||||
private static final double SPLASH_EYE_A = 5.6;
|
||||
private static final double SPLASH_EYE_B = 4.6;
|
||||
private static final SplashTone PLAIN_TONE = (glyph) -> "";
|
||||
|
||||
private IrisSplashRenderer() {
|
||||
}
|
||||
|
||||
public static String[] renderPlain() {
|
||||
return render(PLAIN_TONE);
|
||||
}
|
||||
|
||||
public static String[] render(SplashTone tone) {
|
||||
SplashTone splashTone = tone == null ? PLAIN_TONE : tone;
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
double headThickness = 3.7 + random.nextDouble() * 0.6;
|
||||
double tipReach = 19.0 + random.nextDouble() * 4.0;
|
||||
double notchX = 3.5 + random.nextDouble() * 1.5;
|
||||
double[][][] spines = splashFinSpines(tipReach);
|
||||
double[][][] voids = splashNotchVoids(notchX);
|
||||
String[] lines = new String[SPLASH_HEIGHT];
|
||||
for (int y = 0; y < SPLASH_HEIGHT; y++) {
|
||||
StringBuilder line = new StringBuilder();
|
||||
String activeTone = null;
|
||||
for (int x = 0; x < SPLASH_WIDTH; x++) {
|
||||
char glyph = splashEyeGlyph(x, y);
|
||||
if (glyph == 0) {
|
||||
glyph = splashFinGlyph(x, y, spines, voids, headThickness);
|
||||
}
|
||||
if (glyph == 0 || glyph == ' ') {
|
||||
line.append(' ');
|
||||
continue;
|
||||
}
|
||||
String glyphTone = splashTone.tone(glyph);
|
||||
if (!glyphTone.isEmpty() && !glyphTone.equals(activeTone)) {
|
||||
line.append(glyphTone);
|
||||
activeTone = glyphTone;
|
||||
}
|
||||
line.append(glyph);
|
||||
}
|
||||
lines[y] = line.toString();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
private static char splashEyeGlyph(int x, int y) {
|
||||
if (y == 5 && Math.abs(x - 26) <= 1) {
|
||||
if (x == 25) {
|
||||
return '(';
|
||||
}
|
||||
if (x == 27) {
|
||||
return ')';
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
double radius = splashEyeRadius(x, y);
|
||||
if (radius <= 0.50) {
|
||||
return '@';
|
||||
}
|
||||
if (radius <= 0.72) {
|
||||
return '%';
|
||||
}
|
||||
if (radius <= 0.88) {
|
||||
return '*';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static char splashFinGlyph(int x, int y, double[][][] spines, double[][][] voids, double headThickness) {
|
||||
if (splashEyeRadius(x, y) <= 1.26) {
|
||||
return 0;
|
||||
}
|
||||
double voidDistance = Double.MAX_VALUE;
|
||||
for (double[][] notch : voids) {
|
||||
for (double[] sample : notch) {
|
||||
double voidRadius = Math.max(0.25, 0.95 - 0.65 * sample[2]);
|
||||
double dx = (x - sample[0]) / SPLASH_ASPECT;
|
||||
double dy = y - sample[1];
|
||||
double distance = Math.sqrt(dx * dx + dy * dy) / voidRadius;
|
||||
if (distance < voidDistance) {
|
||||
voidDistance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (voidDistance < 1.0) {
|
||||
return 0;
|
||||
}
|
||||
double best = Double.MAX_VALUE;
|
||||
double bestT = 0.0;
|
||||
for (double[][] spine : spines) {
|
||||
for (int i = 0; i < spine.length; i++) {
|
||||
double t = i / (double) (spine.length - 1);
|
||||
double thickness = headThickness * Math.pow(1.0 - t, 1.3) + 0.6;
|
||||
double dx = (x - spine[i][0]) / SPLASH_ASPECT;
|
||||
double dy = y - spine[i][1];
|
||||
double distance = Math.sqrt(dx * dx + dy * dy) / thickness;
|
||||
if (distance < best) {
|
||||
best = distance;
|
||||
bestT = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
double shade = best
|
||||
+ Math.max(0.0, 3.0 - Math.min(x, SPLASH_WIDTH - 1 - x)) * 0.12
|
||||
+ Math.max(0.0, 0.10 - bestT) * 1.5
|
||||
+ Math.max(0.0, 1.30 - voidDistance) * 0.15;
|
||||
if (shade > 1.0) {
|
||||
return 0;
|
||||
}
|
||||
int level = shade <= 0.70 ? 0 : shade <= 0.90 ? 1 : 2;
|
||||
if (bestT > 0.97) {
|
||||
level += 2;
|
||||
} else if (bestT > 0.88) {
|
||||
level += 1;
|
||||
}
|
||||
return switch (Math.min(level, 2)) {
|
||||
case 0 -> '#';
|
||||
case 1 -> '=';
|
||||
default -> '-';
|
||||
};
|
||||
}
|
||||
|
||||
private static double splashEyeRadius(int x, int y) {
|
||||
double dx = (x - SPLASH_CENTER_X) / SPLASH_ASPECT;
|
||||
double dy = y - SPLASH_CENTER_Y;
|
||||
double nx = dx / SPLASH_EYE_A;
|
||||
double ny = dy / SPLASH_EYE_B;
|
||||
return Math.sqrt(nx * nx + ny * ny);
|
||||
}
|
||||
|
||||
private static double[][][] splashNotchVoids(double notchX) {
|
||||
double[][] control = {{notchX + 0.8, 12.0}, {notchX, 9.6}, {notchX - 1.4, 7.8}};
|
||||
int samples = 31;
|
||||
double[][] left = new double[samples][3];
|
||||
double[][] right = new double[samples][3];
|
||||
for (int i = 0; i < samples; i++) {
|
||||
double t = i / (double) (samples - 1);
|
||||
double u = 1.0 - t;
|
||||
double bx = u * u * control[0][0] + 2.0 * u * t * control[1][0] + t * t * control[2][0];
|
||||
double by = u * u * control[0][1] + 2.0 * u * t * control[1][1] + t * t * control[2][1];
|
||||
left[i][0] = bx;
|
||||
left[i][1] = by;
|
||||
left[i][2] = t;
|
||||
right[i][0] = (SPLASH_WIDTH - 1.0) - bx;
|
||||
right[i][1] = (SPLASH_HEIGHT - 1.0) - by;
|
||||
right[i][2] = t;
|
||||
}
|
||||
return new double[][][]{left, right};
|
||||
}
|
||||
|
||||
private static double[][][] splashFinSpines(double tipReach) {
|
||||
double[][] control = {{-1.5, 9.8}, {0.4, 4.4}, {5.2, 1.0}, {tipReach, 0.4}};
|
||||
int samples = 61;
|
||||
double[][] left = new double[samples][2];
|
||||
double[][] right = new double[samples][2];
|
||||
for (int i = 0; i < samples; i++) {
|
||||
double t = i / (double) (samples - 1);
|
||||
double u = 1.0 - t;
|
||||
double bx = u * u * u * control[0][0] + 3.0 * u * u * t * control[1][0] + 3.0 * u * t * t * control[2][0] + t * t * t * control[3][0];
|
||||
double by = u * u * u * control[0][1] + 3.0 * u * u * t * control[1][1] + 3.0 * u * t * t * control[2][1] + t * t * t * control[3][1];
|
||||
left[i][0] = bx;
|
||||
left[i][1] = by;
|
||||
right[i][0] = (SPLASH_WIDTH - 1.0) - bx;
|
||||
right[i][1] = (SPLASH_HEIGHT - 1.0) - by;
|
||||
}
|
||||
return new double[][][]{left, right};
|
||||
}
|
||||
|
||||
public interface SplashTone {
|
||||
String tone(char glyph);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user