diff --git a/core/plugins/Iris/cache/instance b/core/plugins/Iris/cache/instance index 1d12b25fe..6a677cd79 100644 --- a/core/plugins/Iris/cache/instance +++ b/core/plugins/Iris/cache/instance @@ -1 +1 @@ -203609563 \ No newline at end of file +-1504154581 \ No newline at end of file diff --git a/core/src/main/java/art/arcane/iris/core/safeguard/Mode.java b/core/src/main/java/art/arcane/iris/core/safeguard/Mode.java index 6ef3e216f..f45474db1 100644 --- a/core/src/main/java/art/arcane/iris/core/safeguard/Mode.java +++ b/core/src/main/java/art/arcane/iris/core/safeguard/Mode.java @@ -10,17 +10,28 @@ 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), - WARNING(C.GOLD), - UNSTABLE(C.RED); + 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; - Mode(C color) { + Mode(C color, C glow) { this.color = color; + this.glow = glow; this.id = name().toLowerCase(Locale.ROOT); } @@ -58,19 +69,7 @@ public enum Mode { String startupDate = getStartupDate(); int javaVersion = getJavaVersion(); - String[] splash = new String[]{ - padd + C.GRAY + " @@@@@@@@@@@@@@" + C.DARK_GRAY + "@@@", - padd + C.GRAY + " @@&&&&&&&&&" + C.DARK_GRAY + "&&&&&&" + color + " .(((()))). ", - padd + C.GRAY + "@@@&&&&&&&&" + C.DARK_GRAY + "&&&&&" + color + " .((((((())))))). ", - padd + C.GRAY + "@@@&&&&&" + C.DARK_GRAY + "&&&&&&&" + color + " ((((((((())))))))) " + C.GRAY + " @", - padd + C.GRAY + "@@@&&&&" + C.DARK_GRAY + "@@@@@&" + color + " ((((((((-))))))))) " + C.GRAY + " @@", - padd + C.GRAY + "@@@&&" + color + " ((((((({ })))))))) " + C.GRAY + " &&@@@", - padd + C.GRAY + "@@" + color + " ((((((((-))))))))) " + C.DARK_GRAY + "&@@@@@" + C.GRAY + "&&&&@@@", - padd + C.GRAY + "@" + color + " ((((((((())))))))) " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&@@@", - padd + C.GRAY + "" + color + " '((((((()))))))' " + C.DARK_GRAY + "&&&&&" + C.GRAY + "&&&&&&&&@@@", - padd + C.GRAY + "" + color + " '(((())))' " + C.DARK_GRAY + "&&&&&&&&" + C.GRAY + "&&&&&&&@@", - padd + C.GRAY + " " + C.DARK_GRAY + "@@@" + C.GRAY + "@@@@@@@@@@@@@@" - }; + String[] splash = renderSplashLogo(); String[] info = new String[]{ "", @@ -88,14 +87,222 @@ public enum Mode { StringBuilder builder = new StringBuilder("\n\n"); for (int i = 0; i < splash.length; i++) { - builder.append(splash[i]); - builder.append(info[i]); - builder.append("\n"); + builder.append(padd).append(splash[i]).append(info[i]).append("\n"); } Iris.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 streamReach = 22.0 + random.nextDouble() * 3.0; + double[][][] spines = splashFinSpines(tipReach); + double[][][] voids = splashNotchVoids(notchX); + double[][][] streams = splashStreamSpines(notchX, streamReach); + 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, streams, 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(); + case '*' -> glow.toString(); + case '%', '@' -> color.toString(); + case '(', ')' -> C.WHITE.toString(); + default -> C.DARK_GRAY.toString(); + }; + } + + 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[][][] streams, 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; + double bestSpineY = 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; + bestSpineY = spine[i][1]; + } + } + } + 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) { + 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 -> '-'; + }; + } + if (bestT < 0.25 && Math.abs(bestSpineY - SPLASH_CENTER_Y) > 2.5 && shade <= 1.25) { + return '-'; + } + if (bestT > 0.88 && shade <= 1.45) { + return '-'; + } + double streamBest = Double.MAX_VALUE; + for (double[][] stream : streams) { + for (double[] sample : stream) { + double thickness = Math.max(0.4, 0.85 - 0.4 * sample[2]); + double dx = (x - sample[0]) / SPLASH_ASPECT; + double dy = y - sample[1]; + double distance = Math.sqrt(dx * dx + dy * dy) / thickness; + if (distance < streamBest) { + streamBest = distance; + } + } + } + if (streamBest <= 1.0) { + return '-'; + } + return 0; + } + + 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[][][] splashStreamSpines(double notchX, double streamReach) { + double[][] control = {{notchX + 2.5, 10.2}, {13.0, 10.4}, {streamReach, 10.9}}; + int samples = 41; + 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; } diff --git a/core/src/main/java/art/arcane/iris/engine/modifier/IrisCarveModifier.java b/core/src/main/java/art/arcane/iris/engine/modifier/IrisCarveModifier.java index f486800c9..3602620ad 100644 --- a/core/src/main/java/art/arcane/iris/engine/modifier/IrisCarveModifier.java +++ b/core/src/main/java/art/arcane/iris/engine/modifier/IrisCarveModifier.java @@ -454,9 +454,10 @@ public class IrisCarveModifier extends EngineAssignedModifier { private void processZone(Hunk output, MantleChunk mc, Mantle mantle, CaveZone zone, int rx, int rz, int xx, int zz, IrisDimensionCarvingResolver.State resolverState, Long2ObjectOpenHashMap caveBiomeCache) { int center = (zone.floor + zone.ceiling) / 2; + int maxY = output.getHeight(); String customBiome = ""; - if (B.isDecorant(output.getClosest(rx, zone.ceiling + 1, rz))) { + if (zone.ceiling + 1 < maxY && B.isDecorant(output.getRaw(rx, zone.ceiling + 1, rz))) { output.setRaw(rx, zone.ceiling + 1, rz, AIR); } @@ -517,32 +518,31 @@ public class IrisCarveModifier extends EngineAssignedModifier { blocks = biome.generateCeilingLayers(getDimension(), xx, zz, rng, 3, zone.ceiling, getData(), getComplex()); - if (zone.ceiling + 1 < mantle.getWorldHeight()) { - for (int i = 0; i < zone.ceiling + 1; i++) { - if (!blocks.hasIndex(i)) { - break; - } - - BlockData b = blocks.get(i); - BlockData up = output.getRaw(rx, zone.ceiling + i + 1, rz); - - if (!B.isSolid(up)) { - continue; - } - - if (B.isOre(up)) { - output.setRaw(rx, zone.ceiling + i + 1, rz, B.toDeepSlateOre(up, b)); - continue; - } - - output.setRaw(rx, zone.ceiling + i + 1, rz, b); + for (int i = 0; i < blocks.size(); i++) { + int cy = zone.ceiling + i + 1; + if (cy >= maxY) { + break; } + + BlockData b = blocks.get(i); + BlockData up = output.getRaw(rx, cy, rz); + + if (!B.isSolid(up)) { + continue; + } + + if (B.isOre(up)) { + output.setRaw(rx, cy, rz, B.toDeepSlateOre(up, b)); + continue; + } + + output.setRaw(rx, cy, rz, b); } for (IrisDecorator decorator : biome.getDecorators()) { - if (decorator.getPartOf().equals(IrisDecorationPart.NONE) && B.isSolid(output.getRaw(rx, zone.getFloor() - 1, rz))) { + if (decorator.getPartOf().equals(IrisDecorationPart.NONE) && zone.getFloor() > 0 && B.isSolid(output.getRaw(rx, zone.getFloor() - 1, rz))) { decorant.getSurfaceDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getFloor() - 1, zone.airThickness()); - } else if (decorator.getPartOf().equals(IrisDecorationPart.CEILING) && B.isSolid(output.getRaw(rx, zone.getCeiling() + 1, rz))) { + } else if (decorator.getPartOf().equals(IrisDecorationPart.CEILING) && zone.getCeiling() + 1 < maxY && B.isSolid(output.getRaw(rx, zone.getCeiling() + 1, rz))) { decorant.getCeilingDecorator().decorate(rx, rz, xx, xx, xx, zz, zz, zz, output, biome, zone.getCeiling(), zone.airThickness()); } }