mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2025-07-04 00:46:08 +00:00
implement engine services and other improvements
This commit is contained in:
parent
90bab2b292
commit
3b98b20f73
@ -20,12 +20,12 @@ package com.volmit.iris.core.commands;
|
|||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.loader.IrisData;
|
import com.volmit.iris.core.loader.IrisData;
|
||||||
import com.volmit.iris.core.service.IrisCleanerSVC;
|
|
||||||
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
import com.volmit.iris.core.tools.IrisPackBenchmarking;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.core.tools.IrisWorldDump;
|
import com.volmit.iris.core.tools.IrisWorldDump;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.object.IrisDimension;
|
import com.volmit.iris.engine.object.IrisDimension;
|
||||||
|
import com.volmit.iris.engine.service.EngineStatusSVC;
|
||||||
import com.volmit.iris.util.decree.DecreeExecutor;
|
import com.volmit.iris.util.decree.DecreeExecutor;
|
||||||
import com.volmit.iris.util.decree.DecreeOrigin;
|
import com.volmit.iris.util.decree.DecreeOrigin;
|
||||||
import com.volmit.iris.util.decree.annotations.Decree;
|
import com.volmit.iris.util.decree.annotations.Decree;
|
||||||
@ -50,8 +50,6 @@ import java.io.*;
|
|||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.zip.GZIPInputStream;
|
||||||
import java.util.zip.GZIPOutputStream;
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
@ -60,55 +58,22 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
private CommandTurboPregen turboPregen;
|
private CommandTurboPregen turboPregen;
|
||||||
private CommandUpdater updater;
|
private CommandUpdater updater;
|
||||||
|
|
||||||
@Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, sync = true)
|
@Decree(description = "Get Loaded TectonicPlates Count", origin = DecreeOrigin.BOTH, aliases = "status", sync = true)
|
||||||
public void EngineStatus() {
|
public void EngineStatus() {
|
||||||
List<World> IrisWorlds = new ArrayList<>();
|
var status = EngineStatusSVC.getStatus();
|
||||||
int TotalLoadedChunks = 0;
|
|
||||||
int TotalQueuedTectonicPlates = 0;
|
|
||||||
int TotalNotQueuedTectonicPlates = 0;
|
|
||||||
int TotalTectonicPlates = 0;
|
|
||||||
|
|
||||||
long lowestUnloadDuration = 0;
|
sender().sendMessage("-------------------------");
|
||||||
long highestUnloadDuration = 0;
|
sender().sendMessage(C.DARK_PURPLE + "Engine Status");
|
||||||
|
sender().sendMessage(C.DARK_PURPLE + "Total Engines: " + C.LIGHT_PURPLE + status.engineCount());
|
||||||
for (World world : Bukkit.getWorlds()) {
|
sender().sendMessage(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + status.loadedChunks());
|
||||||
try {
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + status.tectonicLimit());
|
||||||
if (IrisToolbelt.access(world).getEngine() != null) {
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + status.tectonicPlates());
|
||||||
IrisWorlds.add(world);
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + status.activeTectonicPlates());
|
||||||
}
|
sender().sendMessage(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + status.queuedTectonicPlates());
|
||||||
} catch (Exception e) {
|
sender().sendMessage(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(status.minTectonicUnloadDuration()));
|
||||||
// no
|
sender().sendMessage(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(status.maxTectonicUnloadDuration()));
|
||||||
}
|
sender().sendMessage(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
||||||
}
|
sender().sendMessage("-------------------------");
|
||||||
|
|
||||||
for (World world : IrisWorlds) {
|
|
||||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
|
||||||
TotalQueuedTectonicPlates += (int) engine.getMantle().getToUnload();
|
|
||||||
TotalNotQueuedTectonicPlates += (int) engine.getMantle().getNotQueuedLoadedRegions();
|
|
||||||
TotalTectonicPlates += engine.getMantle().getLoadedRegionCount();
|
|
||||||
if (highestUnloadDuration <= (long) engine.getMantle().getTectonicDuration()) {
|
|
||||||
highestUnloadDuration = (long) engine.getMantle().getTectonicDuration();
|
|
||||||
}
|
|
||||||
if (lowestUnloadDuration >= (long) engine.getMantle().getTectonicDuration()) {
|
|
||||||
lowestUnloadDuration = (long) engine.getMantle().getTectonicDuration();
|
|
||||||
}
|
|
||||||
for (Chunk chunk : world.getLoadedChunks()) {
|
|
||||||
if (chunk.isLoaded()) {
|
|
||||||
TotalLoadedChunks++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Iris.info("-------------------------");
|
|
||||||
Iris.info(C.DARK_PURPLE + "Engine Status");
|
|
||||||
Iris.info(C.DARK_PURPLE + "Total Loaded Chunks: " + C.LIGHT_PURPLE + TotalLoadedChunks);
|
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic Limit: " + C.LIGHT_PURPLE + IrisCleanerSVC.getTectonicLimit());
|
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic Total Plates: " + C.LIGHT_PURPLE + TotalTectonicPlates);
|
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic Active Plates: " + C.LIGHT_PURPLE + TotalNotQueuedTectonicPlates);
|
|
||||||
Iris.info(C.DARK_PURPLE + "Tectonic ToUnload: " + C.LIGHT_PURPLE + TotalQueuedTectonicPlates);
|
|
||||||
Iris.info(C.DARK_PURPLE + "Lowest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(lowestUnloadDuration));
|
|
||||||
Iris.info(C.DARK_PURPLE + "Highest Tectonic Unload Duration: " + C.LIGHT_PURPLE + Form.duration(highestUnloadDuration));
|
|
||||||
Iris.info(C.DARK_PURPLE + "Cache Size: " + C.LIGHT_PURPLE + Form.f(IrisData.cacheSize()));
|
|
||||||
Iris.info("-------------------------");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "Test")
|
@Decree(description = "Test")
|
||||||
@ -126,7 +91,7 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
for (File i : Objects.requireNonNull(tectonicplates.listFiles())) {
|
for (File i : Objects.requireNonNull(tectonicplates.listFiles())) {
|
||||||
TectonicPlate.read(maxHeight, i);
|
TectonicPlate.read(maxHeight, i);
|
||||||
c++;
|
c++;
|
||||||
Iris.info("Loaded count: " + c );
|
sender().sendMessage("Loaded count: " + c );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,12 +104,14 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
@Param(description = "Headless", defaultValue = "true")
|
@Param(description = "Headless", defaultValue = "true")
|
||||||
boolean headless,
|
boolean headless,
|
||||||
@Param(description = "GUI", defaultValue = "false")
|
@Param(description = "GUI", defaultValue = "false")
|
||||||
boolean gui
|
boolean gui,
|
||||||
|
@Param(description = "Diameter in regions", defaultValue = "5")
|
||||||
|
int diameter
|
||||||
) {
|
) {
|
||||||
Iris.info("test");
|
int rb = diameter << 9;
|
||||||
IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, 1, headless, gui);
|
Iris.info("Benchmarking pack " + dimension.getName() + " with diameter: " + rb + "(" + diameter + ")");
|
||||||
|
IrisPackBenchmarking benchmark = new IrisPackBenchmarking(dimension, diameter, headless, gui);
|
||||||
benchmark.runBenchmark();
|
benchmark.runBenchmark();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decree(description = "test")
|
@Decree(description = "test")
|
||||||
@ -235,9 +202,8 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
Engine engine = IrisToolbelt.access(world).getEngine();
|
Engine engine = IrisToolbelt.access(world).getEngine();
|
||||||
if(engine != null) {
|
if(engine != null) {
|
||||||
int height = engine.getTarget().getHeight();
|
int height = engine.getTarget().getHeight();
|
||||||
ExecutorService service = Executors.newFixedThreadPool(1);
|
|
||||||
VolmitSender sender = sender();
|
VolmitSender sender = sender();
|
||||||
service.submit(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
DataInputStream raw = new DataInputStream(new FileInputStream(file));
|
DataInputStream raw = new DataInputStream(new FileInputStream(file));
|
||||||
TectonicPlate plate = new TectonicPlate(height, raw);
|
TectonicPlate plate = new TectonicPlate(height, raw);
|
||||||
@ -271,8 +237,7 @@ public class CommandDeveloper implements DecreeExecutor {
|
|||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
}, "Compression Test").start();
|
||||||
service.shutdown();
|
|
||||||
} else {
|
} else {
|
||||||
Iris.info(C.RED + "Engine is null!");
|
Iris.info(C.RED + "Engine is null!");
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import java.io.Closeable;
|
|||||||
|
|
||||||
public interface IHeadless extends Closeable {
|
public interface IHeadless extends Closeable {
|
||||||
|
|
||||||
void save();
|
int getLoadedChunks();
|
||||||
|
|
||||||
@ChunkCoordinates
|
@ChunkCoordinates
|
||||||
boolean exists(int x, int z);
|
boolean exists(int x, int z);
|
||||||
|
@ -37,7 +37,6 @@ public class HeadlessPregenMethod implements PregeneratorMethod {
|
|||||||
try {
|
try {
|
||||||
semaphore.acquire(max);
|
semaphore.acquire(max);
|
||||||
} catch (InterruptedException ignored) {}
|
} catch (InterruptedException ignored) {}
|
||||||
headless.save();
|
|
||||||
try {
|
try {
|
||||||
headless.close();
|
headless.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@ -47,9 +46,7 @@ public class HeadlessPregenMethod implements PregeneratorMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void save() {
|
public void save() {}
|
||||||
headless.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supportsRegions(int x, int z, PregenListener listener) {
|
public boolean supportsRegions(int x, int z, PregenListener listener) {
|
||||||
|
@ -1,318 +0,0 @@
|
|||||||
package com.volmit.iris.core.service;
|
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
|
||||||
import com.volmit.iris.engine.platform.PlatformChunkGenerator;
|
|
||||||
import com.volmit.iris.util.collection.KMap;
|
|
||||||
import com.volmit.iris.util.format.C;
|
|
||||||
import com.volmit.iris.util.format.Form;
|
|
||||||
import com.volmit.iris.util.misc.getHardware;
|
|
||||||
import com.volmit.iris.util.plugin.IrisService;
|
|
||||||
import com.volmit.iris.util.scheduling.ChronoLatch;
|
|
||||||
import com.volmit.iris.util.scheduling.Looper;
|
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.server.PluginDisableEvent;
|
|
||||||
import org.bukkit.event.server.ServerLoadEvent;
|
|
||||||
import org.bukkit.event.world.WorldLoadEvent;
|
|
||||||
import org.bukkit.event.world.WorldUnloadEvent;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public class IrisCleanerSVC implements IrisService {
|
|
||||||
public static IrisCleanerSVC instance;
|
|
||||||
public boolean isServerShuttingDown = false;
|
|
||||||
public boolean isServerLoaded = false;
|
|
||||||
private static final AtomicInteger tectonicLimit = new AtomicInteger(30);
|
|
||||||
private ReentrantLock lastUseLock;
|
|
||||||
private KMap<World, Long> lastUse;
|
|
||||||
private List<World> IrisWorlds;
|
|
||||||
private Looper cacheTicker;
|
|
||||||
private Looper trimTicker;
|
|
||||||
private Looper unloadTicker;
|
|
||||||
private Looper updateTicker;
|
|
||||||
private PrecisionStopwatch trimAlive;
|
|
||||||
private PrecisionStopwatch unloadAlive;
|
|
||||||
public PrecisionStopwatch trimActiveAlive;
|
|
||||||
public PrecisionStopwatch unloadActiveAlive;
|
|
||||||
private AtomicInteger TotalTectonicPlates;
|
|
||||||
private AtomicInteger TotalQueuedTectonicPlates;
|
|
||||||
private AtomicInteger TotalNotQueuedTectonicPlates;
|
|
||||||
private AtomicInteger failedTrim;
|
|
||||||
private AtomicInteger failedUnload;
|
|
||||||
private AtomicInteger failedSupply;
|
|
||||||
private AtomicBoolean IsUnloadAlive;
|
|
||||||
private AtomicBoolean IsTrimAlive;
|
|
||||||
ChronoLatch cl;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
this.cl = new ChronoLatch(5000);
|
|
||||||
lastUse = new KMap<>();
|
|
||||||
lastUseLock = new ReentrantLock();
|
|
||||||
IrisWorlds = new ArrayList<>();
|
|
||||||
IsUnloadAlive = new AtomicBoolean(true);
|
|
||||||
IsTrimAlive = new AtomicBoolean(true);
|
|
||||||
trimActiveAlive = new PrecisionStopwatch();
|
|
||||||
unloadActiveAlive = new PrecisionStopwatch();
|
|
||||||
trimAlive = new PrecisionStopwatch();
|
|
||||||
unloadAlive = new PrecisionStopwatch();
|
|
||||||
TotalTectonicPlates = new AtomicInteger();
|
|
||||||
TotalQueuedTectonicPlates = new AtomicInteger();
|
|
||||||
TotalNotQueuedTectonicPlates = new AtomicInteger();
|
|
||||||
failedTrim = new AtomicInteger();
|
|
||||||
failedUnload = new AtomicInteger();
|
|
||||||
failedSupply = new AtomicInteger();
|
|
||||||
tectonicLimit.set(2);
|
|
||||||
long t = getHardware.getProcessMemory();
|
|
||||||
while (t > 200) {
|
|
||||||
tectonicLimit.getAndAdd(1);
|
|
||||||
t = t - 200;
|
|
||||||
}
|
|
||||||
this.setup();
|
|
||||||
this.TrimLogic();
|
|
||||||
this.UnloadLogic();
|
|
||||||
|
|
||||||
trimAlive.begin();
|
|
||||||
unloadAlive.begin();
|
|
||||||
trimActiveAlive.begin();
|
|
||||||
unloadActiveAlive.begin();
|
|
||||||
|
|
||||||
updateTicker.start();
|
|
||||||
cacheTicker.start();
|
|
||||||
//trimTicker.start();
|
|
||||||
//unloadTicker.start();
|
|
||||||
instance = this;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void engineStatus() {
|
|
||||||
boolean trimAlive = trimTicker.isAlive();
|
|
||||||
boolean unloadAlive = unloadTicker.isAlive();
|
|
||||||
Iris.info("Status:");
|
|
||||||
Iris.info("- Trim: " + trimAlive);
|
|
||||||
Iris.info("- Unload: " + unloadAlive);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getTectonicLimit() {
|
|
||||||
return tectonicLimit.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onWorldUnload(WorldUnloadEvent event) {
|
|
||||||
updateWorlds();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onWorldLoad(WorldLoadEvent event) {
|
|
||||||
updateWorlds();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onServerBoot(ServerLoadEvent event) {
|
|
||||||
isServerLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPluginDisable(PluginDisableEvent event) {
|
|
||||||
if (event.getPlugin().equals(Iris.instance)) {
|
|
||||||
isServerShuttingDown = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateWorlds() {
|
|
||||||
for (World world : Bukkit.getWorlds()) {
|
|
||||||
try {
|
|
||||||
if (IrisToolbelt.access(world).getEngine() != null) {
|
|
||||||
IrisWorlds.add(world);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// no
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setup() {
|
|
||||||
cacheTicker = new Looper() {
|
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
lastUseLock.lock();
|
|
||||||
try {
|
|
||||||
for (World key : new ArrayList<>(lastUse.keySet())) {
|
|
||||||
Long last = lastUse.get(key);
|
|
||||||
if (last == null)
|
|
||||||
continue;
|
|
||||||
if (now - last > 60000) {
|
|
||||||
lastUse.remove(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
lastUseLock.unlock();
|
|
||||||
}
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
updateTicker = new Looper() {
|
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
try {
|
|
||||||
TotalQueuedTectonicPlates.set(0);
|
|
||||||
TotalNotQueuedTectonicPlates.set(0);
|
|
||||||
TotalTectonicPlates.set(0);
|
|
||||||
for (World world : IrisWorlds) {
|
|
||||||
Engine engine = Objects.requireNonNull(IrisToolbelt.access(world)).getEngine();
|
|
||||||
TotalQueuedTectonicPlates.addAndGet((int) engine.getMantle().getToUnload());
|
|
||||||
TotalNotQueuedTectonicPlates.addAndGet((int) engine.getMantle().getNotQueuedLoadedRegions());
|
|
||||||
TotalTectonicPlates.addAndGet(engine.getMantle().getLoadedRegionCount());
|
|
||||||
}
|
|
||||||
if (!isServerShuttingDown && isServerLoaded) {
|
|
||||||
if (!trimTicker.isAlive()) {
|
|
||||||
Iris.info(C.RED + "TrimTicker found dead! Booting it up!");
|
|
||||||
try {
|
|
||||||
TrimLogic();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Iris.error("What happened?");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!unloadTicker.isAlive()) {
|
|
||||||
Iris.info(C.RED + "UnloadTicker found dead! Booting it up!");
|
|
||||||
try {
|
|
||||||
UnloadLogic();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Iris.error("What happened?");
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 1000;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
public void TrimLogic() {
|
|
||||||
if (trimTicker == null || !trimTicker.isAlive()) {
|
|
||||||
trimTicker = new Looper() {
|
|
||||||
private final Supplier<Engine> supplier = createSupplier();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
trimAlive.reset();
|
|
||||||
try {
|
|
||||||
Engine engine = supplier.get();
|
|
||||||
if (engine != null) {
|
|
||||||
engine.getMantle().trim(tectonicLimit.get() / lastUse.size());
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
Iris.debug(C.RED + "EngineSVC: Failed to trim.");
|
|
||||||
failedTrim.getAndIncrement();
|
|
||||||
e.printStackTrace();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int size = lastUse.size();
|
|
||||||
long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start);
|
|
||||||
if (time <= 0)
|
|
||||||
return 0;
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
trimTicker.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void UnloadLogic() {
|
|
||||||
if (unloadTicker == null || !unloadTicker.isAlive()) {
|
|
||||||
unloadTicker = new Looper() {
|
|
||||||
private final Supplier<Engine> supplier = createSupplier();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
unloadAlive.reset();
|
|
||||||
try {
|
|
||||||
Engine engine = supplier.get();
|
|
||||||
if (engine != null) {
|
|
||||||
long unloadStart = System.currentTimeMillis();
|
|
||||||
int count = engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / lastUse.size());
|
|
||||||
if (count > 0) {
|
|
||||||
Iris.debug(C.GOLD + "Unloaded " + C.YELLOW + count + " TectonicPlates in " + C.RED + Form.duration(System.currentTimeMillis() - unloadStart, 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.reportError(e);
|
|
||||||
Iris.debug(C.RED + "EngineSVC: Failed to unload.");
|
|
||||||
failedUnload.getAndIncrement();
|
|
||||||
e.printStackTrace();
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int size = lastUse.size();
|
|
||||||
long time = (size > 0 ? 1000 / size : 1000) - (System.currentTimeMillis() - start);
|
|
||||||
if (time <= 0)
|
|
||||||
return 0;
|
|
||||||
return time;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
unloadTicker.start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Supplier<Engine> createSupplier() {
|
|
||||||
AtomicInteger i = new AtomicInteger();
|
|
||||||
return () -> {
|
|
||||||
List<World> worlds = Bukkit.getWorlds();
|
|
||||||
if (i.get() >= worlds.size()) {
|
|
||||||
i.set(0);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
for (int j = 0; j < worlds.size(); j++) {
|
|
||||||
World world = worlds.get(i.getAndIncrement());
|
|
||||||
PlatformChunkGenerator generator = IrisToolbelt.access(world);
|
|
||||||
if (i.get() >= worlds.size()) {
|
|
||||||
i.set(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (generator != null) {
|
|
||||||
Engine engine = generator.getEngine();
|
|
||||||
boolean closed = engine.getMantle().getData().isClosed();
|
|
||||||
if (engine != null && !engine.isStudio() && !closed) {
|
|
||||||
lastUseLock.lock();
|
|
||||||
lastUse.put(world, System.currentTimeMillis());
|
|
||||||
lastUseLock.unlock();
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable e) {
|
|
||||||
failedSupply.getAndIncrement();
|
|
||||||
Iris.debug(C.RED + "EngineSVC: Failed to create supplier.");
|
|
||||||
e.printStackTrace();
|
|
||||||
Iris.reportError(e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDisable() {
|
|
||||||
cacheTicker.interrupt();
|
|
||||||
trimTicker.interrupt();
|
|
||||||
unloadTicker.interrupt();
|
|
||||||
lastUse.clear();
|
|
||||||
}
|
|
||||||
}
|
|
@ -96,7 +96,7 @@ public class IrisPackBenchmarking {
|
|||||||
File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks");
|
File profilers = new File("plugins" + File.separator + "Iris" + File.separator + "packbenchmarks");
|
||||||
profilers.mkdir();
|
profilers.mkdir();
|
||||||
|
|
||||||
File results = new File("plugins" + File.separator + "Iris", IrisDimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt");
|
File results = new File(profilers, IrisDimension.getName() + " " + LocalDateTime.now(Clock.systemDefaultZone()).toString().replace(':', '-') + ".txt");
|
||||||
results.getParentFile().mkdirs();
|
results.getParentFile().mkdirs();
|
||||||
KMap<String, Double> metrics = engine.getMetrics().pull();
|
KMap<String, Double> metrics = engine.getMetrics().pull();
|
||||||
try (FileWriter writer = new FileWriter(results)) {
|
try (FileWriter writer = new FileWriter(results)) {
|
||||||
@ -124,7 +124,9 @@ public class IrisPackBenchmarking {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
Bukkit.getServer().unloadWorld("benchmark", true);
|
if (headless) engine.close();
|
||||||
|
else J.s(() -> Bukkit.unloadWorld("benchmark", true));
|
||||||
|
|
||||||
stopwatch.end();
|
stopwatch.end();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Iris.error("Something has gone wrong!");
|
Iris.error("Something has gone wrong!");
|
||||||
@ -171,8 +173,8 @@ public class IrisPackBenchmarking {
|
|||||||
.builder()
|
.builder()
|
||||||
.gui(gui)
|
.gui(gui)
|
||||||
.center(new Position2(x, z))
|
.center(new Position2(x, z))
|
||||||
.width(5)
|
.width(radius)
|
||||||
.height(5)
|
.height(radius)
|
||||||
.build(), headless ? new HeadlessPregenMethod(engine) : new HybridPregenMethod(engine.getWorld().realWorld(),
|
.build(), headless ? new HeadlessPregenMethod(engine) : new HybridPregenMethod(engine.getWorld().realWorld(),
|
||||||
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), engine);
|
IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getParallelism())), engine);
|
||||||
}
|
}
|
||||||
|
@ -296,7 +296,8 @@ public class IrisComplex implements DataProvider {
|
|||||||
var cache = new HashMap<DPair, IrisBiome>();
|
var cache = new HashMap<DPair, IrisBiome>();
|
||||||
double hi = interpolator.interpolate(x, z, (xx, zz) -> {
|
double hi = interpolator.interpolate(x, z, (xx, zz) -> {
|
||||||
try {
|
try {
|
||||||
IrisBiome bx = cache.computeIfAbsent(new DPair(xx, zz), k -> baseBiomeStream.get(k.x, k.z));
|
IrisBiome bx = baseBiomeStream.get(xx, zz);
|
||||||
|
cache.put(new DPair(xx, zz), bx);
|
||||||
double b = 0;
|
double b = 0;
|
||||||
|
|
||||||
for (IrisGenerator gen : generators) {
|
for (IrisGenerator gen : generators) {
|
||||||
@ -315,7 +316,7 @@ public class IrisComplex implements DataProvider {
|
|||||||
|
|
||||||
double lo = interpolator.interpolate(x, z, (xx, zz) -> {
|
double lo = interpolator.interpolate(x, z, (xx, zz) -> {
|
||||||
try {
|
try {
|
||||||
IrisBiome bx = cache.computeIfAbsent(new DPair(xx, zz), k -> baseBiomeStream.get(k.x, k.z));
|
IrisBiome bx = cache.get(new DPair(xx, zz));
|
||||||
double b = 0;
|
double b = 0;
|
||||||
|
|
||||||
for (IrisGenerator gen : generators) {
|
for (IrisGenerator gen : generators) {
|
||||||
|
@ -32,6 +32,7 @@ import com.volmit.iris.engine.framework.*;
|
|||||||
import com.volmit.iris.engine.mantle.EngineMantle;
|
import com.volmit.iris.engine.mantle.EngineMantle;
|
||||||
import com.volmit.iris.engine.object.*;
|
import com.volmit.iris.engine.object.*;
|
||||||
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
|
import com.volmit.iris.engine.scripting.EngineExecutionEnvironment;
|
||||||
|
import com.volmit.iris.engine.service.EngineEffectsSVC;
|
||||||
import com.volmit.iris.util.atomics.AtomicRollingSequence;
|
import com.volmit.iris.util.atomics.AtomicRollingSequence;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.context.ChunkContext;
|
import com.volmit.iris.util.context.ChunkContext;
|
||||||
@ -41,6 +42,7 @@ import com.volmit.iris.util.format.C;
|
|||||||
import com.volmit.iris.util.format.Form;
|
import com.volmit.iris.util.format.Form;
|
||||||
import com.volmit.iris.util.hunk.Hunk;
|
import com.volmit.iris.util.hunk.Hunk;
|
||||||
import com.volmit.iris.util.io.IO;
|
import com.volmit.iris.util.io.IO;
|
||||||
|
import com.volmit.iris.util.io.JarScanner;
|
||||||
import com.volmit.iris.util.mantle.MantleFlag;
|
import com.volmit.iris.util.mantle.MantleFlag;
|
||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
import com.volmit.iris.util.math.RNG;
|
import com.volmit.iris.util.math.RNG;
|
||||||
@ -62,9 +64,9 @@ import org.bukkit.entity.Player;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashSet;
|
import java.lang.reflect.Constructor;
|
||||||
import java.util.Set;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
@ -74,6 +76,8 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
@EqualsAndHashCode(exclude = "context")
|
@EqualsAndHashCode(exclude = "context")
|
||||||
@ToString(exclude = "context")
|
@ToString(exclude = "context")
|
||||||
public class IrisEngine implements Engine {
|
public class IrisEngine implements Engine {
|
||||||
|
private static final Map<Class<? extends IrisEngineService>, Constructor<? extends IrisEngineService>> SERVICES = scanServices();
|
||||||
|
private final KMap<Class<? extends IrisEngineService>, IrisEngineService> services;
|
||||||
private final AtomicInteger bud;
|
private final AtomicInteger bud;
|
||||||
private final AtomicInteger buds;
|
private final AtomicInteger buds;
|
||||||
private final AtomicInteger generated;
|
private final AtomicInteger generated;
|
||||||
@ -94,7 +98,6 @@ public class IrisEngine implements Engine {
|
|||||||
private final ChronoLatch cleanLatch;
|
private final ChronoLatch cleanLatch;
|
||||||
private final SeedManager seedManager;
|
private final SeedManager seedManager;
|
||||||
private EngineMode mode;
|
private EngineMode mode;
|
||||||
private EngineEffects effects;
|
|
||||||
private EngineExecutionEnvironment execution;
|
private EngineExecutionEnvironment execution;
|
||||||
private EngineWorldManager worldManager;
|
private EngineWorldManager worldManager;
|
||||||
private volatile int parallelism;
|
private volatile int parallelism;
|
||||||
@ -114,6 +117,7 @@ public class IrisEngine implements Engine {
|
|||||||
getEngineData();
|
getEngineData();
|
||||||
verifySeed();
|
verifySeed();
|
||||||
this.seedManager = new SeedManager(target.getWorld().getRawWorldSeed());
|
this.seedManager = new SeedManager(target.getWorld().getRawWorldSeed());
|
||||||
|
services = new KMap<>();
|
||||||
dataLock = new ReentrantLock();
|
dataLock = new ReentrantLock();
|
||||||
bud = new AtomicInteger(0);
|
bud = new AtomicInteger(0);
|
||||||
buds = new AtomicInteger(0);
|
buds = new AtomicInteger(0);
|
||||||
@ -154,17 +158,17 @@ public class IrisEngine implements Engine {
|
|||||||
bud.set(0);
|
bud.set(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effects != null) {
|
var effects = getService(EngineEffectsSVC.class);
|
||||||
effects.tickRandomPlayer();
|
if (effects != null) effects.tickRandomPlayer();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prehotload() {
|
private void prehotload() {
|
||||||
worldManager.close();
|
worldManager.close();
|
||||||
complex.close();
|
complex.close();
|
||||||
execution.close();
|
execution.close();
|
||||||
effects.close();
|
|
||||||
mode.close();
|
mode.close();
|
||||||
|
services.values().forEach(s -> s.onDisable(true));
|
||||||
|
services.values().forEach(Iris.instance::unregisterListener);
|
||||||
|
|
||||||
J.a(() -> new IrisProject(getData().getDataFolder()).updateWorkspace());
|
J.a(() -> new IrisProject(getData().getDataFolder()).updateWorkspace());
|
||||||
}
|
}
|
||||||
@ -173,10 +177,25 @@ public class IrisEngine implements Engine {
|
|||||||
try {
|
try {
|
||||||
Iris.debug("Setup Engine " + getCacheID());
|
Iris.debug("Setup Engine " + getCacheID());
|
||||||
cacheId = RNG.r.nextInt();
|
cacheId = RNG.r.nextInt();
|
||||||
|
boolean hotload = true;
|
||||||
|
if (services.isEmpty()) {
|
||||||
|
SERVICES.forEach((s, c) -> {
|
||||||
|
try {
|
||||||
|
services.put(s, c.newInstance(this));
|
||||||
|
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
|
||||||
|
Iris.error("Failed to create service " + s.getName());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
hotload = false;
|
||||||
|
}
|
||||||
|
for (var service : services.values()) {
|
||||||
|
service.onEnable(hotload);
|
||||||
|
Iris.instance.registerListener(service);
|
||||||
|
}
|
||||||
worldManager = new IrisWorldManager(this);
|
worldManager = new IrisWorldManager(this);
|
||||||
complex = new IrisComplex(this);
|
complex = new IrisComplex(this);
|
||||||
execution = new IrisExecutionEnvironment(this);
|
execution = new IrisExecutionEnvironment(this);
|
||||||
effects = new IrisEngineEffects(this);
|
|
||||||
setupMode();
|
setupMode();
|
||||||
J.a(this::computeBiomeMaxes);
|
J.a(this::computeBiomeMaxes);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@ -439,6 +458,12 @@ public class IrisEngine implements Engine {
|
|||||||
PregeneratorJob.shutdownInstance();
|
PregeneratorJob.shutdownInstance();
|
||||||
closed = true;
|
closed = true;
|
||||||
J.car(art);
|
J.car(art);
|
||||||
|
try {
|
||||||
|
if (getWorld().hasHeadless()) getWorld().headless().close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Iris.reportError(e);
|
||||||
|
}
|
||||||
|
services.values().forEach(s -> s.onDisable(false));
|
||||||
getWorldManager().close();
|
getWorldManager().close();
|
||||||
getTarget().close();
|
getTarget().close();
|
||||||
saveEngineData();
|
saveEngineData();
|
||||||
@ -554,6 +579,12 @@ public class IrisEngine implements Engine {
|
|||||||
return cacheId;
|
return cacheId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T extends IrisEngineService> T getService(Class<T> clazz) {
|
||||||
|
return (T) services.get(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean EngineSafe() {
|
private boolean EngineSafe() {
|
||||||
// Todo: this has potential if done right
|
// Todo: this has potential if done right
|
||||||
int EngineMCVersion = getEngineData().getStatistics().getMCVersion();
|
int EngineMCVersion = getEngineData().getStatistics().getMCVersion();
|
||||||
@ -568,4 +599,24 @@ public class IrisEngine implements Engine {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Map<Class<? extends IrisEngineService>, Constructor<? extends IrisEngineService>> scanServices() {
|
||||||
|
JarScanner js = new JarScanner(Iris.instance.getJarFile(), "com.volmit.iris.engine.service");
|
||||||
|
J.attempt(js::scan);
|
||||||
|
KMap<Class<? extends IrisEngineService>, Constructor<? extends IrisEngineService>> map = new KMap<>();
|
||||||
|
js.getClasses()
|
||||||
|
.stream()
|
||||||
|
.filter(IrisEngineService.class::isAssignableFrom)
|
||||||
|
.map(c -> (Class<? extends IrisEngineService>) c)
|
||||||
|
.forEach(c -> {
|
||||||
|
try {
|
||||||
|
map.put(c, c.getConstructor(Engine.class));
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
Iris.warn("Failed to load service " + c.getName() + " due to missing constructor");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Collections.unmodifiableMap(map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -534,8 +534,6 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EngineEffects getEffects();
|
|
||||||
|
|
||||||
default MultiBurst burst() {
|
default MultiBurst burst() {
|
||||||
return getTarget().getBurster();
|
return getTarget().getBurster();
|
||||||
}
|
}
|
||||||
@ -960,4 +958,5 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat
|
|||||||
J.a(() -> getMantle().cleanupChunk(x, z));
|
J.a(() -> getMantle().cleanupChunk(x, z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
<T extends IrisEngineService> T getService(Class<T> clazz);
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
|
||||||
* Copyright (c) 2022 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.engine.framework;
|
|
||||||
|
|
||||||
public interface EngineEffects extends EngineComponent {
|
|
||||||
void updatePlayerMap();
|
|
||||||
|
|
||||||
void tickRandomPlayer();
|
|
||||||
}
|
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class IrisEngineService implements Listener {
|
||||||
|
protected final Engine engine;
|
||||||
|
|
||||||
|
public abstract void onEnable(boolean hotload);
|
||||||
|
|
||||||
|
public abstract void onDisable(boolean hotload);
|
||||||
|
|
||||||
|
public final void postShutdown(Runnable r) {
|
||||||
|
Iris.instance.postShutdown(r);
|
||||||
|
}
|
||||||
|
}
|
@ -19,6 +19,7 @@
|
|||||||
package com.volmit.iris.engine.object;
|
package com.volmit.iris.engine.object;
|
||||||
|
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.nms.IHeadless;
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.util.collection.KList;
|
import com.volmit.iris.util.collection.KList;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
@ -48,6 +49,7 @@ public class IrisWorld {
|
|||||||
private long seed;
|
private long seed;
|
||||||
private World.Environment environment;
|
private World.Environment environment;
|
||||||
private World realWorld;
|
private World realWorld;
|
||||||
|
private IHeadless headless;
|
||||||
private int minHeight;
|
private int minHeight;
|
||||||
private int maxHeight;
|
private int maxHeight;
|
||||||
|
|
||||||
@ -91,6 +93,10 @@ public class IrisWorld {
|
|||||||
return realWorld != null;
|
return realWorld != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasHeadless() {
|
||||||
|
return headless != null;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Player> getPlayers() {
|
public List<Player> getPlayers() {
|
||||||
|
|
||||||
if (hasRealWorld()) {
|
if (hasRealWorld()) {
|
||||||
|
@ -1,27 +1,8 @@
|
|||||||
/*
|
package com.volmit.iris.engine.service;
|
||||||
* Iris is a World Generator for Minecraft Bukkit Servers
|
|
||||||
* Copyright (c) 2022 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.engine;
|
|
||||||
|
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
import com.volmit.iris.engine.framework.EngineAssignedComponent;
|
|
||||||
import com.volmit.iris.engine.framework.EngineEffects;
|
|
||||||
import com.volmit.iris.engine.framework.EnginePlayer;
|
import com.volmit.iris.engine.framework.EnginePlayer;
|
||||||
|
import com.volmit.iris.engine.object.IrisEngineService;
|
||||||
import com.volmit.iris.util.collection.KMap;
|
import com.volmit.iris.util.collection.KMap;
|
||||||
import com.volmit.iris.util.math.M;
|
import com.volmit.iris.util.math.M;
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
@ -31,19 +12,28 @@ import java.util.List;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
public class IrisEngineEffects extends EngineAssignedComponent implements EngineEffects {
|
public class EngineEffectsSVC extends IrisEngineService {
|
||||||
private final KMap<UUID, EnginePlayer> players;
|
private KMap<UUID, EnginePlayer> players;
|
||||||
private final Semaphore limit;
|
private Semaphore limit;
|
||||||
|
|
||||||
public IrisEngineEffects(Engine engine) {
|
public EngineEffectsSVC(Engine engine) {
|
||||||
super(engine, "FX");
|
super(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable(boolean hotload) {
|
||||||
players = new KMap<>();
|
players = new KMap<>();
|
||||||
limit = new Semaphore(1);
|
limit = new Semaphore(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public void onDisable(boolean hotload) {
|
||||||
|
players = null;
|
||||||
|
limit = null;
|
||||||
|
}
|
||||||
|
|
||||||
public void updatePlayerMap() {
|
public void updatePlayerMap() {
|
||||||
List<Player> pr = getEngine().getWorld().getPlayers();
|
List<Player> pr = engine.getWorld().getPlayers();
|
||||||
|
|
||||||
if (pr == null) {
|
if (pr == null) {
|
||||||
return;
|
return;
|
||||||
@ -52,7 +42,7 @@ public class IrisEngineEffects extends EngineAssignedComponent implements Engine
|
|||||||
for (Player i : pr) {
|
for (Player i : pr) {
|
||||||
boolean pcc = players.containsKey(i.getUniqueId());
|
boolean pcc = players.containsKey(i.getUniqueId());
|
||||||
if (!pcc) {
|
if (!pcc) {
|
||||||
players.put(i.getUniqueId(), new EnginePlayer(getEngine(), i));
|
players.put(i.getUniqueId(), new EnginePlayer(engine, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +53,6 @@ public class IrisEngineEffects extends EngineAssignedComponent implements Engine
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tickRandomPlayer() {
|
public void tickRandomPlayer() {
|
||||||
if (limit.tryAcquire()) {
|
if (limit.tryAcquire()) {
|
||||||
if (M.r(0.02)) {
|
if (M.r(0.02)) {
|
@ -0,0 +1,62 @@
|
|||||||
|
package com.volmit.iris.engine.service;
|
||||||
|
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.object.IrisEngineService;
|
||||||
|
import com.volmit.iris.util.collection.KList;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class EngineStatusSVC extends IrisEngineService {
|
||||||
|
private static final KList<EngineStatusSVC> INSTANCES = new KList<>();
|
||||||
|
|
||||||
|
public EngineStatusSVC(Engine engine) {
|
||||||
|
super(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable(boolean hotload) {
|
||||||
|
if (hotload) return;
|
||||||
|
synchronized (INSTANCES) {
|
||||||
|
INSTANCES.add(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable(boolean hotload) {
|
||||||
|
if (hotload) return;
|
||||||
|
|
||||||
|
synchronized (INSTANCES) {
|
||||||
|
INSTANCES.remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getEngineCount() {
|
||||||
|
return Math.max(INSTANCES.size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Status getStatus() {
|
||||||
|
synchronized (INSTANCES) {
|
||||||
|
long loadedChunks = 0;
|
||||||
|
long tectonicPlates = 0;
|
||||||
|
long activeTectonicPlates = 0;
|
||||||
|
long queuedTectonicPlates = 0;
|
||||||
|
long minTectonicUnloadDuration = Long.MAX_VALUE;
|
||||||
|
long maxTectonicUnloadDuration = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
for (var service : INSTANCES) {
|
||||||
|
var world = service.engine.getWorld();
|
||||||
|
if (world.hasRealWorld()) loadedChunks += world.realWorld().getLoadedChunks().length;
|
||||||
|
if (world.hasHeadless()) loadedChunks += world.headless().getLoadedChunks();
|
||||||
|
|
||||||
|
tectonicPlates += service.engine.getMantle().getLoadedRegionCount();
|
||||||
|
activeTectonicPlates += service.engine.getMantle().getNotQueuedLoadedRegions();
|
||||||
|
queuedTectonicPlates += service.engine.getMantle().getToUnload();
|
||||||
|
minTectonicUnloadDuration = Math.min(minTectonicUnloadDuration, (long) service.engine.getMantle().getTectonicDuration());
|
||||||
|
maxTectonicUnloadDuration = Math.max(maxTectonicUnloadDuration, (long) service.engine.getMantle().getTectonicDuration());
|
||||||
|
}
|
||||||
|
return new Status(INSTANCES.size(), loadedChunks, MantleCleanerSVC.getTectonicLimit(), tectonicPlates, activeTectonicPlates, queuedTectonicPlates, minTectonicUnloadDuration, maxTectonicUnloadDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public record Status(int engineCount, long loadedChunks, int tectonicLimit, long tectonicPlates, long activeTectonicPlates, long queuedTectonicPlates, long minTectonicUnloadDuration, long maxTectonicUnloadDuration) {}
|
||||||
|
}
|
@ -0,0 +1,123 @@
|
|||||||
|
package com.volmit.iris.engine.service;
|
||||||
|
|
||||||
|
import com.volmit.iris.Iris;
|
||||||
|
import com.volmit.iris.core.IrisSettings;
|
||||||
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
|
import com.volmit.iris.engine.object.IrisEngineService;
|
||||||
|
import com.volmit.iris.util.format.C;
|
||||||
|
import com.volmit.iris.util.math.M;
|
||||||
|
import com.volmit.iris.util.misc.getHardware;
|
||||||
|
import com.volmit.iris.util.scheduling.Looper;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.LongSupplier;
|
||||||
|
|
||||||
|
import static com.volmit.iris.engine.service.EngineStatusSVC.getEngineCount;
|
||||||
|
|
||||||
|
public class MantleCleanerSVC extends IrisEngineService {
|
||||||
|
private static final AtomicInteger tectonicLimit = new AtomicInteger(30);
|
||||||
|
private static final AtomicInteger idCounter = new AtomicInteger();
|
||||||
|
private int id = -1;
|
||||||
|
private Ticker trimmer;
|
||||||
|
private Ticker unloader;
|
||||||
|
|
||||||
|
public MantleCleanerSVC(Engine engine) {
|
||||||
|
super(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable(boolean hotload) {
|
||||||
|
if (engine.isStudio() && !IrisSettings.get().getPerformance().trimMantleInStudio)
|
||||||
|
return;
|
||||||
|
if (id == -1) id = idCounter.getAndIncrement();
|
||||||
|
if (trimmer == null || !trimmer.isAlive())
|
||||||
|
trimmer = createTrimmer(id, engine);
|
||||||
|
if (unloader == null || !unloader.isAlive())
|
||||||
|
unloader = createUnloader(id, engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable(boolean hotload) {
|
||||||
|
if (hotload) return;
|
||||||
|
if (trimmer != null) trimmer.await();
|
||||||
|
if (unloader != null) unloader.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
tectonicLimit.set(2);
|
||||||
|
long t = getHardware.getProcessMemory();
|
||||||
|
while (t > 200) {
|
||||||
|
tectonicLimit.incrementAndGet();
|
||||||
|
t = t - 200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getTectonicLimit() {
|
||||||
|
return tectonicLimit.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Ticker createTrimmer(int id, Engine engine) {
|
||||||
|
return new Ticker(() -> {
|
||||||
|
if (engine.isClosed()) return -1;
|
||||||
|
long start = M.ms();
|
||||||
|
try {
|
||||||
|
engine.getMantle().trim(tectonicLimit.get() / getEngineCount());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.debug(C.RED + "Mantle: Failed to trim.");
|
||||||
|
Iris.reportError(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (engine.isClosed()) return -1;
|
||||||
|
int size = getEngineCount();
|
||||||
|
return Math.max(1000 / size - (M.ms() - start), 0);
|
||||||
|
}, "Iris Mantle Trimmer-" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Ticker createUnloader(int id, Engine engine) {
|
||||||
|
return new Ticker(() -> {
|
||||||
|
if (engine.isClosed()) return -1;
|
||||||
|
long start = M.ms();
|
||||||
|
try {
|
||||||
|
engine.getMantle().unloadTectonicPlate(tectonicLimit.get() / getEngineCount());
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.debug(C.RED + "Mantle: Failed to unload.");
|
||||||
|
Iris.reportError(e);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (engine.isClosed()) return -1;
|
||||||
|
int size = getEngineCount();
|
||||||
|
return Math.max(1000 / size - (M.ms() - start), 0);
|
||||||
|
}, "Iris Mantle Unloader-" + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Ticker extends Looper {
|
||||||
|
private final LongSupplier supplier;
|
||||||
|
private final CountDownLatch exit = new CountDownLatch(1);
|
||||||
|
|
||||||
|
private Ticker(LongSupplier supplier, String name) {
|
||||||
|
this.supplier = supplier;
|
||||||
|
setPriority(Thread.MIN_PRIORITY);
|
||||||
|
setName(name);
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long loop() {
|
||||||
|
long wait = -1;
|
||||||
|
try {
|
||||||
|
wait = supplier.getAsLong();
|
||||||
|
} catch (Throwable ignored) {}
|
||||||
|
if (wait < 0) exit.countDown();
|
||||||
|
return wait;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void await() {
|
||||||
|
try {
|
||||||
|
exit.await();
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,6 @@ package com.volmit.iris.util.mantle;
|
|||||||
import com.google.common.util.concurrent.AtomicDouble;
|
import com.google.common.util.concurrent.AtomicDouble;
|
||||||
import com.volmit.iris.Iris;
|
import com.volmit.iris.Iris;
|
||||||
import com.volmit.iris.core.IrisSettings;
|
import com.volmit.iris.core.IrisSettings;
|
||||||
import com.volmit.iris.core.service.IrisCleanerSVC;
|
|
||||||
import com.volmit.iris.core.tools.IrisToolbelt;
|
import com.volmit.iris.core.tools.IrisToolbelt;
|
||||||
import com.volmit.iris.engine.data.cache.Cache;
|
import com.volmit.iris.engine.data.cache.Cache;
|
||||||
import com.volmit.iris.engine.framework.Engine;
|
import com.volmit.iris.engine.framework.Engine;
|
||||||
@ -41,6 +40,7 @@ import com.volmit.iris.util.matter.MatterSlice;
|
|||||||
import com.volmit.iris.util.parallel.BurstExecutor;
|
import com.volmit.iris.util.parallel.BurstExecutor;
|
||||||
import com.volmit.iris.util.parallel.HyperLock;
|
import com.volmit.iris.util.parallel.HyperLock;
|
||||||
import com.volmit.iris.util.parallel.MultiBurst;
|
import com.volmit.iris.util.parallel.MultiBurst;
|
||||||
|
import com.volmit.iris.util.scheduling.Looper;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.Chunk;
|
||||||
|
|
||||||
@ -61,6 +61,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
|
|
||||||
public class Mantle {
|
public class Mantle {
|
||||||
private static final boolean disableClear = System.getProperty("disableClear", "false").equals("true");
|
private static final boolean disableClear = System.getProperty("disableClear", "false").equals("true");
|
||||||
|
|
||||||
private final File dataFolder;
|
private final File dataFolder;
|
||||||
@Getter
|
@Getter
|
||||||
private final int worldHeight;
|
private final int worldHeight;
|
||||||
@ -425,8 +426,8 @@ public class Mantle {
|
|||||||
ioTrim.set(true);
|
ioTrim.set(true);
|
||||||
unloadLock.lock();
|
unloadLock.lock();
|
||||||
try {
|
try {
|
||||||
if (lastUse != null && IrisCleanerSVC.instance != null) {
|
if (lastUse == null || lastUse.isEmpty()) return;
|
||||||
if (!lastUse.isEmpty()) {
|
|
||||||
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0));
|
Iris.debug("Trimming Tectonic Plates older than " + Form.duration(adjustedIdleDuration.get(), 0));
|
||||||
for (long i : new ArrayList<>(lastUse.keySet())) {
|
for (long i : new ArrayList<>(lastUse.keySet())) {
|
||||||
double finalAdjustedIdleDuration = adjustedIdleDuration.get();
|
double finalAdjustedIdleDuration = adjustedIdleDuration.get();
|
||||||
@ -435,13 +436,9 @@ public class Mantle {
|
|||||||
if (lastUseTime != null && M.ms() - lastUseTime >= finalAdjustedIdleDuration) {
|
if (lastUseTime != null && M.ms() - lastUseTime >= finalAdjustedIdleDuration) {
|
||||||
toUnload.add(i);
|
toUnload.add(i);
|
||||||
Iris.debug("Tectonic Region added to unload");
|
Iris.debug("Tectonic Region added to unload");
|
||||||
IrisCleanerSVC.instance.trimActiveAlive.reset();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
} finally {
|
} finally {
|
||||||
@ -454,7 +451,6 @@ public class Mantle {
|
|||||||
AtomicInteger i = new AtomicInteger();
|
AtomicInteger i = new AtomicInteger();
|
||||||
unloadLock.lock();
|
unloadLock.lock();
|
||||||
BurstExecutor burst = null;
|
BurstExecutor burst = null;
|
||||||
if (IrisCleanerSVC.instance != null) {
|
|
||||||
try {
|
try {
|
||||||
KList<Long> copy = toUnload.copy();
|
KList<Long> copy = toUnload.copy();
|
||||||
if (!disableClear) toUnload.clear();
|
if (!disableClear) toUnload.clear();
|
||||||
@ -478,7 +474,6 @@ public class Mantle {
|
|||||||
if (disableClear) toUnload.remove(id);
|
if (disableClear) toUnload.remove(id);
|
||||||
i.incrementAndGet();
|
i.incrementAndGet();
|
||||||
Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id));
|
Iris.debug("Unloaded Tectonic Plate " + C.DARK_GREEN + Cache.keyX(id) + " " + Cache.keyZ(id));
|
||||||
IrisCleanerSVC.instance.unloadActiveAlive.reset();
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Iris.reportError(e);
|
Iris.reportError(e);
|
||||||
}
|
}
|
||||||
@ -496,8 +491,6 @@ public class Mantle {
|
|||||||
}
|
}
|
||||||
return i.get();
|
return i.get();
|
||||||
}
|
}
|
||||||
return i.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,33 +21,32 @@ import com.volmit.iris.util.hunk.view.ChunkDataHunkHolder;
|
|||||||
import com.volmit.iris.util.mantle.MantleFlag;
|
import com.volmit.iris.util.mantle.MantleFlag;
|
||||||
import com.volmit.iris.util.math.RNG;
|
import com.volmit.iris.util.math.RNG;
|
||||||
import com.volmit.iris.util.parallel.MultiBurst;
|
import com.volmit.iris.util.parallel.MultiBurst;
|
||||||
import com.volmit.iris.util.scheduling.Looper;
|
|
||||||
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.QuartPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
import net.minecraft.world.level.LevelHeightAccessor;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayDeque;
|
import java.util.concurrent.*;
|
||||||
import java.util.Queue;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class Headless implements IHeadless, LevelHeightAccessor {
|
public class Headless implements IHeadless, LevelHeightAccessor {
|
||||||
private final NMSBinding binding;
|
private final NMSBinding binding;
|
||||||
private final Engine engine;
|
private final Engine engine;
|
||||||
private final RegionFileStorage storage;
|
private final RegionFileStorage storage;
|
||||||
private final Queue<ProtoChunk> chunkQueue = new ArrayDeque<>();
|
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
private final ReentrantLock saveLock = new ReentrantLock();
|
private final AtomicInteger loadedChunks = new AtomicInteger();
|
||||||
private final KMap<String, Holder<Biome>> customBiomes = new KMap<>();
|
private final KMap<String, Holder<Biome>> customBiomes = new KMap<>();
|
||||||
private final KMap<org.bukkit.block.Biome, Holder<Biome>> minecraftBiomes = new KMap<>();
|
private final KMap<org.bukkit.block.Biome, Holder<Biome>> minecraftBiomes = new KMap<>();
|
||||||
private final RNG BIOME_RNG;
|
private final RNG BIOME_RNG;
|
||||||
@ -56,17 +55,9 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
public Headless(NMSBinding binding, Engine engine) {
|
public Headless(NMSBinding binding, Engine engine) {
|
||||||
this.binding = binding;
|
this.binding = binding;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.storage = new RegionFileStorage(new File(engine.getWorld().worldFolder(), "region").toPath(), false);
|
this.storage = new RegionFileStorage(new File(engine.getWorld().worldFolder(), "region").toPath(), true);
|
||||||
this.BIOME_RNG = new RNG(engine.getSeedManager().getBiome());
|
this.BIOME_RNG = new RNG(engine.getSeedManager().getBiome());
|
||||||
var queueLooper = new Looper() {
|
engine.getWorld().headless(this);
|
||||||
@Override
|
|
||||||
protected long loop() {
|
|
||||||
save();
|
|
||||||
return closed ? -1 : 100;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
queueLooper.setName("Region Save Looper");
|
|
||||||
queueLooper.start();
|
|
||||||
|
|
||||||
var dimKey = engine.getDimension().getLoadKey();
|
var dimKey = engine.getDimension().getLoadKey();
|
||||||
for (var biome : engine.getAllBiomes()) {
|
for (var biome : engine.getAllBiomes()) {
|
||||||
@ -83,6 +74,11 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
ServerConfigurator.dumpDataPack();
|
ServerConfigurator.dumpDataPack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLoadedChunks() {
|
||||||
|
return loadedChunks.get();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the mca plate is fully generated or not.
|
* Checks if the mca plate is fully generated or not.
|
||||||
*
|
*
|
||||||
@ -101,26 +97,6 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save() {
|
|
||||||
if (closed) return;
|
|
||||||
saveLock.lock();
|
|
||||||
try {
|
|
||||||
while (!chunkQueue.isEmpty()) {
|
|
||||||
ChunkAccess chunk = chunkQueue.poll();
|
|
||||||
if (chunk == null) break;
|
|
||||||
try {
|
|
||||||
storage.write(chunk.getPos(), binding.serializeChunk(chunk, this));
|
|
||||||
} catch (Throwable e) {
|
|
||||||
Iris.error("Failed to save chunk " + chunk.getPos().x + ", " + chunk.getPos().z);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
saveLock.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void generateRegion(MultiBurst burst, int x, int z, PregenListener listener) {
|
public void generateRegion(MultiBurst burst, int x, int z, PregenListener listener) {
|
||||||
if (closed) return;
|
if (closed) return;
|
||||||
@ -157,6 +133,7 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
var pos = new ChunkPos(x, z);
|
var pos = new ChunkPos(x, z);
|
||||||
ProtoChunk chunk = binding.createProtoChunk(pos, this);
|
ProtoChunk chunk = binding.createProtoChunk(pos, this);
|
||||||
var tc = new MCATerrainChunk(chunk);
|
var tc = new MCATerrainChunk(chunk);
|
||||||
|
loadedChunks.incrementAndGet();
|
||||||
|
|
||||||
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
|
ChunkDataHunkHolder blocks = new ChunkDataHunkHolder(tc);
|
||||||
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
|
BiomeGridHunkHolder biomes = new BiomeGridHunkHolder(tc, tc.getMinHeight(), tc.getMaxHeight());
|
||||||
@ -166,13 +143,27 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
|
|
||||||
inject(engine, chunk, ctx);
|
inject(engine, chunk, ctx);
|
||||||
chunk.setStatus(ChunkStatus.FULL);
|
chunk.setStatus(ChunkStatus.FULL);
|
||||||
chunkQueue.add(chunk);
|
executor.submit(saveChunk(chunk));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
|
loadedChunks.decrementAndGet();
|
||||||
Iris.error("Failed to generate " + x + ", " + z);
|
Iris.error("Failed to generate " + x + ", " + z);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Runnable saveChunk(ProtoChunk chunk) {
|
||||||
|
return () -> {
|
||||||
|
if (closed) return;
|
||||||
|
try {
|
||||||
|
storage.write(chunk.getPos(), binding.serializeChunk(chunk, this));
|
||||||
|
loadedChunks.decrementAndGet();
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Iris.error("Failed to save chunk " + chunk.getPos().x + ", " + chunk.getPos().z);
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@BlockCoordinates
|
@BlockCoordinates
|
||||||
private ChunkContext generate(Engine engine, int x, int z, Hunk<BlockData> vblocks, Hunk<org.bukkit.block.Biome> vbiomes) throws WrongEngineBroException {
|
private ChunkContext generate(Engine engine, int x, int z, Hunk<BlockData> vblocks, Hunk<org.bukkit.block.Biome> vbiomes) throws WrongEngineBroException {
|
||||||
if (engine.isClosed()) {
|
if (engine.isClosed()) {
|
||||||
@ -214,32 +205,33 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void inject(Engine engine, ChunkAccess chunk, ChunkContext ctx) {
|
private void inject(Engine engine, ChunkAccess chunk, ChunkContext ctx) {
|
||||||
var pos = chunk.getPos();
|
chunk.fillBiomesFromNoise((qX, qY, qZ, sampler) -> getNoiseBiome(engine, ctx, qX << 2, qY << 2, qZ << 2), null);
|
||||||
for (int y = engine.getMinHeight(); y < engine.getMaxHeight(); y++) {
|
/*
|
||||||
for (int x = 0; x < 16; x++) {
|
int qX = QuartPos.fromBlock(chunk.getPos().getMinBlockX());
|
||||||
for (int z = 0; z < 16; z++) {
|
int qZ = QuartPos.fromBlock(chunk.getPos().getMinBlockZ());
|
||||||
int wX = pos.getBlockX(x);
|
|
||||||
int wZ = pos.getBlockZ(z);
|
for (int i = chunk.getMinSection(); i < chunk.getMaxSection(); i++) {
|
||||||
try {
|
var section = chunk.getSection(chunk.getSectionIndexFromSectionY(i));
|
||||||
chunk.setBiome(x, y, z, getNoiseBiome(engine, ctx, x, z, wX, y, wZ));
|
PalettedContainer<Holder<Biome>> biomes = (PalettedContainer<Holder<Biome>>) section.getBiomes();
|
||||||
} catch (Throwable e) {
|
int qY = QuartPos.fromSection(i);
|
||||||
Iris.error("Failed to inject biome for " + wX + ", " + y + ", " + wZ);
|
|
||||||
e.printStackTrace();
|
for (int sX = 0; sX < 4; sX++) {
|
||||||
}
|
for (int sZ = 0; sZ < 4; sZ++) {
|
||||||
|
for (int sY = 0; sY < 4; sY++) {
|
||||||
|
biomes.getAndSetUnchecked(sX, sY, sZ, getNoiseBiome(engine, ctx, (qX + sX) << 2, (qY + sY) << 2, (qZ + sZ) << 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private Holder<Biome> getNoiseBiome(Engine engine, ChunkContext ctx, int rX, int rZ, int x, int y, int z) {
|
private Holder<Biome> getNoiseBiome(Engine engine, ChunkContext ctx, int x, int y, int z) {
|
||||||
int m = (y - engine.getMinHeight()) << 2;
|
int m = y - engine.getMinHeight();
|
||||||
IrisBiome ib = ctx == null ?
|
IrisBiome ib = ctx == null ? engine.getSurfaceBiome(x, z) : ctx.getBiome().get(x & 15, z & 15);
|
||||||
engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2) :
|
|
||||||
ctx.getBiome().get(rX, rZ);
|
|
||||||
if (ib.isCustom()) {
|
if (ib.isCustom()) {
|
||||||
return customBiomes.get(ib.getCustomBiome(BIOME_RNG, x << 2, m, z << 2).getId());
|
return customBiomes.get(ib.getCustomBiome(BIOME_RNG, x, m, z).getId());
|
||||||
} else {
|
} else {
|
||||||
return minecraftBiomes.get(ib.getSkyBiome(BIOME_RNG, x << 2, m, z << 2));
|
return minecraftBiomes.get(ib.getSkyBiome(BIOME_RNG, x, m, z));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +239,13 @@ public class Headless implements IHeadless, LevelHeightAccessor {
|
|||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (closed) return;
|
if (closed) return;
|
||||||
try {
|
try {
|
||||||
|
executor.shutdown();
|
||||||
|
try {
|
||||||
|
if (executor.awaitTermination(10, TimeUnit.SECONDS))
|
||||||
|
executor.shutdownNow();
|
||||||
|
} catch (InterruptedException ignored) {}
|
||||||
storage.close();
|
storage.close();
|
||||||
|
engine.getWorld().headless(null);
|
||||||
} finally {
|
} finally {
|
||||||
closed = true;
|
closed = true;
|
||||||
customBiomes.clear();
|
customBiomes.clear();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user