9
0
mirror of https://github.com/VolmitSoftware/Iris.git synced 2025-12-26 02:29:14 +00:00

Merge pull request #830 from VolmitSoftware/Development

Development
This commit is contained in:
Brian Fopiano
2022-07-21 19:38:44 -07:00
committed by GitHub
12 changed files with 253 additions and 9 deletions

View File

@@ -26,6 +26,7 @@ import com.volmit.iris.core.ServerConfigurator;
import com.volmit.iris.core.link.*;
import com.volmit.iris.core.loader.IrisData;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.core.pregenerator.LazyPregenerator;
import com.volmit.iris.core.service.StudioSVC;
import com.volmit.iris.core.tools.IrisToolbelt;
import com.volmit.iris.engine.EnginePanic;
@@ -404,6 +405,7 @@ public class Iris extends VolmitPlugin implements Listener {
J.s(() -> {
J.a(() -> PaperLib.suggestPaper(this));
J.a(() -> IO.delete(getTemp()));
J.a(LazyPregenerator::loadLazyGenerators, 100);
J.a(this::bstats);
J.ar(this::checkConfigHotload, 60);
J.sr(this::tickQueue, 0);

View File

@@ -38,14 +38,16 @@ import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.jobs.QueueJob;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Decree(name = "iris", aliases = {"ir", "irs", "i"}, description = "Basic Command")
@Decree(name = "iris", aliases = {"ir", "irs"}, description = "Basic Command")
public class CommandIris implements DecreeExecutor {
private CommandStudio studio;
private CommandPregen pregen;
@@ -96,6 +98,37 @@ public class CommandIris implements DecreeExecutor {
sender().sendMessage(C.GREEN + "Successfully created your world!");
}
@Decree(description = "Remove an Iris world", aliases = {"del", "rm"}, sync = true)
public void remove(
@Param(description = "The world to remove")
World world,
@Param(description = "Whether to also remove the folder (if set to false, just does not load the world)", defaultValue = "true")
boolean delete
) {
if (!IrisToolbelt.isIrisWorld(world)) {
sender().sendMessage(C.RED + "This is not an Iris world. Iris worlds: " + String.join(", ", Bukkit.getServer().getWorlds().stream().filter(IrisToolbelt::isIrisWorld).map(World::getName).toList()));
return;
}
sender().sendMessage(C.GREEN + "Removing world: " + world.getName());
try {
if (IrisToolbelt.removeWorld(world)) {
sender().sendMessage(C.GREEN + "Successfully removed " + world.getName() + " from bukkit.yml");
} else {
sender().sendMessage(C.YELLOW + "Looks like the world was already removed from bukkit.yml");
}
} catch (IOException e) {
sender().sendMessage(C.RED + "Failed to save bukkit.yml because of " + e.getMessage());
e.printStackTrace();
}
IrisToolbelt.evacuate(world, "Deleting world");
Bukkit.unloadWorld(world, false);
if (delete && world.getWorldFolder().delete()) {
sender().sendMessage(C.GREEN + "Successfully removed world folder");
} else {
sender().sendMessage(C.RED + "Failed to remove world folder");
}
}
@Decree(description = "Print version information")
public void version() {
sender().sendMessage(C.GREEN + "Iris v" + Iris.instance.getDescription().getVersion() + " by Volmit Software");

View File

@@ -83,7 +83,6 @@ public class PregeneratorJob implements PregenListener {
this.pregenerator = new IrisPregenerator(task, method, this);
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()));

View File

@@ -0,0 +1,178 @@
package com.volmit.iris.core.pregenerator;
import com.google.gson.Gson;
import com.volmit.iris.Iris;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.math.Spiraler;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import io.papermc.lib.PaperLib;
import lombok.Builder;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldUnloadEvent;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
public class LazyPregenerator extends Thread implements Listener
{
private final LazyPregenJob job;
private final File destination;
private final int maxPosition;
private final World world;
private final long rate;
private final ChronoLatch latch;
public LazyPregenerator(LazyPregenJob job, File destination)
{
this.job = job;
this.destination = destination;
this.maxPosition = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {}).count();
this.world = Bukkit.getWorld(job.getWorld());
this.rate = Math.round((1D / (job.chunksPerMinute / 60D)) * 1000D);
this.latch = new ChronoLatch(60000);
}
public LazyPregenerator(File file) throws IOException {
this(new Gson().fromJson(IO.readAll(file), LazyPregenJob.class), file);
}
@EventHandler
public void on(WorldUnloadEvent e)
{
if(e.getWorld().equals(world)) {
interrupt();
}
}
public void run()
{
while(!interrupted()) {
J.sleep(rate);
tick();
}
try {
saveNow();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void tick() {
if(latch.flip())
{
save();
Iris.info("LazyGen: " + world.getName() + " RTT: " + Form.duration((Math.pow((job.radiusBlocks / 16D), 2) / job.chunksPerMinute) * 60 * 1000, 2));
}
if(job.getPosition() >= maxPosition)
{
if(job.isHealing())
{
int pos = (job.getHealingPosition() + 1) % maxPosition;
job.setHealingPosition(pos);
tickRegenerate(getChunk(pos));
}
else
{
Iris.verbose("Completed Lazy Gen!");
interrupt();
}
}
else
{
int pos = job.getPosition() + 1;
job.setPosition(pos);
tickGenerate(getChunk(pos));
}
}
private void tickGenerate(Position2 chunk) {
if(PaperLib.isPaper()) {
PaperLib.getChunkAtAsync(world, chunk.getX(), chunk.getZ(), true).thenAccept((i) -> Iris.verbose("Generated Async " + chunk));
}
else {
J.s(() -> world.getChunkAt(chunk.getX(), chunk.getZ()));
Iris.verbose("Generated " + chunk);
}
}
private void tickRegenerate(Position2 chunk) {
J.s(() -> world.regenerateChunk(chunk.getX(), chunk.getZ()));
Iris.verbose("Regenerated " + chunk);
}
public Position2 getChunk(int position)
{
int p = -1;
AtomicInteger xx = new AtomicInteger();
AtomicInteger zz = new AtomicInteger();
Spiraler s = new Spiraler(job.getRadiusBlocks() * 2, job.getRadiusBlocks() * 2, (x, z) -> {
xx.set(x);
zz.set(z);
});
while(s.hasNext() && p++ < position) {
s.next();
}
return new Position2(xx.get(), zz.get());
}
public void save()
{
J.a(() -> {
try {
saveNow();
}
catch (Throwable e) {
e.printStackTrace();
}
});
}
public void saveNow() throws IOException {
IO.writeAll(this.destination, new Gson().toJson(job));
}
public static void loadLazyGenerators()
{
for(World i : Bukkit.getWorlds())
{
File lazygen = new File(i.getWorldFolder(), "lazygen.json");
if(lazygen.exists()) {
try {
LazyPregenerator p = new LazyPregenerator(lazygen);
p.start();
Iris.info("Started Lazy Pregenerator: " + p.job);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@Data
@Builder
public static class LazyPregenJob
{
private String world;
@Builder.Default private int healingPosition = 0;
@Builder.Default private boolean healing = false;
@Builder.Default private int chunksPerMinute = 32; // 48 hours is roughly 5000 radius
@Builder.Default private int radiusBlocks = 5000;
@Builder.Default private int position = 0;
}
}

View File

@@ -231,4 +231,18 @@ public class IrisCreator {
}
}
}
public static boolean removeFromBukkitYml(String name) throws IOException {
YamlConfiguration yml = YamlConfiguration.loadConfiguration(BUKKIT_YML);
ConfigurationSection section = yml.getConfigurationSection("worlds");
if (section == null) {
return false;
}
section.set(name, null);
if (section.getValues(false).keySet().stream().noneMatch(k -> section.get(k) != null)) {
yml.set("worlds", null);
}
yml.save(BUKKIT_YML);
return true;
}
}

View File

@@ -36,6 +36,7 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@@ -221,7 +222,6 @@ public class IrisToolbelt {
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world. " + m);
j.teleport(i.getSpawnLocation());
}
return true;
}
}
@@ -248,4 +248,8 @@ public class IrisToolbelt {
if(e == null) {return;}
e.getEngine().getMantle().getMantle().remove(x, y - world.getMinHeight(), z, of);
}
public static boolean removeWorld(World world) throws IOException {
return IrisCreator.removeFromBukkitYml(world.getName());
}
}

View File

@@ -55,7 +55,7 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
bd = decorator.getBlockData100(biome, getRng(), realX, height, realZ, getData());
if(!underwater) {
if(!canGoOn(bd, bdx)) {
if(!canGoOn(bd, bdx) && !decorator.isForcePlace()) {
return;
}
}
@@ -72,8 +72,9 @@ public class IrisSurfaceDecorator extends IrisEngineDecorator {
((Bisected) bd).setHalf(Bisected.Half.BOTTOM);
}
if(decorator.getForceBlock() != null)
data.set(x, height, z, decorator.getForceBlock().getBlockData(getData()));
data.set(x, height + 1, z, bd);
} else {
if(height < getDimension().getFluidHeight()) {
max = getDimension().getFluidHeight();

View File

@@ -53,6 +53,8 @@ public class IrisDecorator {
private IrisGeneratorStyle variance = NoiseStyle.STATIC.style();
@Desc("Forcefully place this decorant anywhere it is supposed to go even if it should not go on a specific surface block. For example, you could force tallgrass to place on top of stone by using this.")
private boolean forcePlace = false;
@Desc("Forced the surface block of this decorant to be the specified block. Assumes forcePlace.")
private IrisBlockData forceBlock;
@DependsOn({"scaleStack", "stackMin", "stackMax"})
@Desc("If stackMax is set to true, use this to limit its max height for large caverns")
private int absoluteMaxStack = 30;

View File

@@ -799,7 +799,7 @@ public class IrisObject extends IrisRegistrant {
continue;
}
if(config.isWaterloggable() && yy <= placer.getFluidHeight() && data instanceof Waterlogged) {
if((config.isWaterloggable() || config.isUnderwater()) && yy <= placer.getFluidHeight() && data instanceof Waterlogged) {
((Waterlogged) data).setWaterlogged(true);
}
@@ -849,6 +849,7 @@ public class IrisObject extends IrisRegistrant {
BlockVector i = g.clone();
i = config.getRotation().rotate(i.clone(), spinx, spiny, spinz).clone();
i = config.getTranslate().translate(i.clone(), config.getRotation(), spinx, spiny, spinz).clone();
d = config.getRotation().rotate(d, spinx, spiny, spinz);
if(i.getBlockY() != lowest)
continue;
@@ -882,7 +883,7 @@ public class IrisObject extends IrisRegistrant {
int highest = placer.getHighest(xx, zz, getLoader(), true);
if(config.isWaterloggable() && highest <= placer.getFluidHeight() && d instanceof Waterlogged)
if((config.isWaterloggable() || config.isUnderwater()) && highest <= placer.getFluidHeight() && d instanceof Waterlogged)
((Waterlogged) d).setWaterlogged(true);
if(yv >= 0 && config.isBottom())

View File

@@ -75,4 +75,14 @@ public class Spiraler {
z += dz;
i++;
}
public int count() {
int c = 0;
while(hasNext()) {
next();
c++;
}
return c;
}
}