mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-18 18:23:06 +00:00
commit
2c1d4cfc40
@ -19,8 +19,13 @@
|
|||||||
package com.volmit.iris.core.command.world;
|
package com.volmit.iris.core.command.world;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.gui.PregeneratorJob;
|
||||||
import com.volmit.iris.core.gui.components.Pregenerator;
|
import com.volmit.iris.core.gui.components.Pregenerator;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
|
import com.volmit.iris.core.pregenerator.methods.HybridPregenMethod;
|
||||||
|
import com.volmit.iris.core.pregenerator.methods.PaperOrMedievalPregenMethod;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.math.Position2;
|
||||||
import com.volmit.iris.util.plugin.MortarCommand;
|
import com.volmit.iris.util.plugin.MortarCommand;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -69,17 +74,17 @@ public class CommandIrisPregen extends MortarCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args[0].equalsIgnoreCase("stop") || args[0].equalsIgnoreCase("x")) {
|
if (args[0].equalsIgnoreCase("stop") || args[0].equalsIgnoreCase("x")) {
|
||||||
if (Pregenerator.shutdownInstance()) {
|
if (PregeneratorJob.shutdownInstance()) {
|
||||||
sender.sendMessage("Stopped Pregen.");
|
sender.sendMessage("Stopped Pregen.");
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage("No Active Pregens.");
|
sender.sendMessage("No Active Pregens.");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else if (args[0].equalsIgnoreCase("pause") || args[0].equalsIgnoreCase("resume")) {
|
} else if (args[0].equalsIgnoreCase("pause") || args[0].equalsIgnoreCase("resume")) {
|
||||||
if (Pregenerator.getInstance() != null) {
|
if (PregeneratorJob.getInstance() != null) {
|
||||||
Pregenerator.pauseResume();
|
PregeneratorJob.pauseResume();
|
||||||
|
|
||||||
if (Pregenerator.isPaused()) {
|
if (PregeneratorJob.isPaused()) {
|
||||||
sender.sendMessage("Pregen Paused");
|
sender.sendMessage("Pregen Paused");
|
||||||
} else {
|
} else {
|
||||||
sender.sendMessage("Pregen Resumed");
|
sender.sendMessage("Pregen Resumed");
|
||||||
@ -105,7 +110,12 @@ public class CommandIrisPregen extends MortarCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
new Pregenerator(world, getVal(args[0]) * 2);
|
new PregeneratorJob(PregenTask
|
||||||
|
.builder()
|
||||||
|
.center(new Position2(0, 0))
|
||||||
|
.radius(((getVal(args[0])>>4)>>5) + 1)
|
||||||
|
.build(),
|
||||||
|
new HybridPregenMethod(world, Runtime.getRuntime().availableProcessors()));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
sender.sendMessage("Invalid argument in command");
|
sender.sendMessage("Invalid argument in command");
|
||||||
@ -131,7 +141,12 @@ public class CommandIrisPregen extends MortarCommand {
|
|||||||
}
|
}
|
||||||
World world = Bukkit.getWorld(args[1]);
|
World world = Bukkit.getWorld(args[1]);
|
||||||
try {
|
try {
|
||||||
new Pregenerator(world, getVal(args[0]) * 2);
|
new PregeneratorJob(PregenTask
|
||||||
|
.builder()
|
||||||
|
.center(new Position2(0, 0))
|
||||||
|
.radius(((getVal(args[0])>>4)>>5) + 1)
|
||||||
|
.build(),
|
||||||
|
new HybridPregenMethod(world, Runtime.getRuntime().availableProcessors()));
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
sender.sendMessage("Invalid argument in command");
|
sender.sendMessage("Invalid argument in command");
|
||||||
|
351
src/main/java/com/volmit/iris/core/gui/PregeneratorJob.java
Normal file
351
src/main/java/com/volmit/iris/core/gui/PregeneratorJob.java
Normal file
@ -0,0 +1,351 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.gui;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.core.pregenerator.IrisPregenerator;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.format.Form;
|
||||||
|
import com.volmit.iris.util.function.Consumer2;
|
||||||
|
import com.volmit.iris.util.math.M;
|
||||||
|
import com.volmit.iris.util.math.Position2;
|
||||||
|
import com.volmit.iris.util.math.Spiraler;
|
||||||
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.KeyListener;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
public class PregeneratorJob implements PregenListener {
|
||||||
|
public static PregeneratorJob instance;
|
||||||
|
private static final Color COLOR_GENERATING = parseColor("#346beb");
|
||||||
|
private static final Color COLOR_GENERATED = parseColor("#34eb93");
|
||||||
|
private JFrame frame;
|
||||||
|
private final PregenTask task;
|
||||||
|
private boolean saving;
|
||||||
|
private final IrisPregenerator pregenerator;
|
||||||
|
private PregenRenderer renderer;
|
||||||
|
private String[] info;
|
||||||
|
private Position2 min;
|
||||||
|
private Position2 max;
|
||||||
|
|
||||||
|
public PregeneratorJob(PregenTask task, PregeneratorMethod method)
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
saving = false;
|
||||||
|
info = new String[]{"Initializing..."};
|
||||||
|
this.task = task;
|
||||||
|
this.pregenerator = new IrisPregenerator(task, method, this);
|
||||||
|
J.a(this.pregenerator::start);
|
||||||
|
max = new Position2(0, 0);
|
||||||
|
min = new Position2(0, 0);
|
||||||
|
KList<Runnable> draw = new KList<>();
|
||||||
|
task.iterateRegions((xx,zz) -> {
|
||||||
|
min.setX(Math.min(xx << 5, min.getX()));
|
||||||
|
min.setZ(Math.min(zz << 5, min.getZ()));
|
||||||
|
max.setX(Math.max((xx << 5) + 31, max.getX()));
|
||||||
|
max.setZ(Math.max((zz << 5) + 31, max.getZ()));
|
||||||
|
});
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shutdownInstance() {
|
||||||
|
if(instance == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
J.a(() -> instance.pregenerator.close());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PregeneratorJob getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void pauseResume() {
|
||||||
|
if(instance == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isPaused())
|
||||||
|
{
|
||||||
|
instance.pregenerator.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
instance.pregenerator.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isPaused() {
|
||||||
|
if(instance == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance.paused();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw(int x, int z, Color color)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(renderer != null && frame != null && frame.isVisible())
|
||||||
|
{
|
||||||
|
renderer.func.accept(new Position2(x, z), color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
catch(Throwable ignored)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop()
|
||||||
|
{
|
||||||
|
J.a(() -> {
|
||||||
|
pregenerator.close();
|
||||||
|
close();
|
||||||
|
instance = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
J.a(() -> {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
J.sleep(3000);
|
||||||
|
frame.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch(Throwable e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void open()
|
||||||
|
{
|
||||||
|
J.a(() -> {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
frame = new JFrame("Pregen View");
|
||||||
|
renderer = new PregenRenderer();
|
||||||
|
frame.addKeyListener(renderer);
|
||||||
|
renderer.l = new ReentrantLock();
|
||||||
|
renderer.frame = frame;
|
||||||
|
renderer.job = this;
|
||||||
|
renderer.func = (c, b) ->
|
||||||
|
{
|
||||||
|
renderer.l.lock();
|
||||||
|
renderer.order.add(() -> renderer.draw(c, b, renderer.bg));
|
||||||
|
renderer.l.unlock();
|
||||||
|
};
|
||||||
|
frame.add(renderer);
|
||||||
|
frame.setSize(1000, 1000);
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch(Throwable e)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
|
||||||
|
info = new String[] {
|
||||||
|
(paused() ? "PAUSED" : (saving ? "Saving... " : "Generating")) + " " + Form.f(generated) + " of " + Form.f(totalChunks) + " (" + Form.pc(percent, 0) + " Complete)",
|
||||||
|
"Speed: " + Form.f(chunksPerSecond, 0) + " Chunks/s, " + Form.f(regionsPerMinute, 1) + " Regions/m, " + Form.f(chunksPerMinute, 0) + " Chunks/m",
|
||||||
|
Form.duration(eta, 2) + " Remaining " + " (" + Form.duration(elapsed, 2) + " Elapsed)",
|
||||||
|
"Generation Method: " + method,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChunkGenerating(int x, int z) {
|
||||||
|
draw(x, z, COLOR_GENERATING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChunkGenerated(int x, int z) {
|
||||||
|
draw(x, z, COLOR_GENERATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegionGenerated(int x, int z) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegionGenerating(int x, int z) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegionSkipped(int x, int z) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
close();
|
||||||
|
instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaving() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private Position2 getMax() {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Position2 getMin() {
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean paused() {
|
||||||
|
return pregenerator.paused();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] getProgress() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PregenRenderer extends JPanel implements KeyListener {
|
||||||
|
private PregeneratorJob job;
|
||||||
|
private static final long serialVersionUID = 2094606939770332040L;
|
||||||
|
private final KList<Runnable> order = new KList<>();
|
||||||
|
private final int res = 512;
|
||||||
|
Graphics2D bg;
|
||||||
|
private ReentrantLock l;
|
||||||
|
private final BufferedImage image = new BufferedImage(res, res, BufferedImage.TYPE_INT_RGB);
|
||||||
|
private Consumer2<Position2, Color> func;
|
||||||
|
private JFrame frame;
|
||||||
|
|
||||||
|
public PregenRenderer() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paint(int x, int z, Color c) {
|
||||||
|
func.accept(new Position2(x, z), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint(Graphics gx) {
|
||||||
|
Graphics2D g = (Graphics2D) gx;
|
||||||
|
bg = (Graphics2D) image.getGraphics();
|
||||||
|
l.lock();
|
||||||
|
|
||||||
|
while (order.isNotEmpty()) {
|
||||||
|
try {
|
||||||
|
order.pop().run();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
l.unlock();
|
||||||
|
g.drawImage(image, 0, 0, getParent().getWidth(), getParent().getHeight(), (img, infoflags, x, y, width, height) -> true);
|
||||||
|
g.setColor(Color.WHITE);
|
||||||
|
g.setFont(new Font("Hevetica", Font.BOLD, 28));
|
||||||
|
String[] prog = job.getProgress();
|
||||||
|
int h = g.getFontMetrics().getHeight() + 5;
|
||||||
|
int hh = 20;
|
||||||
|
|
||||||
|
if (job.paused()) {
|
||||||
|
g.drawString("PAUSED", 20, hh += h);
|
||||||
|
|
||||||
|
g.drawString("Press P to Resume", 20, hh += h);
|
||||||
|
} else {
|
||||||
|
for (String i : prog) {
|
||||||
|
g.drawString(i, 20, hh += h);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.drawString("Press P to Pause", 20, hh += h);
|
||||||
|
}
|
||||||
|
|
||||||
|
J.sleep(IrisSettings.get().getGui().isMaximumPregenGuiFPS() ? 4 : 250);
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void draw(Position2 p, Color c, Graphics2D bg) {
|
||||||
|
double pw = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX());
|
||||||
|
double ph = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ());
|
||||||
|
double pwa = M.lerpInverse(job.getMin().getX(), job.getMax().getX(), p.getX() + 1);
|
||||||
|
double pha = M.lerpInverse(job.getMin().getZ(), job.getMax().getZ(), p.getZ() + 1);
|
||||||
|
int x = (int) M.lerp(0, res, pw);
|
||||||
|
int z = (int) M.lerp(0, res, ph);
|
||||||
|
int xa = (int) M.lerp(0, res, pwa);
|
||||||
|
int za = (int) M.lerp(0, res, pha);
|
||||||
|
bg.setColor(c);
|
||||||
|
bg.fillRect(x, z, xa - x, za - z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyTyped(KeyEvent e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_P) {
|
||||||
|
PregeneratorJob.pauseResume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
frame.setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color parseColor(String c) {
|
||||||
|
String v = (c.startsWith("#") ? c : "#" + c).trim();
|
||||||
|
try {
|
||||||
|
return Color.decode(v);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
Iris.error("Error Parsing 'color', (" + c + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color.RED;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator;
|
||||||
|
|
||||||
|
import com.volmit.iris.util.math.M;
|
||||||
|
import com.volmit.iris.util.math.RollingSequence;
|
||||||
|
import com.volmit.iris.util.scheduling.ChronoLatch;
|
||||||
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import com.volmit.iris.util.scheduling.Looper;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
public class IrisPregenerator {
|
||||||
|
private final PregenTask task;
|
||||||
|
private final PregeneratorMethod generator;
|
||||||
|
private final PregenListener listener;
|
||||||
|
private final Looper ticker;
|
||||||
|
private final AtomicBoolean paused;
|
||||||
|
private final AtomicBoolean shutdown;
|
||||||
|
private final RollingSequence chunksPerSecond;
|
||||||
|
private final RollingSequence chunksPerMinute;
|
||||||
|
private final RollingSequence regionsPerMinute;
|
||||||
|
private final AtomicInteger generated;
|
||||||
|
private final AtomicInteger generatedLast;
|
||||||
|
private final AtomicInteger generatedLastMinute;
|
||||||
|
private final AtomicInteger totalChunks;
|
||||||
|
private final AtomicLong startTime;
|
||||||
|
private final ChronoLatch minuteLatch;
|
||||||
|
private final AtomicReference<String> currentGeneratorMethod;
|
||||||
|
|
||||||
|
public IrisPregenerator(PregenTask task, PregeneratorMethod generator, PregenListener listener)
|
||||||
|
{
|
||||||
|
this.listener = listenify(listener);
|
||||||
|
this.shutdown = new AtomicBoolean(false);
|
||||||
|
this.paused = new AtomicBoolean(false);
|
||||||
|
this.task = task;
|
||||||
|
this.generator = generator;
|
||||||
|
currentGeneratorMethod = new AtomicReference<>("Void");
|
||||||
|
minuteLatch = new ChronoLatch(60000, false);
|
||||||
|
chunksPerSecond = new RollingSequence(10);
|
||||||
|
chunksPerMinute = new RollingSequence(10);
|
||||||
|
regionsPerMinute = new RollingSequence(10);
|
||||||
|
generated = new AtomicInteger(0);
|
||||||
|
generatedLast = new AtomicInteger(0);
|
||||||
|
generatedLastMinute = new AtomicInteger(0);
|
||||||
|
totalChunks = new AtomicInteger(0);
|
||||||
|
task.iterateRegions((_a, _b) -> totalChunks.addAndGet(1024));
|
||||||
|
startTime = new AtomicLong(M.ms());
|
||||||
|
ticker = new Looper() {
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
long eta = computeETA();
|
||||||
|
int secondGenerated = generated.get() - generatedLast.get();
|
||||||
|
generatedLast.set(generated.get());
|
||||||
|
chunksPerSecond.put(secondGenerated);
|
||||||
|
|
||||||
|
if(minuteLatch.flip())
|
||||||
|
{
|
||||||
|
int minuteGenerated = generated.get() - generatedLastMinute.get();
|
||||||
|
generatedLastMinute.set(generated.get());
|
||||||
|
chunksPerMinute.put(minuteGenerated);
|
||||||
|
regionsPerMinute.put((double)minuteGenerated / 1024D);
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.onTick(chunksPerSecond.getAverage(), chunksPerMinute.getAverage(),
|
||||||
|
regionsPerMinute.getAverage(),
|
||||||
|
(double)generated.get() / (double)totalChunks.get(),
|
||||||
|
generated.get(), totalChunks.get(),
|
||||||
|
totalChunks.get() - generated.get(),
|
||||||
|
eta, M.ms() - startTime.get(), currentGeneratorMethod.get());
|
||||||
|
return 1000;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private long computeETA() {
|
||||||
|
return (long) ((totalChunks.get() - generated.get()) *
|
||||||
|
((double) (M.ms() - startTime.get()) / (double) generated.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
shutdown.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
ticker.start();
|
||||||
|
task.iterateRegions(this::visitRegion);
|
||||||
|
shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
generator.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void shutdown() {
|
||||||
|
listener.onSaving();
|
||||||
|
generator.close();
|
||||||
|
ticker.interrupt();
|
||||||
|
listener.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visitRegion(int x, int z) {
|
||||||
|
while(paused.get() && !shutdown.get())
|
||||||
|
{
|
||||||
|
J.sleep(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(shutdown.get())
|
||||||
|
{
|
||||||
|
listener.onRegionSkipped(x, z);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.onRegionGenerating(x, z);
|
||||||
|
currentGeneratorMethod.set(generator.getMethod(x, z));
|
||||||
|
|
||||||
|
if(generator.supportsRegions(x, z))
|
||||||
|
{
|
||||||
|
generator.generateRegion(x, z, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PregenTask.iterateRegion(x, z, (xx, zz) -> generator.generateChunk(xx, zz, listener));
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.onRegionGenerated(x, z);
|
||||||
|
listener.onSaving();
|
||||||
|
generator.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pause()
|
||||||
|
{
|
||||||
|
paused.set(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resume()
|
||||||
|
{
|
||||||
|
paused.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PregenListener listenify(PregenListener listener) {
|
||||||
|
return new PregenListener() {
|
||||||
|
@Override
|
||||||
|
public void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method) {
|
||||||
|
listener.onTick( chunksPerSecond, chunksPerMinute, regionsPerMinute, percent, generated, totalChunks, chunksRemaining, eta, elapsed, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChunkGenerating(int x, int z) {
|
||||||
|
listener.onChunkGenerating(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChunkGenerated(int x, int z) {
|
||||||
|
listener.onChunkGenerated(x, z);
|
||||||
|
generated.addAndGet(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegionGenerated(int x, int z) {
|
||||||
|
listener.onRegionGenerated(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegionGenerating(int x, int z) {
|
||||||
|
listener.onRegionGenerating(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRegionSkipped(int x, int z) {
|
||||||
|
listener.onRegionSkipped(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose() {
|
||||||
|
listener.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaving() {
|
||||||
|
listener.onSaving();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean paused() {
|
||||||
|
return paused.get();
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,22 @@
|
|||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.volmit.iris.core.gui;
|
package com.volmit.iris.core.pregenerator;
|
||||||
|
|
||||||
public class PregeneratorGUI {
|
public interface PregenListener {
|
||||||
|
void onTick(double chunksPerSecond, double chunksPerMinute, double regionsPerMinute, double percent, int generated, int totalChunks, int chunksRemaining, long eta, long elapsed, String method);
|
||||||
|
|
||||||
|
void onChunkGenerating(int x, int z);
|
||||||
|
|
||||||
|
void onChunkGenerated(int x, int z);
|
||||||
|
|
||||||
|
void onRegionGenerated(int x, int z);
|
||||||
|
|
||||||
|
void onRegionGenerating(int x, int z);
|
||||||
|
|
||||||
|
void onRegionSkipped(int x, int z);
|
||||||
|
|
||||||
|
void onClose();
|
||||||
|
|
||||||
|
void onSaving();
|
||||||
}
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator;
|
||||||
|
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.math.Position2;
|
||||||
|
import com.volmit.iris.util.math.Spiraled;
|
||||||
|
import com.volmit.iris.util.math.Spiraler;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
@Builder
|
||||||
|
@Data
|
||||||
|
public class PregenTask {
|
||||||
|
@Builder.Default
|
||||||
|
private Position2 center = new Position2(0,0);
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
private int radius = 1;
|
||||||
|
|
||||||
|
private static final KList<Position2> order = computeChunkOrder();
|
||||||
|
|
||||||
|
public void iterateRegions(Spiraled s)
|
||||||
|
{
|
||||||
|
new Spiraler(radius * 2, radius * 2, s)
|
||||||
|
.setOffset(center.getX(), center.getZ()).drain();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void iterateRegion(int xr, int zr, Spiraled s)
|
||||||
|
{
|
||||||
|
for(Position2 i : order)
|
||||||
|
{
|
||||||
|
s.on(i.getX() + (xr << 5), i.getZ() + (zr << 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void iterateAllChunks(Spiraled s)
|
||||||
|
{
|
||||||
|
new Spiraler(radius * 2, radius * 2, (x, z) -> iterateRegion(x, z, s))
|
||||||
|
.setOffset(center.getX(), center.getZ()).drain();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static KList<Position2> computeChunkOrder() {
|
||||||
|
Position2 center = new Position2(15, 15);
|
||||||
|
KList<Position2> p = new KList<>();
|
||||||
|
new Spiraler(33, 33, (x, z) -> {
|
||||||
|
int xx = x + 15;
|
||||||
|
int zz = z + 15;
|
||||||
|
if (xx < 0 || xx > 31 || zz < 0 || zz > 31) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.add(new Position2(xx, zz));
|
||||||
|
}).drain();
|
||||||
|
p.sort(Comparator.comparing((i) -> i.distance(center)));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents something that is capable of generating in chunks or regions, or both
|
||||||
|
*/
|
||||||
|
public interface PregeneratorMethod {
|
||||||
|
/**
|
||||||
|
* This is called before any generate methods are called. Setup your generator here
|
||||||
|
*/
|
||||||
|
void init();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is called after the pregenerator is done. Save your work and stop threads
|
||||||
|
*/
|
||||||
|
void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is called every X amount of chunks or regions. Save work,
|
||||||
|
* but no need to save all of it. At the end, close() will still be called.
|
||||||
|
*/
|
||||||
|
void save();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if regions can be generated
|
||||||
|
* @return true if they can be
|
||||||
|
* @param x the x region
|
||||||
|
* @param z the z region
|
||||||
|
*/
|
||||||
|
boolean supportsRegions(int x, int z);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the method being used
|
||||||
|
* @return the name
|
||||||
|
* @param x the x region
|
||||||
|
* @param z the z region
|
||||||
|
*/
|
||||||
|
String getMethod(int x, int z);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to generate a region. Execute sync, if multicore internally, wait
|
||||||
|
* for the task to complete
|
||||||
|
* @param x the x
|
||||||
|
* @param z the z
|
||||||
|
* @param listener signal chunks generating & generated. Parallel capable.
|
||||||
|
*/
|
||||||
|
void generateRegion(int x, int z, PregenListener listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called to generate a chunk. You can go async so long as save will wait on the threads to finish
|
||||||
|
* @param x the x
|
||||||
|
* @param z the z
|
||||||
|
* @param listener
|
||||||
|
*/
|
||||||
|
void generateChunk(int x, int z, PregenListener listener);
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator.methods;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
|
|
||||||
|
public class DummyPregenMethod implements PregeneratorMethod {
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod(int x, int z) {
|
||||||
|
return "Dummy";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRegions(int x, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateRegion(int x, int z, PregenListener listener) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateChunk(int x, int z, PregenListener listener) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator.methods;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
|
import com.volmit.iris.engine.headless.HeadlessGenerator;
|
||||||
|
import com.volmit.iris.engine.headless.HeadlessWorld;
|
||||||
|
|
||||||
|
public class HeadlessPregenMethod implements PregeneratorMethod {
|
||||||
|
private final HeadlessWorld world;
|
||||||
|
private final HeadlessGenerator generator;
|
||||||
|
|
||||||
|
public HeadlessPregenMethod(HeadlessWorld world)
|
||||||
|
{
|
||||||
|
this.world = world;
|
||||||
|
this.generator = world.generate();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
generator.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
generator.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRegions(int x, int z) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod(int x, int z) {
|
||||||
|
return "Headless";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateRegion(int x, int z, PregenListener listener) {
|
||||||
|
generator.generateRegion(x, z, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateChunk(int x, int z, PregenListener listener) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator.methods;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
|
import com.volmit.iris.engine.IrisWorlds;
|
||||||
|
import com.volmit.iris.engine.headless.HeadlessWorld;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class HybridPregenMethod implements PregeneratorMethod {
|
||||||
|
private final PregeneratorMethod headless;
|
||||||
|
private final PregeneratorMethod inWorld;
|
||||||
|
private final World world;
|
||||||
|
|
||||||
|
public HybridPregenMethod(World world, int threads)
|
||||||
|
{
|
||||||
|
this.world = world;
|
||||||
|
headless = supportsHeadless(world)
|
||||||
|
? new HeadlessPregenMethod(HeadlessWorld.from(world)) : new DummyPregenMethod();
|
||||||
|
inWorld = new PaperOrMedievalPregenMethod(world, threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean supportsHeadless(World world) {
|
||||||
|
return IrisWorlds.access(world) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod(int x, int z) {
|
||||||
|
return "Hybrid<" + ((supportsRegions(x, z) ? headless.getMethod(x, z) : inWorld.getMethod(x, z)) + ">");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
headless.init();
|
||||||
|
inWorld.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
headless.close();
|
||||||
|
inWorld.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
headless.save();
|
||||||
|
inWorld.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRegions(int x, int z) {
|
||||||
|
if (headless instanceof DummyPregenMethod) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !new File(world.getWorldFolder(), "region/r." + x + "." + z + ".mca").exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateRegion(int x, int z, PregenListener listener) {
|
||||||
|
headless.generateRegion(x, z, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateChunk(int x, int z, PregenListener listener) {
|
||||||
|
inWorld.generateChunk(x, z, listener);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator.methods;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public class MedievalPregenMethod implements PregeneratorMethod {
|
||||||
|
private final World world;
|
||||||
|
private final KList<CompletableFuture<?>> futures;
|
||||||
|
|
||||||
|
public MedievalPregenMethod(World world)
|
||||||
|
{
|
||||||
|
this.world = world;
|
||||||
|
futures = new KList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForChunks()
|
||||||
|
{
|
||||||
|
for(CompletableFuture<?> i : futures)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
i.get();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
futures.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unloadAndSaveAllChunks() {
|
||||||
|
waitForChunks();
|
||||||
|
J.s(() -> {
|
||||||
|
for(Chunk i : world.getLoadedChunks())
|
||||||
|
{
|
||||||
|
i.unload(true);
|
||||||
|
}
|
||||||
|
world.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
unloadAndSaveAllChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
unloadAndSaveAllChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
unloadAndSaveAllChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRegions(int x, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateRegion(int x, int z, PregenListener listener) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod(int x, int z) {
|
||||||
|
return "Medieval";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateChunk(int x, int z, PregenListener listener) {
|
||||||
|
if(futures.size() > 32)
|
||||||
|
{
|
||||||
|
waitForChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.onChunkGenerating(x, z);
|
||||||
|
futures.add(J.sfut(() -> {
|
||||||
|
world.getChunkAt(x, z);
|
||||||
|
listener.onChunkGenerated(x, z);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator.methods;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
|
import com.volmit.iris.engine.parallel.MultiBurst;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import com.volmit.iris.util.scheduling.J;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
|
import org.bukkit.Chunk;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
public class PaperAsyncPregenMethod implements PregeneratorMethod {
|
||||||
|
private final World world;
|
||||||
|
private final MultiBurst burst;
|
||||||
|
private final KList<CompletableFuture<?>> future;
|
||||||
|
|
||||||
|
public PaperAsyncPregenMethod(World world, int threads)
|
||||||
|
{
|
||||||
|
if(!PaperLib.isPaper())
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException("Cannot use PaperAsync on non paper!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.world = world;
|
||||||
|
burst = new MultiBurst("Iris PaperAsync Pregenerator", 6, threads);
|
||||||
|
future = new KList<>(1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void unloadAndSaveAllChunks() {
|
||||||
|
J.s(() -> {
|
||||||
|
for(Chunk i : world.getLoadedChunks())
|
||||||
|
{
|
||||||
|
i.unload(true);
|
||||||
|
}
|
||||||
|
world.save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void completeChunk(int x, int z, PregenListener listener) {
|
||||||
|
try {
|
||||||
|
PaperLib.getChunkAtAsync(world, x, z, true).get();
|
||||||
|
listener.onChunkGenerated(x, z);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void waitForChunks()
|
||||||
|
{
|
||||||
|
for(CompletableFuture<?> i : future)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
i.get();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
future.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
unloadAndSaveAllChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod(int x, int z) {
|
||||||
|
return "Async";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
waitForChunks();
|
||||||
|
burst.shutdownAndAwait();
|
||||||
|
unloadAndSaveAllChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
waitForChunks();
|
||||||
|
unloadAndSaveAllChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRegions(int x, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateRegion(int x, int z, PregenListener listener) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateChunk(int x, int z, PregenListener listener) {
|
||||||
|
if(future.size() > 128)
|
||||||
|
{
|
||||||
|
waitForChunks();
|
||||||
|
}
|
||||||
|
|
||||||
|
listener.onChunkGenerating(x, z);
|
||||||
|
future.add(burst.complete(() -> completeChunk(x, z, listener)));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2021 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.volmit.iris.core.pregenerator.methods;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregeneratorMethod;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
public class PaperOrMedievalPregenMethod implements PregeneratorMethod {
|
||||||
|
private final PregeneratorMethod method;
|
||||||
|
|
||||||
|
public PaperOrMedievalPregenMethod(World world, int threads)
|
||||||
|
{
|
||||||
|
method = PaperLib.isPaper() ? new PaperAsyncPregenMethod(world, threads) : new MedievalPregenMethod(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
method.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
method.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save() {
|
||||||
|
method.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getMethod(int x, int z) {
|
||||||
|
return method.getMethod(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsRegions(int x, int z) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateRegion(int x, int z, PregenListener listener) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void generateChunk(int x, int z, PregenListener listener) {
|
||||||
|
method.generateChunk(x, z, listener);
|
||||||
|
}
|
||||||
|
}
|
@ -313,15 +313,7 @@ public class NBTWorld {
|
|||||||
|
|
||||||
if(mcaf == null)
|
if(mcaf == null)
|
||||||
{
|
{
|
||||||
File f = getRegionFile(x, z);
|
mcaf = new MCAFile(x, z);
|
||||||
try {
|
|
||||||
mcaf = f.exists() ? MCAUtil.read(f) : new MCAFile(x, z);
|
|
||||||
} catch (IOException e) {
|
|
||||||
Iris.error("Failed to properly read MCA File " + f.getPath() + " Using a blank one.");
|
|
||||||
e.printStackTrace();
|
|
||||||
mcaf = new MCAFile(x, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
regionLock.lock();
|
regionLock.lock();
|
||||||
loadedRegions.put(key, mcaf);
|
loadedRegions.put(key, mcaf);
|
||||||
regionLock.unlock();
|
regionLock.unlock();
|
||||||
|
@ -23,6 +23,8 @@ import com.volmit.iris.core.IrisDataManager;
|
|||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.nms.BiomeBaseInjector;
|
import com.volmit.iris.core.nms.BiomeBaseInjector;
|
||||||
import com.volmit.iris.core.nms.INMS;
|
import com.volmit.iris.core.nms.INMS;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenTask;
|
||||||
import com.volmit.iris.engine.IrisEngineCompound;
|
import com.volmit.iris.engine.IrisEngineCompound;
|
||||||
import com.volmit.iris.engine.IrisWorlds;
|
import com.volmit.iris.engine.IrisWorlds;
|
||||||
import com.volmit.iris.engine.cache.Cache;
|
import com.volmit.iris.engine.cache.Cache;
|
||||||
@ -460,17 +462,24 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst) {
|
public void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst) {
|
||||||
BurstExecutor e = burst.burst(1024);
|
directWriteMCA(w, x, z, writer, burst, null);
|
||||||
int mcaox = x << 5;
|
}
|
||||||
int mcaoz = z << 5;
|
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) {
|
@Override
|
||||||
int ii = i;
|
public void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst, PregenListener l) {
|
||||||
for (int j = 0; j < 32; j++) {
|
BurstExecutor e = burst.burst(1024);
|
||||||
int jj = j;
|
|
||||||
e.queue(() -> directWriteChunk(w, ii + mcaox, jj + mcaoz, writer));
|
PregenTask.iterateRegion(x, z, (ii, jj) -> e.queue(() -> {
|
||||||
|
if(l != null)
|
||||||
|
{
|
||||||
|
l.onChunkGenerating(ii, jj);
|
||||||
}
|
}
|
||||||
}
|
directWriteChunk(w, ii, jj, writer);
|
||||||
|
if(l != null)
|
||||||
|
{
|
||||||
|
l.onChunkGenerated(ii, jj);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
e.complete();
|
e.complete();
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ package com.volmit.iris.engine.framework;
|
|||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisDataManager;
|
import com.volmit.iris.core.IrisDataManager;
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
import com.volmit.iris.engine.IrisComplex;
|
import com.volmit.iris.engine.IrisComplex;
|
||||||
import com.volmit.iris.engine.data.DataProvider;
|
import com.volmit.iris.engine.data.DataProvider;
|
||||||
import com.volmit.iris.engine.data.mca.NBTWorld;
|
import com.volmit.iris.engine.data.mca.NBTWorld;
|
||||||
@ -47,6 +48,8 @@ public interface IrisAccess extends Hotloadable, DataProvider {
|
|||||||
|
|
||||||
void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst);
|
void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst);
|
||||||
|
|
||||||
|
void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst, PregenListener listener);
|
||||||
|
|
||||||
void directWriteChunk(IrisWorld w, int x, int z, NBTWorld writer);
|
void directWriteChunk(IrisWorld w, int x, int z, NBTWorld writer);
|
||||||
|
|
||||||
int getGenerated();
|
int getGenerated();
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
package com.volmit.iris.engine.headless;
|
package com.volmit.iris.engine.headless;
|
||||||
|
|
||||||
|
import com.volmit.iris.core.pregenerator.PregenListener;
|
||||||
import com.volmit.iris.engine.data.mca.NBTWorld;
|
import com.volmit.iris.engine.data.mca.NBTWorld;
|
||||||
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
|
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
|
||||||
import com.volmit.iris.engine.parallel.MultiBurst;
|
import com.volmit.iris.engine.parallel.MultiBurst;
|
||||||
@ -51,6 +52,11 @@ public class HeadlessGenerator {
|
|||||||
generator.directWriteMCA(world.getWorld(), x, z, writer, burst);
|
generator.directWriteMCA(world.getWorld(), x, z, writer, burst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void generateRegion(int x, int z, PregenListener listener)
|
||||||
|
{
|
||||||
|
generator.directWriteMCA(world.getWorld(), x, z, writer, burst, listener);
|
||||||
|
}
|
||||||
|
|
||||||
public File generateRegionToFile(int x, int z)
|
public File generateRegionToFile(int x, int z)
|
||||||
{
|
{
|
||||||
generateRegionToFile(x, z);
|
generateRegionToFile(x, z);
|
||||||
|
@ -20,7 +20,9 @@ package com.volmit.iris.engine.headless;
|
|||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisDataManager;
|
import com.volmit.iris.core.IrisDataManager;
|
||||||
|
import com.volmit.iris.engine.IrisWorlds;
|
||||||
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
|
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
|
||||||
|
import com.volmit.iris.engine.framework.IrisAccess;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
import com.volmit.iris.engine.object.common.IrisWorld;
|
import com.volmit.iris.engine.object.common.IrisWorld;
|
||||||
import com.volmit.iris.util.plugin.VolmitSender;
|
import com.volmit.iris.util.plugin.VolmitSender;
|
||||||
@ -73,6 +75,10 @@ public class HeadlessWorld {
|
|||||||
.createWorld();
|
.createWorld();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HeadlessWorld from(World world) {
|
||||||
|
return new HeadlessWorld(world.getName(), IrisWorlds.access(world).getTarget().getDimension(), world.getSeed());
|
||||||
|
}
|
||||||
|
|
||||||
public static HeadlessWorld from(String name, String dimension, long seed)
|
public static HeadlessWorld from(String name, String dimension, long seed)
|
||||||
{
|
{
|
||||||
return new HeadlessWorld(name, IrisDataManager.loadAnyDimension(dimension), seed);
|
return new HeadlessWorld(name, IrisDataManager.loadAnyDimension(dimension), seed);
|
||||||
|
@ -43,6 +43,11 @@ public class Position2 {
|
|||||||
this.z = z;
|
this.z = z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "[" + x + "," + z + "]";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
@ -52,6 +57,11 @@ public class Position2 {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Position2 regionToChunk()
|
||||||
|
{
|
||||||
|
return new Position2(x << 5, z << 5);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
@ -66,4 +76,8 @@ public class Position2 {
|
|||||||
public double distance(Position2 center) {
|
public double distance(Position2 center) {
|
||||||
return Math.pow(center.getX() - x, 2) + Math.pow(center.getZ() - z, 2);
|
return Math.pow(center.getX() - x, 2) + Math.pow(center.getZ() - z, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Position2 add(int x, int z) {
|
||||||
|
return new Position2(this.x + x, this.z + z);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,6 +208,15 @@ public class J {
|
|||||||
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, r);
|
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CompletableFuture sfut(Runnable r) {
|
||||||
|
CompletableFuture f = new CompletableFuture();
|
||||||
|
Bukkit.getScheduler().scheduleSyncDelayedTask(Iris.instance, () -> {
|
||||||
|
r.run();
|
||||||
|
f.complete(null);
|
||||||
|
});
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queue a sync task
|
* Queue a sync task
|
||||||
*
|
*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user