mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-17 17:54:05 +00:00
Map Command Overhaul in 1.17
- Features biomes using random color (based on vanilla derivative) if a color isn't provided in the biome class - Allows a map to be opened for packs that don't have a world open (`/iris std map overworld`)
This commit is contained in:
parent
147d5902ed
commit
1f2871f649
@ -5,7 +5,7 @@ plugins {
|
||||
}
|
||||
|
||||
group 'com.volmit.iris'
|
||||
version '1.5-TOTALLY-UNSTABLE'
|
||||
version '1.5-UNSTABLE-MAP'
|
||||
def apiVersion = '1.17'
|
||||
def name = 'Iris'
|
||||
def main = 'com.volmit.iris.Iris'
|
||||
|
@ -78,6 +78,10 @@ public class IrisComplex implements DataProvider {
|
||||
}
|
||||
|
||||
public IrisComplex(Engine engine) {
|
||||
this(engine, false);
|
||||
}
|
||||
|
||||
public IrisComplex(Engine engine, boolean simple) {
|
||||
int cacheSize = IrisSettings.get().getCache().getStreamingCacheSize();
|
||||
this.rng = new RNG(engine.getWorld().getSeed());
|
||||
this.data = engine.getData();
|
||||
|
@ -2,15 +2,24 @@ package com.volmit.iris.manager.command.studio;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.IrisSettings;
|
||||
import com.volmit.iris.manager.gui.IrisVision;
|
||||
import com.volmit.iris.scaffold.IrisWorlds;
|
||||
import com.volmit.iris.generator.IrisComplex;
|
||||
import com.volmit.iris.manager.IrisDataManager;
|
||||
import com.volmit.iris.map.MapVision;
|
||||
import com.volmit.iris.object.IrisDimension;
|
||||
import com.volmit.iris.scaffold.engine.IrisAccess;
|
||||
import com.volmit.iris.util.FakeEngine;
|
||||
import com.volmit.iris.util.FakeWorld;
|
||||
import com.volmit.iris.util.KList;
|
||||
import com.volmit.iris.util.MortarCommand;
|
||||
import com.volmit.iris.util.MortarSender;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class CommandIrisStudioMap extends MortarCommand {
|
||||
public CommandIrisStudioMap() {
|
||||
import java.io.File;
|
||||
|
||||
public class CommandIrisStudioMap extends MortarCommand
|
||||
{
|
||||
public CommandIrisStudioMap()
|
||||
{
|
||||
super("map", "render");
|
||||
setDescription("Render a map (gui outside of mc)");
|
||||
requiresPermission(Iris.perm.studio);
|
||||
@ -23,33 +32,79 @@ public class CommandIrisStudioMap extends MortarCommand {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(MortarSender sender, String[] args) {
|
||||
if (!IrisSettings.get().isStudio()) {
|
||||
public boolean handle(MortarSender sender, String[] args)
|
||||
{
|
||||
if(!IrisSettings.get().isStudio())
|
||||
{
|
||||
sender.sendMessage("To use Iris Studio, please enable studio in Iris/settings.json");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!IrisSettings.get().isUseServerLaunchedGuis()) {
|
||||
if(!IrisSettings.get().isUseServerLaunchedGuis())
|
||||
{
|
||||
sender.sendMessage("To use Iris Guis, please enable serverLaunchedGuis in Iris/settings.json");
|
||||
return true;
|
||||
}
|
||||
|
||||
IrisComplex complex;
|
||||
|
||||
try {
|
||||
if (args.length > 0) {
|
||||
String type = "";
|
||||
long seed = 1337;
|
||||
for(String i : args)
|
||||
{
|
||||
if (i.contains("=")) {
|
||||
type = i.startsWith("type=") ? i.split("\\Q=\\E")[1] : type;
|
||||
seed = i.startsWith("seed=") ? Long.valueOf(i.split("\\Q=\\E")[1]) : seed;
|
||||
} else {
|
||||
if (type.equals("")) {
|
||||
type = i;
|
||||
} else if (seed == 1337) {
|
||||
seed = Long.valueOf(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals("")) {
|
||||
sender.sendMessage("Open this in a studio world or do /iris studio map [pack]");
|
||||
return true;
|
||||
}
|
||||
|
||||
IrisDimension dim = IrisDataManager.loadAnyDimension(type);
|
||||
|
||||
if (dim == null) {
|
||||
sender.sendMessage("Can't find dimension: " + type);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dim.getEnvironment() == null) {
|
||||
dim.setEnvironment(World.Environment.NORMAL);
|
||||
}
|
||||
|
||||
//Setup the fake world and engine objects so we can get an IrisComplex for the terrain they will
|
||||
//generate without actually generating any of it
|
||||
sender.sendMessage("Preparing map...");
|
||||
FakeWorld world = new FakeWorld(dim.getName(), 0, 256, seed, new File(dim.getName()), dim.getEnvironment());
|
||||
FakeEngine engine = new FakeEngine(dim, world);
|
||||
complex = new IrisComplex(engine, true);
|
||||
sender.sendMessage("Opening Map!");
|
||||
} else if (Iris.proj.isProjectOpen()) {
|
||||
IrisAccess g = Iris.proj.getActiveProject().getActiveProvider();
|
||||
IrisVision.launch(g, 0);
|
||||
sender.sendMessage("Opening Map!");
|
||||
} catch (Throwable e) {
|
||||
IrisAccess g = IrisWorlds.access(sender.player().getWorld());
|
||||
IrisVision.launch(g, 0);
|
||||
sender.sendMessage("Opening Map!");
|
||||
complex = g.getCompound().getDefaultEngine().getFramework().getComplex();
|
||||
sender.sendMessage("Opening map for existing studio world!");
|
||||
} else {
|
||||
sender.sendMessage("Open this in a studio world or do /iris studio map [pack]");
|
||||
return true;
|
||||
}
|
||||
|
||||
MapVision map = new MapVision(complex);
|
||||
map.open();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArgsUsage() {
|
||||
return "";
|
||||
protected String getArgsUsage()
|
||||
{
|
||||
return "[pack] [seed=1337]";
|
||||
}
|
||||
}
|
||||
|
67
src/main/java/com/volmit/iris/map/BiomeMap.java
Normal file
67
src/main/java/com/volmit/iris/map/BiomeMap.java
Normal file
@ -0,0 +1,67 @@
|
||||
package com.volmit.iris.map;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.volmit.iris.object.IrisBiome;
|
||||
import com.volmit.iris.object.IrisDimension;
|
||||
import com.volmit.iris.object.IrisRegion;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class BiomeMap {
|
||||
|
||||
private BiMap<IrisBiome, Integer> biomeMap;
|
||||
private BiMap<IrisRegion, Integer> regionMap;
|
||||
private IrisDimension dimension;
|
||||
|
||||
private Set<Integer> activeBiomes = new HashSet<>();
|
||||
private Set<Integer> activeRegions = new HashSet<>();
|
||||
|
||||
public BiomeMap(IrisDimension dimension) {
|
||||
this.dimension = dimension;
|
||||
|
||||
List<IrisBiome> biomes = dimension.getAllAnyBiomes();
|
||||
List<IrisRegion> regions = dimension.getAllAnyRegions();
|
||||
|
||||
biomeMap = HashBiMap.create(biomes.size());
|
||||
regionMap = HashBiMap.create(regions.size());
|
||||
|
||||
int nextID = 0;
|
||||
|
||||
for (IrisBiome biome : biomes) {
|
||||
biomeMap.putIfAbsent(biome, nextID);
|
||||
activeBiomes.add(nextID);
|
||||
nextID++;
|
||||
}
|
||||
|
||||
nextID = 0;
|
||||
|
||||
for (IrisRegion region : regions) {
|
||||
regionMap.putIfAbsent(region, nextID);
|
||||
activeRegions.add(nextID);
|
||||
nextID++;
|
||||
}
|
||||
}
|
||||
|
||||
public IrisDimension getDimension() {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
public IrisBiome getBiome(int id) {
|
||||
return biomeMap.inverse().get(id);
|
||||
}
|
||||
|
||||
public int getBiomeId(IrisBiome biome) {
|
||||
return biomeMap.get(biome);
|
||||
}
|
||||
|
||||
public IrisRegion getRegion(int id) {
|
||||
return regionMap.inverse().get(id);
|
||||
}
|
||||
|
||||
public int getRegionId(IrisRegion region) {
|
||||
return regionMap.get(region);
|
||||
}
|
||||
}
|
586
src/main/java/com/volmit/iris/map/MapVision.java
Normal file
586
src/main/java/com/volmit/iris/map/MapVision.java
Normal file
@ -0,0 +1,586 @@
|
||||
package com.volmit.iris.map;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.generator.IrisComplex;
|
||||
import com.volmit.iris.util.J;
|
||||
import com.volmit.iris.util.KMap;
|
||||
import com.volmit.iris.util.KSet;
|
||||
import com.volmit.iris.util.PrecisionStopwatch;
|
||||
import com.volmit.iris.util.RandomColor;
|
||||
import com.volmit.iris.util.RollingSequence;
|
||||
import io.netty.util.internal.ConcurrentSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import java.awt.Color;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Point;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MapVision extends JPanel {
|
||||
|
||||
private int threadId = 0;
|
||||
|
||||
private static final int TILE_SIZE = 128; //Tile size in pixels
|
||||
private static final int TILE_REALITY = 512; //How many blocks a tile is
|
||||
private static final int TILE_SIZE_R = 7; //The number of bits to shift to get the pixel side
|
||||
private static final int TILE_REALITY_R = 9; //The number of bits to shift to get the real size
|
||||
|
||||
private static final int DEF_WIDTH = 1440;
|
||||
private static final int DEF_HEIGHT = 820;
|
||||
|
||||
|
||||
private IrisComplex complex;
|
||||
private RenderType currentType = RenderType.BIOME_LAND;
|
||||
|
||||
private int mouseX; //The current mouse coords
|
||||
private int mouseY;
|
||||
private double draggedOffsetX; //The amount the mouse has dragged the map
|
||||
private double draggedOffsetY;
|
||||
private int centerTileX; //The center tile in the screen
|
||||
private int centerTileY;
|
||||
private int offsetX; //Offset to draw tiles to
|
||||
private int offsetY;
|
||||
private int lastTileWidth;
|
||||
|
||||
private boolean dirty = true; //Whether to repaint textures
|
||||
private double scale = 1;
|
||||
private boolean realname = false;
|
||||
|
||||
private KMap<Integer, Tile> tiles = new KMap<>();
|
||||
|
||||
private Set<Tile> visibleTiles = new ConcurrentSet<>(); //Tiles that are visible on screen
|
||||
private Set<Tile> halfDirtyTiles = new ConcurrentSet<>(); //Tiles that should be drawn next draw
|
||||
|
||||
private short[][] spiral; //See #generateSpiral
|
||||
|
||||
private final Color overlay = new Color(80, 80, 80);
|
||||
private final Font overlayFont = new Font("Arial", Font.BOLD, 16);
|
||||
|
||||
private RollingSequence roll = new RollingSequence(50);
|
||||
|
||||
private boolean debug = false;
|
||||
private int[] debugBorder = new int[] {-5, -3, 6, 4};
|
||||
|
||||
private boolean recalculating;
|
||||
|
||||
// IrisComplex is the main class I need for a biome map. You can make one from an Engine object,
|
||||
// which does need a FakeWorld object in it for the seed
|
||||
public MapVision(IrisComplex worldComplex)
|
||||
{
|
||||
this.complex = worldComplex;
|
||||
this.setBackground(Color.BLACK);
|
||||
this.setVisible(true);
|
||||
roll.put(1);
|
||||
generateSpiral(64);
|
||||
|
||||
addMouseWheelListener((mouseWheelEvent) -> {
|
||||
double oldScale = this.scale;
|
||||
this.scale = Math.min(4, Math.max(scale + scale * mouseWheelEvent.getWheelRotation() * 0.2, 1));
|
||||
double wx = getWidth();
|
||||
double hy = getHeight();
|
||||
double xScale = (mouseX - wx) / wx * 0.5;
|
||||
double yScale = (mouseY - hy) / hy * 0.5;
|
||||
|
||||
if (mouseWheelEvent.getWheelRotation() > 0) { //Only on zoom in, adjust the position to zoom into
|
||||
this.draggedOffsetX += xScale * (wx / 2) * (oldScale - scale);
|
||||
this.draggedOffsetY += yScale * (hy / 2) * (oldScale - scale);
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
repaint();
|
||||
softRecalculate();
|
||||
});
|
||||
addMouseMotionListener(new MouseMotionListener()
|
||||
{
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e)
|
||||
{
|
||||
Point cp = e.getPoint();
|
||||
mouseX = cp.x;
|
||||
mouseY = cp.y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e)
|
||||
{
|
||||
Point cp = e.getPoint();
|
||||
draggedOffsetX -= (mouseX - cp.x) / scale;
|
||||
draggedOffsetY -= (mouseY - cp.y) / scale;
|
||||
mouseX = cp.x;
|
||||
mouseY = cp.y;
|
||||
softRecalculate();
|
||||
dirty = true;
|
||||
}
|
||||
});
|
||||
recalculate(); //Setup
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Open this GUI
|
||||
*/
|
||||
public void open() {
|
||||
JFrame frame = new JFrame("Iris Map (" + complex.getData().getDataFolder().getName() + ")");
|
||||
frame.add(this);
|
||||
frame.setSize(DEF_WIDTH, DEF_HEIGHT);
|
||||
frame.setBackground(Color.BLACK);
|
||||
frame.addComponentListener(new ComponentListener() {
|
||||
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
dirty = true;
|
||||
softRecalculate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentMoved(ComponentEvent e) {
|
||||
dirty = true;
|
||||
repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) { }
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) { }
|
||||
});
|
||||
frame.addKeyListener(new KeyListener() {
|
||||
@Override
|
||||
public void keyTyped(KeyEvent e) { }
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_SHIFT)
|
||||
realname = true;
|
||||
else if (e.getKeyCode() == KeyEvent.VK_ALT) debug = !debug;
|
||||
else if (e.getKeyCode() == KeyEvent.VK_R) {
|
||||
dirty = true;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_SHIFT)
|
||||
realname = false;
|
||||
}
|
||||
});
|
||||
File file = Iris.getCached("Iris Icon", "https://raw.githubusercontent.com/VolmitSoftware/Iris/master/icon.png");
|
||||
|
||||
if(file != null) {
|
||||
try {
|
||||
frame.setIconImage(ImageIO.read(file));
|
||||
} catch(IOException ignored) { }
|
||||
}
|
||||
|
||||
frame.setVisible(true);
|
||||
frame.requestFocus();
|
||||
frame.toFront();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics gx) {
|
||||
//super.paint(gx);
|
||||
PrecisionStopwatch stopwatch = PrecisionStopwatch.start();
|
||||
|
||||
int windowOffsetX = getWidth() / 2;
|
||||
int windowOffsetY = getHeight() / 2;
|
||||
|
||||
offsetX = (int) Math.round(draggedOffsetX * scale) + windowOffsetX;
|
||||
offsetY = (int) Math.round(draggedOffsetY * scale) + windowOffsetY;
|
||||
|
||||
//If we should do a full repaint of the entire frame. Only done when the zoom level changes, etc
|
||||
if (dirty) {
|
||||
super.paint(gx); //Clear the frame first
|
||||
for (Iterator<Tile> iterator = visibleTiles.iterator(); iterator.hasNext();) {
|
||||
Tile tile = iterator.next();
|
||||
drawTile(gx, tile);
|
||||
}
|
||||
dirty = false;
|
||||
} else {
|
||||
//Loop through all the tiles that haven't been drawn last draw and draw them
|
||||
//This saves us having to do a FULL redraw when only 1 new tile has been added
|
||||
for (Iterator<Tile> iterator = halfDirtyTiles.iterator(); iterator.hasNext();) {
|
||||
Tile tile = iterator.next();
|
||||
drawTile(gx, tile);
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
gx.setColor(overlay);
|
||||
gx.fillRect(getWidth() - 400, 4, 396, 27);
|
||||
gx.setColor(Color.WHITE);
|
||||
//int x = (int) (((int) ((mouseX - windowOffsetX)) << 2) + (draggedOffsetX * scale));
|
||||
//int y = (int) (((int) ((mouseY - windowOffsetY)) << 2) + (draggedOffsetY * scale));
|
||||
int x = (int) (((int) ((mouseX - windowOffsetX))) + (-draggedOffsetX * scale)) << 2;
|
||||
int y = (int) (((int) ((mouseY - windowOffsetY))) + (-draggedOffsetY * scale)) << 2;
|
||||
String text = " [" + x+ ", " + y + "]";
|
||||
if (realname)
|
||||
text = complex.getLandBiomeStream().get(x, y).getLoadKey().toUpperCase() + text;
|
||||
else
|
||||
text = complex.getLandBiomeStream().get(x, y).getName().toUpperCase() + text;
|
||||
gx.setFont(overlayFont);
|
||||
gx.drawString(text, getWidth() - 400 + 6, 23);
|
||||
|
||||
if (debug) {
|
||||
gx.setColor(Color.RED);
|
||||
int xx = (int) Math.round((debugBorder[0] << TILE_SIZE_R) / scale + offsetX);
|
||||
int yy = (int) Math.round((debugBorder[1] << TILE_SIZE_R) / scale + offsetY);
|
||||
int xx2 = (int) Math.round((debugBorder[2] << TILE_SIZE_R) / scale + offsetX);
|
||||
int yy2 = (int) Math.round((debugBorder[3] << TILE_SIZE_R) / scale + offsetY);
|
||||
gx.drawRect(xx, yy, xx2, yy2);
|
||||
gx.drawRect(xx-1, yy-1, xx2+1, yy2+1);
|
||||
gx.drawRect(xx-2, yy-2, xx2+2, yy2+2);
|
||||
|
||||
|
||||
gx.setColor(overlay);
|
||||
gx.fillRect(10, 10, 220, 200);
|
||||
gx.setColor(Color.WHITE);
|
||||
gx.drawString("Center [" + centerTileX + ", " + centerTileY + "]", 20, 25);
|
||||
gx.drawString((60 / (Math.max(roll.getAverage(), 1))) + " fps", 20, 45);
|
||||
gx.drawString("Width = " + lastTileWidth, 20, 65);
|
||||
gx.drawString("Dirty = " + dirty, 20, 85);
|
||||
gx.drawString("Scale = " + scale, 20, 105);
|
||||
gx.drawString("Tiles (Visible)" + visibleTiles.size(), 20, 125);
|
||||
gx.drawString("Tiles (Total) " + tiles.size(), 20, 145);
|
||||
|
||||
x = (int) (((int) ((mouseX - windowOffsetX))) + (-draggedOffsetX * scale)) >> TILE_SIZE_R;
|
||||
y = (int) (((int) ((mouseY - windowOffsetY))) + (-draggedOffsetY * scale)) >> TILE_SIZE_R;
|
||||
Tile t = getTile((short)x, (short)y);
|
||||
boolean b1 = t != null;
|
||||
boolean b2 = b1 && visibleTiles.contains(t);
|
||||
gx.drawString("Cursor Tile [" + x + ", " + y + "]", 20, 165);
|
||||
gx.drawString("Tile Details [" + String.valueOf(b1).toUpperCase() + ", " + String.valueOf(b2).toUpperCase() + "]", 20, 185);
|
||||
|
||||
}
|
||||
|
||||
stopwatch.end();
|
||||
roll.put(stopwatch.getMillis());
|
||||
|
||||
/*J.a(() ->
|
||||
{
|
||||
J.sleep(1000 / targetFPS);
|
||||
repaint();
|
||||
});*/
|
||||
J.a(sleepTask);
|
||||
}
|
||||
|
||||
public void drawTile(Graphics gx, Tile tile) {
|
||||
if (gx == null) return;
|
||||
|
||||
int x = (int) Math.round((tile.getX() << TILE_SIZE_R) / scale + offsetX);
|
||||
int y = (int) Math.round((tile.getY() << TILE_SIZE_R) / scale + offsetY);
|
||||
//int x = (int) ((tile.getX() * TILE_SIZE) / scale + offsetX);
|
||||
//int y = (int) ((tile.getY() * TILE_SIZE) / scale + offsetY);
|
||||
|
||||
int size = (int) (TILE_SIZE / scale);
|
||||
int off = (int) (TILE_SIZE % scale);
|
||||
gx.drawImage(tile.getImage(), x, y, size, size, null);
|
||||
}
|
||||
|
||||
private Runnable sleepTask = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
double t = Math.max(Math.min(roll.getAverage(), 1000), 30);
|
||||
J.sleep((long) t);
|
||||
repaint();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if we should do a full recalculation of what tiles should be visible
|
||||
*/
|
||||
public void softRecalculate() {
|
||||
short x = (short) (((-draggedOffsetX * scale)) / TILE_SIZE * scale);
|
||||
short y = (short) (((-draggedOffsetY * scale)) / TILE_SIZE * scale);
|
||||
int xTiles = (((int)(getWidth() * scale) >> TILE_SIZE_R)) / 2 + 1;
|
||||
|
||||
if (centerTileX != x || centerTileY != y || xTiles != lastTileWidth) {
|
||||
recalculate();
|
||||
}
|
||||
|
||||
centerTileX = x;
|
||||
centerTileY = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate what tiles should be visible on screen, as well as queue
|
||||
* new tiles to be created
|
||||
*/
|
||||
public void recalculate() {
|
||||
PrecisionStopwatch stopwatch = PrecisionStopwatch.start();
|
||||
|
||||
//Clears out the queue of existing tiles to do because we are redoing them anyway
|
||||
//If we don't do this, the queue gets so clogged that it literally takes up the
|
||||
//entire CPU with thread locking/unlocking
|
||||
executorService.getQueue().clear();
|
||||
|
||||
int W = getWidth();
|
||||
int H = getHeight();
|
||||
|
||||
if (W == 0|| H == 0) { //The window hasn't fully opened yet; assume defaults
|
||||
W = DEF_WIDTH;
|
||||
H = DEF_HEIGHT;
|
||||
}
|
||||
|
||||
short centerTileX = (short) (((-draggedOffsetX * scale)) / TILE_SIZE * scale);
|
||||
short centerTileY = (short) (((-draggedOffsetY * scale)) / TILE_SIZE * scale);
|
||||
|
||||
//Iris.info("Center is " + centerTileX + ", " + centerTileY);
|
||||
//Iris.info("Width is " + W + ", " + H);
|
||||
|
||||
int woh = Math.max(W, H);
|
||||
int newSize = ((int)(woh * scale) >> TILE_SIZE_R) + 1;
|
||||
int checkSizeX = (((int)(W * scale) >> TILE_SIZE_R)) / 2;
|
||||
int checkSizeY = (((int)(H * scale) >> TILE_SIZE_R)) / 2;
|
||||
lastTileWidth = checkSizeX;
|
||||
generateSpiral(newSize);
|
||||
|
||||
Set<Integer> checked = new HashSet<>();
|
||||
Set<Integer> clone = new HashSet(visibleTiles.stream().map((t) ->
|
||||
getTileId(t.getX(), t.getY()))
|
||||
.collect(Collectors.toSet())); //Clone the visible tiles
|
||||
|
||||
if (debug) { //These are the 4 corners of the red line that shows the visibility check region for tiles
|
||||
debugBorder[0] = -checkSizeX + centerTileX;
|
||||
debugBorder[1] = -checkSizeY + centerTileY;
|
||||
debugBorder[2] = checkSizeX + 1 + centerTileX;
|
||||
debugBorder[3] = checkSizeY + 1 + centerTileY;
|
||||
}
|
||||
|
||||
for (short[] coords : spiral) { //Start from the center of the spiral and work outwards to find new tiles to queue
|
||||
short x = (short)(coords[0] + centerTileX);
|
||||
short y = (short)(coords[1] + centerTileY);
|
||||
|
||||
//When it goes offscreen, don't queue the tile by continuing
|
||||
if (Math.abs(coords[0]) > checkSizeX + 1) {
|
||||
continue;
|
||||
}
|
||||
if (Math.abs(coords[1]) > checkSizeY + 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int id = getTileId(x, y);
|
||||
|
||||
//If the tile is not already made
|
||||
if (!tiles.containsKey(id)) {
|
||||
short[] c = getTileCoords(id);
|
||||
queue(c[0], c[1]); //Queue for creation
|
||||
} else {
|
||||
checked.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
clone.removeAll(checked); //Remove the tiles that we know are onscreen
|
||||
|
||||
for (int id : clone) { //Loop through the invisible tiles and mark them for removal from memory
|
||||
short[] c = getTileCoords(id);
|
||||
queueForRemoval(getTile(c[0], c[1]));
|
||||
//visibleTiles.remove(t);
|
||||
}
|
||||
|
||||
stopwatch.end();
|
||||
roll.put(stopwatch.getMillis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a tile for creation
|
||||
* @param tileX X tile coord
|
||||
* @param tileY Y tile coord
|
||||
*/
|
||||
public void queue(short tileX, short tileY) {
|
||||
//If the tile still exists but just isn't visible
|
||||
if (tiles.containsKey(getTileId(tileX, tileY))) {
|
||||
Tile tile = getTile(tileX, tileY);
|
||||
if (visibleTiles.contains(tile)) return;
|
||||
|
||||
visibleTiles.add(tile);
|
||||
halfDirtyTiles.add(tile); //Re-render it without doing a full repaint
|
||||
//dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
//I turned all lambda around here into objects just to see if they would
|
||||
//show up in timings instead of "$lambda". But they didn't. So it's not
|
||||
//not my code DIRECTLY. I believe the thing timings show is just to do
|
||||
//with threads stopping and starting/halting in the thread pool. Don't
|
||||
//know why or how to fix it, though
|
||||
|
||||
/*executorService.execute(() -> {
|
||||
Tile tile = new Tile(tileX, tileY);
|
||||
tile.render(complex, currentType);
|
||||
tiles.put(getTileId(tileX, tileY), tile);
|
||||
visibleTiles.add(tile);
|
||||
dirty = true;
|
||||
});*/
|
||||
executorService.execute(queueTask(tileX, tileY));
|
||||
|
||||
}
|
||||
|
||||
public Runnable queueTask(short tileX, short tileY) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Tile tile = new Tile(tileX, tileY);
|
||||
tile.render(complex, currentType);
|
||||
tiles.put(getTileId(tileX, tileY), tile);
|
||||
visibleTiles.add(tile);
|
||||
//dirty = true; //Disabled marking as dirty so a redraw of the entire map isn't needed
|
||||
halfDirtyTiles.add(tile);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Pend a tile for removal from the screen
|
||||
* @param tile The tile to remove
|
||||
*/
|
||||
public void queueForRemoval(Tile tile) {
|
||||
//TODO Change from using the async task system as it may be putting strain on the server from being called so often
|
||||
J.a(() -> visibleTiles.remove(tile), 20); //Remove visibility in a bit
|
||||
|
||||
J.a(() -> { //Remove it completely from memory after 5 seconds if it's still not visible
|
||||
if (!visibleTiles.contains(tile)) {
|
||||
tiles.remove(getTileId(tile.getX(), tile.getY()));
|
||||
}
|
||||
}, 20 * 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a tile based on the X and Z coords of the tile
|
||||
* @param tileX X Coord
|
||||
* @param tileY Y Coord
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
public Tile getTile(short tileX, short tileY) {
|
||||
return tiles.get(getTileId(tileX, tileY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an integer that represents a tile's location
|
||||
* @param tileX X Coord
|
||||
* @param tileY Y Coord
|
||||
* @return
|
||||
*/
|
||||
public int getTileId(short tileX, short tileY) {
|
||||
return tileX | tileY << 16;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an integer representing a tiles location back into 2 shorts
|
||||
* @param id The tile integer
|
||||
* @return
|
||||
*/
|
||||
public short[] getTileCoords(int id) {
|
||||
return new short[] {(short) (id & 0x0000FFFF), (short) (id >> 16)};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a 2D array of relative tile locations. This is so we know what order
|
||||
* to search for new tiles in a nice, spiral way
|
||||
* @param size Size of the array
|
||||
*/
|
||||
public void generateSpiral(int size) {
|
||||
if (size % 2 == 0) size++;
|
||||
short[][] newSpiral = new short[size * size][2];
|
||||
|
||||
int x = 0; // current position; x
|
||||
int y = 0; // current position; y
|
||||
int d = 0; // current direction; 0=RIGHT, 1=DOWN, 2=LEFT, 3=UP
|
||||
int s = 1; // chain size
|
||||
int c = 0; // count
|
||||
|
||||
// starting point
|
||||
x = ((int)(size/2.0))-1;
|
||||
y = ((int)(size/2.0))-1;
|
||||
int offset = (size / 2) - 1;
|
||||
|
||||
for (int k=1; k<=(size-1); k++)
|
||||
{
|
||||
for (int j=0; j<(k<(size-1)?2:3); j++)
|
||||
{
|
||||
for (int i=0; i<s; i++)
|
||||
{
|
||||
short[] coords = {(short) (x - offset), (short) (y - offset)};
|
||||
newSpiral[c] = coords;
|
||||
c++;
|
||||
//Iris.info("Spiral " + coords[0] + ", " + coords[1]); //Testing
|
||||
|
||||
switch (d)
|
||||
{
|
||||
case 0: y = y + 1; break;
|
||||
case 1: x = x + 1; break;
|
||||
case 2: y = y - 1; break;
|
||||
case 3: x = x - 1; break;
|
||||
}
|
||||
}
|
||||
d = (d+1)%4;
|
||||
}
|
||||
s = s + 1;
|
||||
}
|
||||
|
||||
spiral = newSpiral;
|
||||
}
|
||||
|
||||
/*private final ExecutorService executorService = Executors.newFixedThreadPool(8, r -> {
|
||||
threadId++;
|
||||
Thread t = new Thread(r);
|
||||
t.setName("Iris Map Renderer " + threadId);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.setUncaughtExceptionHandler((et, e) ->
|
||||
{
|
||||
Iris.info("Exception encountered in " + et.getName());
|
||||
e.printStackTrace();
|
||||
});
|
||||
|
||||
return t;
|
||||
});*/
|
||||
|
||||
private ThreadFactory factory = new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(@NotNull Runnable r) {
|
||||
threadId++;
|
||||
Thread t = new Thread(r);
|
||||
t.setName("Iris Map Renderer " + threadId);
|
||||
t.setPriority(Thread.MIN_PRIORITY);
|
||||
t.setDaemon(true);
|
||||
t.setUncaughtExceptionHandler((et, e) ->
|
||||
{
|
||||
Iris.info("Exception encountered in " + et.getName());
|
||||
e.printStackTrace();
|
||||
});
|
||||
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
//Our thread pool that draws the tiles for us
|
||||
private final ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(8, factory);
|
||||
|
||||
|
||||
}
|
5
src/main/java/com/volmit/iris/map/RenderType.java
Normal file
5
src/main/java/com/volmit/iris/map/RenderType.java
Normal file
@ -0,0 +1,5 @@
|
||||
package com.volmit.iris.map;
|
||||
|
||||
public enum RenderType {
|
||||
BIOME_LAND, REGION, CAVE_LAND
|
||||
}
|
87
src/main/java/com/volmit/iris/map/Tile.java
Normal file
87
src/main/java/com/volmit/iris/map/Tile.java
Normal file
@ -0,0 +1,87 @@
|
||||
package com.volmit.iris.map;
|
||||
|
||||
import com.volmit.iris.generator.IrisComplex;
|
||||
import com.volmit.iris.object.IrisBiome;
|
||||
import com.volmit.iris.object.IrisRegion;
|
||||
import com.volmit.iris.scaffold.stream.ProceduralStream;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class Tile {
|
||||
|
||||
@Getter
|
||||
private short x;
|
||||
@Getter
|
||||
private short y;
|
||||
|
||||
@Getter
|
||||
private BufferedImage image;
|
||||
|
||||
private Set<Integer> biomes;
|
||||
private Set<Integer> regions;
|
||||
|
||||
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean dirty;
|
||||
|
||||
@Getter
|
||||
private boolean rendering;
|
||||
|
||||
public Tile(short x, short y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public boolean hasBiome(int biome) {
|
||||
return biomes.contains(biome);
|
||||
}
|
||||
|
||||
public boolean hasRegion(int region) {
|
||||
return regions.contains(region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the tile
|
||||
* @param complex The world complex
|
||||
* @param type The type of render
|
||||
* @return True when rendered
|
||||
*/
|
||||
public boolean render(IrisComplex complex, RenderType type) {
|
||||
BufferedImage newImage = new BufferedImage(128, 128, BufferedImage.TYPE_INT_RGB);
|
||||
|
||||
ProceduralStream stream;
|
||||
BiFunction<Integer, Integer, Integer> getColor;
|
||||
if (type == RenderType.BIOME_LAND) {
|
||||
stream = complex.getLandBiomeStream();
|
||||
getColor = (x, z) -> ((ProceduralStream<IrisBiome>)stream).get(x, z).getColor().getAsRGB();
|
||||
} else if (type == RenderType.REGION) {
|
||||
stream = complex.getRegionStream();
|
||||
getColor = (x, z) -> ((ProceduralStream<IrisRegion>)stream).get(x, z).getColor().getColor().getRGB();
|
||||
} else {
|
||||
stream = complex.getCaveBiomeStream();
|
||||
getColor = (x, z) -> ((ProceduralStream<IrisBiome>)stream).get(x, z).getColor().getAsRGB();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
for (int j = 0; j < 128; j++) {
|
||||
newImage.setRGB(i, j, getColor.apply(translate(x, i), translate(y, j)));
|
||||
}
|
||||
}
|
||||
image = newImage;
|
||||
rendering = false;
|
||||
dirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int translate(int section, int pixel) {
|
||||
return (section << 9) | (pixel << 2) | 2;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.volmit.iris.object;
|
||||
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.generator.IrisComplex;
|
||||
import com.volmit.iris.generator.noise.CNG;
|
||||
import com.volmit.iris.manager.IrisDataManager;
|
||||
@ -583,4 +584,26 @@ public class IrisBiome extends IrisRegistrant implements IRare {
|
||||
|
||||
return getLayers().get(0).get(rng, x, 0, z, idm);
|
||||
}
|
||||
|
||||
public IrisColor getColor() {
|
||||
if (this.color == null) {
|
||||
RandomColor randomColor = new RandomColor(getName().hashCode());
|
||||
if (this.getVanillaDerivative() == null) {
|
||||
this.color = new IrisColor();
|
||||
this.color.setRed(255).setGreen(255).setBlue(255);
|
||||
Iris.warn("No vanilla biome found for " + getName());
|
||||
}
|
||||
RandomColor.Color col = VanillaBiomeMap.getColorType(this.getVanillaDerivative());
|
||||
RandomColor.Luminosity lum = VanillaBiomeMap.getColorLuminosity(this.getVanillaDerivative());
|
||||
RandomColor.SaturationType sat = VanillaBiomeMap.getColorSaturatiom(this.getVanillaDerivative());
|
||||
int newColorI = randomColor.randomColor(col, col == RandomColor.Color.MONOCHROME ? RandomColor.SaturationType.MONOCHROME : sat, lum);
|
||||
|
||||
|
||||
Color newColor = new Color(newColorI);
|
||||
this.color = new IrisColor();
|
||||
this.color.setRed(newColor.getRed()).setBlue(newColor.getBlue()).setGreen(newColor.getGreen());
|
||||
}
|
||||
|
||||
return this.color;
|
||||
}
|
||||
}
|
||||
|
@ -86,4 +86,17 @@ public class IrisColor {
|
||||
|
||||
return new Color(a << 24 | r << 16 | g << 8 | b);
|
||||
}
|
||||
|
||||
public int getAsRGB() {
|
||||
if (hex != null) {
|
||||
try {
|
||||
if (hex.startsWith("#")) hex = hex.substring(1);
|
||||
return Integer.parseInt(hex, 16);
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return red << 16 | green << 8 | blue;
|
||||
}
|
||||
}
|
||||
|
139
src/main/java/com/volmit/iris/util/FakeEngine.java
Normal file
139
src/main/java/com/volmit/iris/util/FakeEngine.java
Normal file
@ -0,0 +1,139 @@
|
||||
package com.volmit.iris.util;
|
||||
|
||||
import com.volmit.iris.manager.IrisDataManager;
|
||||
import com.volmit.iris.object.IrisBiome;
|
||||
import com.volmit.iris.object.IrisDimension;
|
||||
import com.volmit.iris.scaffold.engine.Engine;
|
||||
import com.volmit.iris.scaffold.engine.EngineCompound;
|
||||
import com.volmit.iris.scaffold.engine.EngineEffects;
|
||||
import com.volmit.iris.scaffold.engine.EngineFramework;
|
||||
import com.volmit.iris.scaffold.engine.EngineMetrics;
|
||||
import com.volmit.iris.scaffold.engine.EngineTarget;
|
||||
import com.volmit.iris.scaffold.engine.EngineWorldManager;
|
||||
import com.volmit.iris.scaffold.hunk.Hunk;
|
||||
import com.volmit.iris.util.FakeWorld;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
|
||||
public class FakeEngine implements Engine {
|
||||
|
||||
@Getter
|
||||
private IrisDimension dimension;
|
||||
|
||||
@Getter
|
||||
private World world;
|
||||
|
||||
public FakeEngine(IrisDimension dimension, FakeWorld world) {
|
||||
this.dimension = dimension;
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() { }
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IrisDataManager getData() {
|
||||
return dimension.getLoader().copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EngineWorldManager getWorldManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParallelism(int parallelism) { }
|
||||
|
||||
@Override
|
||||
public int getParallelism() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EngineTarget getTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EngineFramework getFramework() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinHeight(int min) { }
|
||||
|
||||
@Override
|
||||
public void recycle() { }
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return 64;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double modifyX(double x) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double modifyZ(double z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(int x, int z, Hunk<BlockData> blocks, Hunk<Biome> biomes) { }
|
||||
|
||||
@Override
|
||||
public EngineMetrics getMetrics() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EngineEffects getEffects() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EngineCompound getCompound() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IrisBiome getFocus() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fail(String error, Throwable e) { }
|
||||
|
||||
@Override
|
||||
public boolean hasFailed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCacheID() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hotload() { }
|
||||
}
|
506
src/main/java/com/volmit/iris/util/RandomColor.java
Normal file
506
src/main/java/com/volmit/iris/util/RandomColor.java
Normal file
@ -0,0 +1,506 @@
|
||||
package com.volmit.iris.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Credit to https://github.com/lzyzsd/AndroidRandomColor
|
||||
*/
|
||||
public class RandomColor {
|
||||
|
||||
public static int hueOffset = 0;
|
||||
|
||||
public static class ColorInfo {
|
||||
Range hueRange;
|
||||
Range saturationRange;
|
||||
Range brightnessRange;
|
||||
List<Range> lowerBounds;
|
||||
|
||||
public ColorInfo(Range hueRange, Range saturationRange, Range brightnessRange, List<Range> lowerBounds) {
|
||||
this.hueRange = hueRange;
|
||||
this.saturationRange = saturationRange;
|
||||
this.brightnessRange = brightnessRange;
|
||||
this.lowerBounds = lowerBounds;
|
||||
}
|
||||
|
||||
public Range getHueRange() {
|
||||
return hueRange;
|
||||
}
|
||||
|
||||
public void setHueRange(Range hueRange) {
|
||||
this.hueRange = hueRange;
|
||||
}
|
||||
|
||||
public Range getSaturationRange() {
|
||||
return saturationRange;
|
||||
}
|
||||
|
||||
public void setSaturationRange(Range saturationRange) {
|
||||
this.saturationRange = saturationRange;
|
||||
}
|
||||
|
||||
public Range getBrightnessRange() {
|
||||
return brightnessRange;
|
||||
}
|
||||
|
||||
public void setBrightnessRange(Range brightnessRange) {
|
||||
this.brightnessRange = brightnessRange;
|
||||
}
|
||||
|
||||
public List<Range> getLowerBounds() {
|
||||
return lowerBounds;
|
||||
}
|
||||
|
||||
public void setLowerBounds(List<Range> lowerBounds) {
|
||||
this.lowerBounds = lowerBounds;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Range {
|
||||
int start;
|
||||
int end;
|
||||
|
||||
public Range(int start, int end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public boolean contain(int value) {
|
||||
return value >= start && value <= end;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "start: " + start + " end: " + end;
|
||||
}
|
||||
}
|
||||
|
||||
private Random random;
|
||||
|
||||
public static enum SaturationType {
|
||||
RANDOM, MONOCHROME, HIGH, LOW, MEDIUM
|
||||
}
|
||||
|
||||
public static enum Luminosity {
|
||||
BRIGHT, LIGHT, DARK, RANDOM
|
||||
}
|
||||
|
||||
public static class Options {
|
||||
int hue;
|
||||
SaturationType saturationType;
|
||||
Luminosity luminosity;
|
||||
|
||||
public int getHue() {
|
||||
return hue;
|
||||
}
|
||||
|
||||
public void setHue(int hue) {
|
||||
this.hue = hue;
|
||||
}
|
||||
|
||||
public SaturationType getSaturationType() {
|
||||
return saturationType;
|
||||
}
|
||||
|
||||
public void setSaturationType(SaturationType saturationType) {
|
||||
this.saturationType = saturationType;
|
||||
}
|
||||
|
||||
public Luminosity getLuminosity() {
|
||||
return luminosity;
|
||||
}
|
||||
|
||||
public void setLuminosity(Luminosity luminosity) {
|
||||
this.luminosity = luminosity;
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<String, ColorInfo> colors = new HashMap<>();
|
||||
|
||||
public RandomColor() {
|
||||
loadColorBounds();
|
||||
random = new Random();
|
||||
}
|
||||
|
||||
public RandomColor(long seed){
|
||||
loadColorBounds();
|
||||
random = new Random();
|
||||
random.setSeed(seed);
|
||||
}
|
||||
|
||||
private int getColor(int hue, int saturation, int brightness) {
|
||||
return java.awt.Color.getHSBColor((float)(hue + hueOffset % 360) / 360, (float)saturation / 100, (float)brightness / 100).getRGB();
|
||||
}
|
||||
|
||||
public int randomColor() {
|
||||
return randomColor(0, null, null);
|
||||
}
|
||||
|
||||
public int randomColor(int value, SaturationType saturationType, Luminosity luminosity) {
|
||||
int hue = value;
|
||||
hue = pickHue(hue);
|
||||
int saturation = pickSaturation(hue, saturationType, luminosity);
|
||||
int brightness = pickBrightness(hue, saturation, luminosity);
|
||||
|
||||
return getColor(hue, saturation, brightness);
|
||||
}
|
||||
|
||||
public int randomColor(Color color, SaturationType saturationType, Luminosity luminosity) {
|
||||
int hue = pickHue(color.name());
|
||||
int saturation = pickSaturation(hue, saturationType, luminosity);
|
||||
int brightness = pickBrightness(hue, saturation, luminosity);
|
||||
|
||||
return getColor(hue, saturation, brightness);
|
||||
}
|
||||
|
||||
public int[] randomColor(int count) {
|
||||
if (count <= 0) {
|
||||
throw new IllegalArgumentException("count must be greater than 0");
|
||||
}
|
||||
|
||||
int[] colors = new int[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
colors[i] = randomColor();
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
public int randomColor(Color color) {
|
||||
int hue = pickHue(color.name());
|
||||
int saturation = pickSaturation(color, null, null);
|
||||
int brightness = pickBrightness(color, saturation, null);
|
||||
|
||||
int colorValue = getColor(hue, saturation, brightness);
|
||||
return colorValue;
|
||||
}
|
||||
|
||||
public int[] random(Color color, int count) {
|
||||
if (count <= 0) {
|
||||
throw new IllegalArgumentException("count must be greater than 0");
|
||||
}
|
||||
|
||||
int[] colors = new int[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
colors[i] = randomColor(color);
|
||||
}
|
||||
|
||||
return colors;
|
||||
}
|
||||
|
||||
private int pickHue(int hue) {
|
||||
Range hueRange = getHueRange(hue);
|
||||
return doPickHue(hueRange);
|
||||
}
|
||||
|
||||
private int doPickHue(Range hueRange) {
|
||||
int hue = randomWithin(hueRange);
|
||||
|
||||
// Instead of storing red as two seperate ranges,
|
||||
// we group them, using negative numbers
|
||||
if (hue < 0) {
|
||||
hue = 360 + hue;
|
||||
}
|
||||
|
||||
return hue;
|
||||
}
|
||||
|
||||
private int pickHue(String name) {
|
||||
Range hueRange = getHueRange(name);
|
||||
return doPickHue(hueRange);
|
||||
}
|
||||
|
||||
private Range getHueRange(int number) {
|
||||
if (number < 360 && number > 0) {
|
||||
return new Range(number, number);
|
||||
}
|
||||
|
||||
return new Range(0, 360);
|
||||
}
|
||||
|
||||
private Range getHueRange(String name) {
|
||||
if (colors.containsKey(name)) {
|
||||
return colors.get(name).getHueRange();
|
||||
}
|
||||
|
||||
return new Range(0, 360);
|
||||
}
|
||||
|
||||
private int pickSaturation(int hue, SaturationType saturationType, Luminosity luminosity) {
|
||||
return pickSaturation(getColorInfo(hue), saturationType, luminosity);
|
||||
}
|
||||
|
||||
private int pickSaturation(Color color, SaturationType saturationType, Luminosity luminosity) {
|
||||
ColorInfo colorInfo = colors.get(color.name());
|
||||
return pickSaturation(colorInfo, saturationType, luminosity);
|
||||
}
|
||||
|
||||
private int pickSaturation(ColorInfo colorInfo, SaturationType saturationType, Luminosity luminosity) {
|
||||
if (saturationType != null) {
|
||||
switch (saturationType) {
|
||||
case RANDOM:
|
||||
return randomWithin(new Range(0, 100));
|
||||
case MONOCHROME:
|
||||
return 0;
|
||||
case HIGH:
|
||||
return randomWithin(new Range(75, 100));
|
||||
case MEDIUM:
|
||||
return randomWithin(new Range(55, 75));
|
||||
case LOW:
|
||||
return randomWithin(new Range(35, 55));
|
||||
}
|
||||
}
|
||||
|
||||
if (colorInfo == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Range saturationRange = colorInfo.getSaturationRange();
|
||||
|
||||
int min = saturationRange.start;
|
||||
int max = saturationRange.end;
|
||||
|
||||
if (luminosity != null) {
|
||||
switch (luminosity) {
|
||||
case LIGHT:
|
||||
min = 55;
|
||||
break;
|
||||
case BRIGHT:
|
||||
min = max - 10;
|
||||
break;
|
||||
case DARK:
|
||||
max = 55;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return randomWithin(new Range(min, max));
|
||||
}
|
||||
|
||||
private int pickBrightness(int hue, int saturation, Luminosity luminosity) {
|
||||
ColorInfo colorInfo = getColorInfo(hue);
|
||||
|
||||
return pickBrightness(colorInfo, saturation, luminosity);
|
||||
}
|
||||
|
||||
private int pickBrightness(Color color, int saturation, Luminosity luminosity) {
|
||||
ColorInfo colorInfo = colors.get(color.name());
|
||||
|
||||
return pickBrightness(colorInfo, saturation, luminosity);
|
||||
}
|
||||
|
||||
private int pickBrightness(ColorInfo colorInfo, int saturation, Luminosity luminosity) {
|
||||
int min = getMinimumBrightness(colorInfo, saturation),
|
||||
max = 100;
|
||||
|
||||
if (luminosity != null) {
|
||||
switch (luminosity) {
|
||||
|
||||
case DARK:
|
||||
max = min + 20;
|
||||
break;
|
||||
|
||||
case LIGHT:
|
||||
min = (max + min) / 2;
|
||||
break;
|
||||
|
||||
case RANDOM:
|
||||
min = 0;
|
||||
max = 100;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return randomWithin(new Range(min, max));
|
||||
}
|
||||
|
||||
private int getMinimumBrightness(ColorInfo colorInfo, int saturation) {
|
||||
if (colorInfo == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
List<Range> lowerBounds = colorInfo.getLowerBounds();
|
||||
for (int i = 0; i < lowerBounds.size() - 1; i++) {
|
||||
|
||||
int s1 = lowerBounds.get(i).start,
|
||||
v1 = lowerBounds.get(i).end;
|
||||
|
||||
if (i == lowerBounds.size() - 1) {
|
||||
break;
|
||||
}
|
||||
int s2 = lowerBounds.get(i + 1).start,
|
||||
v2 = lowerBounds.get(i + 1).end;
|
||||
|
||||
if (saturation >= s1 && saturation <= s2) {
|
||||
|
||||
float m = (v2 - v1)/(float) (s2 - s1),
|
||||
b = v1 - m*s1;
|
||||
|
||||
return (int) (m*saturation + b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private ColorInfo getColorInfo(int hue) {
|
||||
// Maps red colors to make picking hue easier
|
||||
if (hue >= 334 && hue <= 360) {
|
||||
hue-= 360;
|
||||
}
|
||||
|
||||
for(String key : colors.keySet()) {
|
||||
ColorInfo colorInfo = colors.get(key);
|
||||
if (colorInfo.getHueRange() != null && colorInfo.getHueRange().contain(hue)) {
|
||||
return colorInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private int randomWithin (Range range) {
|
||||
return (int) Math.floor(range.start + random.nextDouble()*(range.end + 1 - range.start));
|
||||
}
|
||||
|
||||
public void defineColor(String name, Range hueRange, List<Range> lowerBounds) {
|
||||
int sMin = lowerBounds.get(0).start;
|
||||
int sMax = lowerBounds.get(lowerBounds.size() - 1).start;
|
||||
int bMin = lowerBounds.get(lowerBounds.size() - 1).end;
|
||||
int bMax = lowerBounds.get(0).end;
|
||||
|
||||
colors.put(name, new ColorInfo(hueRange, new Range(sMin, sMax), new Range(bMin, bMax), lowerBounds));
|
||||
}
|
||||
|
||||
private void loadColorBounds() {
|
||||
List<Range> lowerBounds1 = new ArrayList<>();
|
||||
lowerBounds1.add(new Range(0, 0));
|
||||
lowerBounds1.add(new Range(100, 0));
|
||||
defineColor(
|
||||
Color.MONOCHROME.name(),
|
||||
new Range(0, 0),
|
||||
lowerBounds1
|
||||
);
|
||||
|
||||
List<Range> lowerBounds2 = new ArrayList<>();
|
||||
lowerBounds2.add(new Range(20, 100));
|
||||
lowerBounds2.add(new Range(30, 92));
|
||||
lowerBounds2.add(new Range(40, 89));
|
||||
lowerBounds2.add(new Range(50, 85));
|
||||
lowerBounds2.add(new Range(60, 78));
|
||||
lowerBounds2.add(new Range(70, 70));
|
||||
lowerBounds2.add(new Range(80, 60));
|
||||
lowerBounds2.add(new Range(90, 55));
|
||||
lowerBounds2.add(new Range(100, 50));
|
||||
defineColor(
|
||||
Color.RED.name(),
|
||||
new Range(-26, 18),
|
||||
lowerBounds2
|
||||
);
|
||||
|
||||
List<Range> lowerBounds3 = new ArrayList<Range>();
|
||||
lowerBounds3.add(new Range(20, 100));
|
||||
lowerBounds3.add(new Range(30, 93));
|
||||
lowerBounds3.add(new Range(40, 88));
|
||||
lowerBounds3.add(new Range(50, 86));
|
||||
lowerBounds3.add(new Range(60, 85));
|
||||
lowerBounds3.add(new Range(70, 70));
|
||||
lowerBounds3.add(new Range(100, 70));
|
||||
defineColor(
|
||||
Color.ORANGE.name(),
|
||||
new Range(19, 46),
|
||||
lowerBounds3
|
||||
);
|
||||
|
||||
List<Range> lowerBounds4 = new ArrayList<>();
|
||||
lowerBounds4.add(new Range(25, 100));
|
||||
lowerBounds4.add(new Range(40, 94));
|
||||
lowerBounds4.add(new Range(50, 89));
|
||||
lowerBounds4.add(new Range(60, 86));
|
||||
lowerBounds4.add(new Range(70, 84));
|
||||
lowerBounds4.add(new Range(80, 82));
|
||||
lowerBounds4.add(new Range(90, 80));
|
||||
lowerBounds4.add(new Range(100, 75));
|
||||
|
||||
defineColor(
|
||||
Color.YELLOW.name(),
|
||||
new Range(47, 62),
|
||||
lowerBounds4
|
||||
);
|
||||
|
||||
List<Range> lowerBounds5 = new ArrayList<>();
|
||||
lowerBounds5.add(new Range(30, 100));
|
||||
lowerBounds5.add(new Range(40, 90));
|
||||
lowerBounds5.add(new Range(50, 85));
|
||||
lowerBounds5.add(new Range(60, 81));
|
||||
lowerBounds5.add(new Range(70, 74));
|
||||
lowerBounds5.add(new Range(80, 64));
|
||||
lowerBounds5.add(new Range(90, 50));
|
||||
lowerBounds5.add(new Range(100, 40));
|
||||
|
||||
defineColor(
|
||||
Color.GREEN.name(),
|
||||
new Range(63,178),
|
||||
lowerBounds5
|
||||
);
|
||||
|
||||
List<Range> lowerBounds6 = new ArrayList<>();
|
||||
lowerBounds6.add(new Range(20, 100));
|
||||
lowerBounds6.add(new Range(30, 86));
|
||||
lowerBounds6.add(new Range(40, 80));
|
||||
lowerBounds6.add(new Range(50, 74));
|
||||
lowerBounds6.add(new Range(60, 60));
|
||||
lowerBounds6.add(new Range(70, 52));
|
||||
lowerBounds6.add(new Range(80, 44));
|
||||
lowerBounds6.add(new Range(90, 39));
|
||||
lowerBounds6.add(new Range(100, 35));
|
||||
|
||||
defineColor(
|
||||
Color.BLUE.name(),
|
||||
new Range(179, 257),
|
||||
lowerBounds6
|
||||
);
|
||||
|
||||
List<Range> lowerBounds7 = new ArrayList<>();
|
||||
lowerBounds7.add(new Range(20, 100));
|
||||
lowerBounds7.add(new Range(30, 87));
|
||||
lowerBounds7.add(new Range(40, 79));
|
||||
lowerBounds7.add(new Range(50, 70));
|
||||
lowerBounds7.add(new Range(60, 65));
|
||||
lowerBounds7.add(new Range(70, 59));
|
||||
lowerBounds7.add(new Range(80, 52));
|
||||
lowerBounds7.add(new Range(90, 45));
|
||||
lowerBounds7.add(new Range(100, 42));
|
||||
|
||||
defineColor(
|
||||
Color.PURPLE.name(),
|
||||
new Range(258, 282),
|
||||
lowerBounds7
|
||||
);
|
||||
|
||||
List<Range> lowerBounds8 = new ArrayList<>();
|
||||
lowerBounds8.add(new Range(20, 100));
|
||||
lowerBounds8.add(new Range(30, 90));
|
||||
lowerBounds8.add(new Range(40, 86));
|
||||
lowerBounds8.add(new Range(60, 84));
|
||||
lowerBounds8.add(new Range(80, 80));
|
||||
lowerBounds8.add(new Range(90, 75));
|
||||
lowerBounds8.add(new Range(100, 73));
|
||||
|
||||
defineColor(
|
||||
Color.PINK.name(),
|
||||
new Range(283, 334),
|
||||
lowerBounds8
|
||||
);
|
||||
}
|
||||
|
||||
public static enum Color {
|
||||
MONOCHROME, RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE, PINK
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
128
src/main/java/com/volmit/iris/util/VanillaBiomeMap.java
Normal file
128
src/main/java/com/volmit/iris/util/VanillaBiomeMap.java
Normal file
@ -0,0 +1,128 @@
|
||||
package com.volmit.iris.util;
|
||||
|
||||
import org.apache.commons.lang3.tuple.ImmutableTriple;
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.bukkit.block.Biome;
|
||||
import com.volmit.iris.util.RandomColor.*;
|
||||
|
||||
public class VanillaBiomeMap {
|
||||
|
||||
private static KMap<Biome, Integer> BIOME_HEX = new KMap<>();
|
||||
private static KMap<Biome, Color> BIOME_COLOR = new KMap<>();
|
||||
private static KMap<Biome, Luminosity> BIOME_LUMINOSITY = new KMap<>();
|
||||
private static KMap<Biome, SaturationType> BIOME_SATURATION = new KMap<>();
|
||||
private static KMap<Biome, Short> BIOME_IDs = new KMap<>();
|
||||
|
||||
private static void add(Biome biome, int color, short id, Color randomColor, Luminosity luminosity, SaturationType saturation) {
|
||||
BIOME_HEX.put(biome, color);
|
||||
BIOME_COLOR.put(biome, randomColor);
|
||||
if (luminosity != null) BIOME_LUMINOSITY.put(biome, luminosity);
|
||||
if (saturation != null) BIOME_SATURATION.put(biome, saturation);
|
||||
BIOME_IDs.put(biome, id);
|
||||
}
|
||||
|
||||
private static void add(Biome biome, int color, short id, Color randomColor, Luminosity luminosity) {
|
||||
add(biome, color, id, randomColor, luminosity, null);
|
||||
}
|
||||
|
||||
public static int getColor(Biome biome) {
|
||||
return BIOME_HEX.get(biome);
|
||||
}
|
||||
|
||||
public static Color getColorType(Biome biome) {
|
||||
return BIOME_COLOR.get(biome);
|
||||
}
|
||||
|
||||
public static Luminosity getColorLuminosity(Biome biome) {
|
||||
return BIOME_LUMINOSITY.get(biome);
|
||||
}
|
||||
|
||||
public static SaturationType getColorSaturatiom(Biome biome) {
|
||||
return BIOME_SATURATION.get(biome);
|
||||
}
|
||||
|
||||
public static short getId(Biome biome) {
|
||||
return BIOME_IDs.get(biome);
|
||||
}
|
||||
|
||||
static {
|
||||
add(Biome.OCEAN, 0x000070, (short) 0, Color.BLUE, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.PLAINS, 0x8DB360, (short) 1, Color.GREEN, Luminosity.LIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.DESERT, 0xFA9418, (short) 2, Color.YELLOW, Luminosity.LIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.MOUNTAINS, 0x606060, (short) 3, Color.MONOCHROME, Luminosity.BRIGHT, null);
|
||||
add(Biome.FOREST, 0x056621, (short) 4, Color.GREEN, Luminosity.BRIGHT);
|
||||
add(Biome.TAIGA, 0x0B6659, (short) 5, Color.GREEN, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.SWAMP, 0x07F9B2, (short) 6, Color.ORANGE, Luminosity.DARK, SaturationType.MEDIUM);
|
||||
add(Biome.RIVER, 0x0000FF, (short) 7, Color.BLUE, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.NETHER_WASTES, 0xBF3B3B, (short) 8, Color.RED, Luminosity.LIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.THE_END, 0x8080FF, (short) 9, Color.PURPLE, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.FROZEN_OCEAN, 0x7070D6, (short) 10, Color.BLUE, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.FROZEN_RIVER, 0xA0A0FF, (short) 11, Color.BLUE, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.SNOWY_TUNDRA, 0xFFFFFF, (short) 12, Color.MONOCHROME, Luminosity.LIGHT);
|
||||
add(Biome.SNOWY_MOUNTAINS, 0xA0A0A0, (short) 13, Color.MONOCHROME, Luminosity.LIGHT);
|
||||
add(Biome.MUSHROOM_FIELDS, 0xFF00FF, (short) 14, Color.PURPLE, Luminosity.BRIGHT);
|
||||
add(Biome.MUSHROOM_FIELD_SHORE, 0xA000FF, (short) 15, Color.PURPLE, Luminosity.BRIGHT);
|
||||
add(Biome.BEACH, 0xFADE55, (short) 16, Color.YELLOW, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.DESERT_HILLS, 0xD25F12, (short) 17, Color.YELLOW, Luminosity.LIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.WOODED_HILLS, 0x22551C, (short) 18, Color.GREEN, Luminosity.LIGHT);
|
||||
add(Biome.TAIGA_HILLS, 0x163933, (short) 19, Color.GREEN, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.MOUNTAIN_EDGE, 0x72789A, (short) 20, Color.MONOCHROME, Luminosity.BRIGHT);
|
||||
add(Biome.JUNGLE, 0x537B09, (short) 21, Color.GREEN, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.JUNGLE_HILLS, 0x2C4205, (short) 22, Color.GREEN, Luminosity.DARK, SaturationType.HIGH);
|
||||
add(Biome.JUNGLE_EDGE, 0x628B17, (short) 23, Color.GREEN, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.DEEP_OCEAN, 0x000030, (short) 24, Color.BLUE, Luminosity.DARK);
|
||||
add(Biome.STONE_SHORE, 0xA2A284, (short) 25, Color.GREEN, Luminosity.DARK);
|
||||
add(Biome.SNOWY_BEACH, 0xFAF0C0, (short) 26, Color.YELLOW, Luminosity.LIGHT);
|
||||
add(Biome.BIRCH_FOREST, 0x307444, (short) 27, Color.GREEN, Luminosity.LIGHT);
|
||||
add(Biome.BIRCH_FOREST_HILLS, 0x1F5F32, (short) 28, Color.GREEN, Luminosity.LIGHT);
|
||||
add(Biome.DARK_FOREST, 0x40511A, (short) 29, Color.GREEN, Luminosity.DARK);
|
||||
add(Biome.SNOWY_TAIGA, 0x31554A, (short) 30, Color.BLUE, Luminosity.LIGHT);
|
||||
add(Biome.SNOWY_TAIGA_HILLS, 0x243F36, (short) 31, Color.BLUE, Luminosity.LIGHT);
|
||||
add(Biome.GIANT_TREE_TAIGA, 0x596651, (short) 32, Color.ORANGE, Luminosity.LIGHT);
|
||||
add(Biome.GIANT_TREE_TAIGA_HILLS, 0x454F3E, (short) 33, Color.ORANGE, Luminosity.LIGHT);
|
||||
add(Biome.WOODED_MOUNTAINS, 0x507050, (short) 34, Color.MONOCHROME, Luminosity.BRIGHT);
|
||||
add(Biome.SAVANNA, 0xBDB25F, (short) 35, Color.GREEN, Luminosity.LIGHT);
|
||||
add(Biome.SAVANNA_PLATEAU, 0xA79D64, (short) 36, Color.GREEN, Luminosity.LIGHT);
|
||||
add(Biome.BADLANDS, 0xD94515, (short) 37, Color.ORANGE, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.WOODED_BADLANDS_PLATEAU, 0xB09765, (short) 38, Color.ORANGE, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.BADLANDS_PLATEAU, 0xCA8C65, (short) 39, Color.ORANGE, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.END_MIDLANDS, 0x8080FF, (short) 41, Color.YELLOW, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.END_HIGHLANDS, 0x8080FF, (short) 42, Color.PURPLE, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.END_BARRENS, 0x8080FF, (short) 43, Color.PURPLE, Luminosity.LIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.WARM_OCEAN, 0x0000AC, (short) 44, Color.BLUE, Luminosity.BRIGHT, SaturationType.LOW);
|
||||
add(Biome.LUKEWARM_OCEAN, 0x000090, (short) 45, Color.BLUE, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.COLD_OCEAN, 0x202070, (short) 46, Color.BLUE, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.DEEP_WARM_OCEAN, 0x000050, (short) 47, Color.BLUE, Luminosity.DARK, SaturationType.LOW);
|
||||
add(Biome.DEEP_LUKEWARM_OCEAN, 0x000040, (short) 48, Color.BLUE, Luminosity.DARK, SaturationType.MEDIUM);
|
||||
add(Biome.DEEP_COLD_OCEAN, 0x202038, (short) 49, Color.BLUE, Luminosity.DARK, SaturationType.HIGH);
|
||||
add(Biome.DEEP_FROZEN_OCEAN, 0x404090, (short) 50, Color.BLUE, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.THE_VOID, 0x000000, (short) 127, Color.MONOCHROME, Luminosity.DARK);
|
||||
add(Biome.SUNFLOWER_PLAINS, 0xB5DB88, (short) 129, Color.GREEN, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.DESERT_LAKES, 0xFFBC40, (short) 130, Color.BLUE, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.GRAVELLY_MOUNTAINS, 0x888888, (short) 131, Color.MONOCHROME, Luminosity.LIGHT);
|
||||
add(Biome.FLOWER_FOREST, 0x2D8E49, (short) 132, Color.RED, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.TAIGA_MOUNTAINS, 0x338E81, (short) 133, Color.GREEN, Luminosity.DARK, SaturationType.MEDIUM);
|
||||
add(Biome.SWAMP_HILLS, 0x2FFFDA, (short) 134, Color.ORANGE, Luminosity.DARK, SaturationType.MEDIUM);
|
||||
add(Biome.ICE_SPIKES, 0xB4DCDC, (short) 140, Color.BLUE, Luminosity.LIGHT, SaturationType.LOW);
|
||||
add(Biome.MODIFIED_JUNGLE, 0x7BA331, (short) 149, Color.GREEN, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.MODIFIED_JUNGLE_EDGE, 0x8AB33F, (short) 151, Color.GREEN, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.TALL_BIRCH_FOREST, 0x589C6C, (short) 155, Color.GREEN, Luminosity.LIGHT);
|
||||
add(Biome.TALL_BIRCH_HILLS, 0x47875A, (short) 156, Color.GREEN, Luminosity.LIGHT);
|
||||
add(Biome.DARK_FOREST_HILLS, 0x687942, (short) 157, Color.GREEN, Luminosity.DARK);
|
||||
add(Biome.SNOWY_TAIGA_MOUNTAINS, 0x597D72, (short) 158, Color.BLUE, Luminosity.LIGHT);
|
||||
add(Biome.GIANT_SPRUCE_TAIGA, 0x818E79, (short) 160, Color.ORANGE, Luminosity.DARK, SaturationType.HIGH);
|
||||
add(Biome.GIANT_SPRUCE_TAIGA_HILLS, 0x6D7766, (short) 161, Color.ORANGE, Luminosity.DARK, SaturationType.HIGH);
|
||||
add(Biome.GRAVELLY_MOUNTAINS, 0x789878, (short) 162, Color.MONOCHROME, Luminosity.LIGHT);
|
||||
add(Biome.SHATTERED_SAVANNA, 0xE5DA87, (short) 163, Color.ORANGE, Luminosity.LIGHT, SaturationType.HIGH);
|
||||
add(Biome.SHATTERED_SAVANNA_PLATEAU, 0xCFC58C, (short) 164, Color.ORANGE, Luminosity.LIGHT, SaturationType.HIGH);
|
||||
add(Biome.ERODED_BADLANDS, 0xFF6D3D, (short) 165, Color.ORANGE, Luminosity.LIGHT, SaturationType.HIGH);
|
||||
add(Biome.MODIFIED_WOODED_BADLANDS_PLATEAU, 0xD8BF8D, (short) 166, Color.ORANGE, Luminosity.BRIGHT);
|
||||
add(Biome.MODIFIED_BADLANDS_PLATEAU, 0xF2B48D, (short) 167, Color.ORANGE, Luminosity.BRIGHT);
|
||||
add(Biome.BAMBOO_JUNGLE, 0x768E14, (short) 168, Color.GREEN, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.BAMBOO_JUNGLE_HILLS, 0x3B470A, (short) 169, Color.GREEN, Luminosity.BRIGHT, SaturationType.HIGH);
|
||||
add(Biome.SOUL_SAND_VALLEY, 0x5E3830, (short) 170, Color.BLUE, Luminosity.BRIGHT, SaturationType.MEDIUM);
|
||||
add(Biome.CRIMSON_FOREST, 0xDD0808, (short) 171, Color.RED, Luminosity.DARK, SaturationType.HIGH);
|
||||
add(Biome.WARPED_FOREST, 0x49907B, (short) 172, Color.BLUE, Luminosity.BRIGHT);
|
||||
add(Biome.BASALT_DELTAS, 0x403636, (short) 173, Color.MONOCHROME, Luminosity.DARK);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user