Writer fixes

This commit is contained in:
Daniel Mills 2020-12-29 06:14:18 -05:00
parent ee557d8191
commit f4eb0cfbcb
9 changed files with 417 additions and 16 deletions

View File

@ -1,7 +1,6 @@
package com.volmit.iris.generator;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.scaffold.engine.*;
import com.volmit.iris.scaffold.hunk.Hunk;
import com.volmit.iris.util.J;
@ -109,7 +108,6 @@ public class IrisEngine extends BlockPopulator implements Engine
try
{
boolean structures = postblocks != null;
boolean multicore = !IrisSettings.get().isUseGleamPregenerator(); //TODO: LATER
s.acquire(1);
PrecisionStopwatch p = PrecisionStopwatch.start();
Hunk<BlockData> blocks = vblocks.synchronize().listen((xx,y,zz,t) -> catchBlockUpdates(x+xx,y+getMinHeight(),z+zz, t));

View File

@ -1,4 +1,4 @@
package com.volmit.iris.scaffold.engine;
package com.volmit.iris.pregen;
import com.volmit.iris.Iris;
import com.volmit.iris.nms.INMS;
@ -33,7 +33,7 @@ public class DirectWorldWriter {
this.worldFolder = worldFolder;
lastUse = SmoothieMap.<Long, Long>newBuilder().build();
writeBuffer = new KMap<>();
new File(worldFolder, "region").mkdirs();
new File(worldFolder, "iris/mca-region").mkdirs();
}
public void flush()
@ -86,7 +86,7 @@ public class DirectWorldWriter {
public File getMCAFile(int x, int z)
{
return new File(worldFolder, "region/r." + x + "." + z + ".mca");
return new File(worldFolder, "iris/mca-region/r." + x + "." + z + ".mca");
}
public BlockData getBlockData(CompoundTag tag) {

View File

@ -1,8 +1,390 @@
package com.volmit.iris.pregen;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.scaffold.engine.IrisAccess;
import com.volmit.iris.scaffold.parallel.BurstExecutor;
import com.volmit.iris.scaffold.parallel.MultiBurst;
import com.volmit.iris.util.*;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.event.Listener;
public class MCAPregenerator implements Listener
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
@Data
public class Pregenerator implements Listener
{
private static final Color COLOR_MCA_PREPARE = Color.DARK_GRAY;
private static final Color COLOR_MCA_GENERATE = Color.MAGENTA;
private static final Color COLOR_MCA_GENERATE_SLOW = Color.MAGENTA.darker().darker();
private static final Color COLOR_MCA_GENERATED = Color.CYAN;
private static final Color COLOR_MCA_SEALED = Color.GREEN;
private static final Color COLOR_MCA_SEALING = Color.GREEN.darker().darker();
private final World world;
private final DirectWorldWriter directWriter;
private final AtomicBoolean active;
private final AtomicBoolean running;
private final KList<Runnable> onComplete;
private final ChunkPosition max;
private final ChunkPosition min;
private final MCAPregenGui gui;
public Pregenerator(World world, IrisAccess access, int blockSize, int xoffset, int zoffset)
{
this.world = world;
this.directWriter = new DirectWorldWriter(world.getWorldFolder());
this.running = new AtomicBoolean(true);
this.active = new AtomicBoolean(true);
MultiBurst burst = new MultiBurst(Runtime.getRuntime().availableProcessors());
int mcaSize = (((blockSize >> 4) + 2) >> 5) + 2;
int xaoff = (xoffset >> 4) >> 5;
int zaoff = (zoffset >> 4) >> 5;
onComplete = new KList<>();
max = new ChunkPosition(xoffset + (blockSize/2), zoffset + (blockSize/2));
min = new ChunkPosition(xoffset - (blockSize/2), zoffset - (blockSize/2));
gui = IrisSettings.get().isLocalPregenGui() && IrisSettings.get().isUseServerLaunchedGuis() ? MCAPregenGui.createAndShowGUI(this) : null;
Spiraler spiraler = new Spiraler(mcaSize, mcaSize, (xx,zz) -> {
int x = xaoff + xx;
int z = zaoff + zz;
try {
flushWorld();
drawMCA(x, z, COLOR_MCA_PREPARE);
File mca = new File(world.getWorldFolder(), "region/r." + x + "." + z + ".mca");
File mcg = directWriter.getMCAFile(x, z);
Path fileToMovePath = Paths.get(mcg.toURI());
Path targetPath = Paths.get(mca.toURI());
BurstExecutor e = burst.burst(1024);
int mcaox = x << 5;
int mcaoz = z << 5;
if(isMCAWritable(x,z) && !mcg.exists())
{
for(int i = 0; i < 32; i++)
{
int ii = i;
for(int j = 0; j < 32; j++)
{
int jj = j;
e.queue(() -> {
draw(ii + mcaox, jj + mcaoz, COLOR_MCA_GENERATE);
access.directWriteChunk(world, ii + mcaox, jj + mcaoz, directWriter);
draw(ii + mcaox, jj + mcaoz, COLOR_MCA_GENERATED);
});
}
}
directWriter.flush();
Files.move(fileToMovePath, targetPath);
}
else
{
for(int i = 0; i < 32; i++)
{
int ii = i;
for(int j = 0; j < 32; j++)
{
int jj = j;
e.queue(() -> {
draw(ii + mcaox, jj + mcaoz, COLOR_MCA_GENERATE_SLOW);
access.generatePaper(world, ii+mcaox, jj + mcaoz);
draw(ii + mcaox, jj + mcaoz, COLOR_MCA_GENERATED);
});
}
}
}
e.complete();
drawMCA(x, z, COLOR_MCA_SEALED);
flushWorld();
drawMCA(x, z, COLOR_MCA_SEALED);
} catch (IOException e) {
e.printStackTrace();
}
});
new Thread(() -> {
while(running.get() && spiraler.hasNext())
{
if(active.get())
{
spiraler.next();
}
}
burst.shutdownNow();
directWriter.flush();
flushWorld();
onComplete.forEach(Runnable::run);
if(gui != null)
{
gui.close();
}
});
}
public void shutdown()
{
running.set(false);
active.set(false);
}
private void draw(int cx, int cz, Color color)
{
if(gui != null)
{
gui.func.accept(new ChunkPosition(cx, cz), color);
}
}
private void drawMCA(int cx, int cz, Color color)
{
for(int i = 0; i < 32; i++)
{
for(int j = 0; j < 32; j++)
{
draw((cx << 5) + i, (cz << 5) + j, color);
}
}
}
private void flushWorld()
{
if(Bukkit.isPrimaryThread())
{
flushWorldSync();
return;
}
AtomicBoolean b = new AtomicBoolean(false);
J.s(() -> {
flushWorldSync();
b.set(true);
});
while(!b.get())
{
J.sleep(10);
}
}
private void flushWorldSync()
{
for(Chunk i : world.getLoadedChunks())
{
i.unload(true);
}
world.save();
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "save-all");
}
private boolean isMCAWritable(int x, int z) {
File mca = new File(world.getWorldFolder(), "region/r." + x + "." + z + ".mca");
if (mca.exists()) {
return false;
}
for (Chunk i : world.getLoadedChunks())
{
if(i.getX() >> 5 == x && i.getZ() >> 5 == z)
{
return false;
}
}
return true;
}
public String[] getProgress() {
return new String[]{"Derp"};
}
public boolean paused() {
return !active.get();
}
public static class MCAPregenGui extends JPanel implements KeyListener
{
private Pregenerator job;
private static final long serialVersionUID = 2094606939770332040L;
private KList<Runnable> order = new KList<>();
private int res = 512;
Graphics2D bg;
private ReentrantLock l;
private BufferedImage image = new BufferedImage(res, res, BufferedImage.TYPE_INT_RGB);
private Consumer2<ChunkPosition,Color> func;
private JFrame frame;
public MCAPregenGui()
{
}
public void paint(int x, int z, Color c)
{
func.accept(new ChunkPosition(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)
{
}
}
l.unlock();
g.drawImage(image, 0, 0, getParent().getWidth(), getParent().getHeight(), new ImageObserver()
{
@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
return 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((long) (IrisSettings.get().isMaximumPregenGuiFPS() ? 4 : 250));
repaint();
}
private void draw(ChunkPosition 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);
}
@SuppressWarnings("deprecation")
private static MCAPregenGui createAndShowGUI(Pregenerator j)
{
JFrame frame = new JFrame("Pregen View");
MCAPregenGui nv = new MCAPregenGui();
frame.addKeyListener(nv);
nv.l = new ReentrantLock();
nv.frame = frame;
nv.job = j;
nv.func = (c, b) ->
{
if(b.equals(Color.pink) && c.equals(new ChunkPosition(Integer.MAX_VALUE, Integer.MAX_VALUE)))
{
frame.hide();
}
nv.l.lock();
nv.order.add(() -> nv.draw(c, b, nv.bg));
nv.l.unlock();
};
frame.add(nv);
frame.setSize(1000, 1000);
frame.setVisible(true);
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 e)
{
}
}
return nv;
}
public static void launch(Pregenerator g)
{
J.a(() ->
{
createAndShowGUI(g);
});
}
@Override
public void keyTyped(KeyEvent e)
{
}
@Override
public void keyPressed(KeyEvent e)
{
}
@Override
public void keyReleased(KeyEvent e)
{
if(e.getKeyCode() == KeyEvent.VK_P)
{
PregenJob.pauseResume();
}
}
public void close() {
frame.setVisible(false);
}
}
}

View File

@ -6,6 +6,7 @@ import com.volmit.iris.generator.IrisEngineCompound;
import com.volmit.iris.manager.IrisDataManager;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.pregen.DirectWorldWriter;
import com.volmit.iris.scaffold.IrisWorlds;
import com.volmit.iris.scaffold.cache.Cache;
import com.volmit.iris.scaffold.hunk.Hunk;
@ -312,11 +313,6 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
public void directWriteMCA(World w, int x, int z, DirectWorldWriter writer, MultiBurst burst)
{
if(writer.getMCAFile(x, z).exists())
{
return;
}
BurstExecutor e = burst.burst(1024);
int mcaox = x << 5;
int mcaoz = z << 5;
@ -327,7 +323,9 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
for(int j = 0; j < 32; j++)
{
int jj = j;
e.queue(() -> directWriteChunk(w, ii + mcaox, jj + mcaoz, writer));
e.queue(() -> {
directWriteChunk(w, ii + mcaox, jj + mcaoz, writer);
});
}
}

View File

@ -2,6 +2,7 @@ package com.volmit.iris.scaffold.engine;
import com.volmit.iris.manager.IrisDataManager;
import com.volmit.iris.object.*;
import com.volmit.iris.pregen.DirectWorldWriter;
import com.volmit.iris.scaffold.data.DataProvider;
import com.volmit.iris.scaffold.parallel.MultiBurst;
import com.volmit.iris.util.*;

View File

@ -80,7 +80,7 @@ public class HunkRegionSlice<T>
public void save()
{
BurstExecutor e = MultiBurst.burst.burst(save.size());
BurstExecutor e = MultiBurst.burst.burst();
for(ChunkPosition i : save.copy())
{
if(i == null)
@ -89,7 +89,16 @@ public class HunkRegionSlice<T>
}
e.queue(() -> save(i.getX(), i.getZ()));
save.remove(i);
try
{
save.remove(i);
}
catch(Throwable ef)
{
}
}
e.complete();

View File

@ -83,4 +83,12 @@ public class MultiBurst
service.execute(o);
}
}
public void shutdownNow() {
service.shutdownNow().forEach(Runnable::run);
}
public void shutdown() {
service.shutdown();
}
}

View File

@ -4,7 +4,7 @@ import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.manager.gui.PregenGui;
import com.volmit.iris.scaffold.IrisWorlds;
import com.volmit.iris.scaffold.engine.DirectWorldWriter;
import com.volmit.iris.pregen.DirectWorldWriter;
import com.volmit.iris.scaffold.engine.IrisAccess;
import com.volmit.iris.scaffold.parallel.MultiBurst;
import io.papermc.lib.PaperLib;

View File

@ -110,6 +110,11 @@ public final class MCAUtil {
* @throws IOException If something goes wrong during serialization.
* */
public static int write(MCAFile mcaFile, File file, boolean changeLastUpdate) throws IOException {
if(mcaFile == null)
{
return 0;
}
File to = file;
if (file.exists()) {
to = File.createTempFile(to.getName(), null);