Can you smell the rot?

This commit is contained in:
Daniel Mills 2021-08-08 07:50:15 -04:00
parent 2ffd1e6e47
commit a8a87e7f79
7 changed files with 0 additions and 1826 deletions

View File

@ -1,91 +0,0 @@
/*
* 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.tools;
import com.volmit.iris.Iris;
import com.volmit.iris.engine.framework.IrisAccess;
import com.volmit.iris.engine.framework.IrisAccessProvider;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.plugin.VolmitSender;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Player;
@SuppressWarnings("ALL")
public class IrisWorlds {
private static final KMap<String, IrisAccess> provisioned = new KMap<>();
public static void register(World w, IrisAccess p) {
provisioned.put(w.getUID().toString(), p);
}
public static boolean isIrisWorld(World world) {
if (world == null) {
return false;
}
if (provisioned.containsKey(world.getUID().toString())) {
return true;
}
return world.getGenerator() instanceof IrisAccess || world.getGenerator() instanceof IrisAccessProvider;
}
public static IrisAccess access(World world) {
if (isIrisWorld(world)) {
if (provisioned.containsKey(world.getUID().toString())) {
return provisioned.get(world.getUID().toString());
}
return world.getGenerator() instanceof IrisAccessProvider ? (((IrisAccessProvider) world.getGenerator()).getAccess()) : ((IrisAccess) world.getGenerator());
}
return null;
}
public static boolean evacuate(World world) {
for (World i : Bukkit.getWorlds()) {
if (!i.getName().equals(world.getName())) {
for (Player j : world.getPlayers()) {
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world.");
j.teleport(i.getSpawnLocation());
}
return true;
}
}
return false;
}
public static boolean evacuate(World world, String m) {
for (World i : Bukkit.getWorlds()) {
if (!i.getName().equals(world.getName())) {
for (Player j : world.getPlayers()) {
new VolmitSender(j, Iris.instance.getTag()).sendMessage("You have been evacuated from this world. " + m);
j.teleport(i.getSpawnLocation());
}
return true;
}
}
return false;
}
}

View File

@ -1,288 +0,0 @@
/*
* 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.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.project.loader.IrisData;
import com.volmit.iris.engine.framework.Engine;
import com.volmit.iris.engine.framework.EngineCompound;
import com.volmit.iris.engine.framework.EngineData;
import com.volmit.iris.engine.framework.EngineTarget;
import com.volmit.iris.engine.object.basic.IrisPosition;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.object.dimensional.IrisDimension;
import com.volmit.iris.engine.object.dimensional.IrisDimensionIndex;
import com.volmit.iris.util.atomics.AtomicRollingSequence;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.documentation.BlockCoordinates;
import com.volmit.iris.util.documentation.ChunkCoordinates;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler;
import org.bukkit.event.world.WorldSaveEvent;
import org.bukkit.generator.BlockPopulator;
import java.io.File;
import java.util.List;
public class IrisEngineCompound implements EngineCompound {
@Getter
private final IrisWorld world;
private final AtomicRollingSequence wallClock;
private Engine defaultEngine;
@Getter
private final EngineData engineMetadata;
private final Engine[] engines;
@Getter
private final MultiBurst burster;
@Getter
private final KList<BlockPopulator> populators;
@Getter
private final IrisDimension rootDimension;
@Getter
private final int threadCount = -1;
@Getter
@Setter
private boolean studio;
public IrisEngineCompound(IrisWorld world, IrisDimension rootDimension, IrisData data, int maximumThreads) {
wallClock = new AtomicRollingSequence(32);
this.rootDimension = rootDimension;
Iris.info("Initializing Engine Composite for " + world.name());
this.world = world;
engineMetadata = EngineData.load(getEngineMetadataFile());
engineMetadata.setDimension(rootDimension.getLoadKey());
engineMetadata.setLastVersion(Iris.instance.getDescription().getVersion());
saveEngineMetadata();
populators = new KList<>();
if (rootDimension.getDimensionalComposite().isEmpty()) {
burster = null;
// TODO: WARNING HEIGHT
engines = new Engine[]{new IrisEngine(new EngineTarget(world, rootDimension, data, 256, maximumThreads), this, 0)};
defaultEngine = engines[0];
} else {
double totalWeight = 0D;
engines = new Engine[rootDimension.getDimensionalComposite().size()];
burster = engines.length > 1 ? new MultiBurst("Iris Compound " + rootDimension.getName(), IrisSettings.get().getConcurrency().getEngineThreadPriority(), engines.length) : null;
int threadDist = (Math.max(2, maximumThreads - engines.length)) / engines.length;
if ((threadDist * engines.length) + engines.length > maximumThreads) {
Iris.warn("Using " + ((threadDist * engines.length) + engines.length) + " threads instead of the configured " + maximumThreads + " maximum thread count due to the requirements of this dimension!");
}
for (IrisDimensionIndex i : rootDimension.getDimensionalComposite()) {
totalWeight += i.getWeight();
}
int buf = 0;
for (int i = 0; i < engines.length; i++) {
IrisDimensionIndex index = rootDimension.getDimensionalComposite().get(i);
IrisDimension dimension = data.getDimensionLoader().load(index.getDimension());
// TODO: WARNING HEIGHT
engines[i] = new IrisEngine(new EngineTarget(world, dimension, data.copy(), (int) Math.floor(256D * (index.getWeight() / totalWeight)), index.isInverted(), threadDist), this, i);
engines[i].setMinHeight(buf);
buf += engines[i].getHeight();
if (index.isPrimary()) {
defaultEngine = engines[i];
}
}
if (defaultEngine == null) {
defaultEngine = engines[0];
}
}
for (Engine i : engines) {
if (i instanceof BlockPopulator) {
populators.add((BlockPopulator) i);
}
}
Iris.instance.registerListener(this);
}
public List<IrisPosition> getStrongholdPositions() {
return engineMetadata.getStrongholdPositions();
}
@EventHandler
public void on(WorldSaveEvent e) {
if (world != null && e.getWorld().equals(world)) {
save();
}
}
public void printMetrics(CommandSender sender) {
KMap<String, Double> totals = new KMap<>();
KMap<String, Double> weights = new KMap<>();
double masterWallClock = wallClock.getAverage();
for (int i = 0; i < getSize(); i++) {
Engine e = getEngine(i);
KMap<String, Double> timings = e.getMetrics().pull();
double totalWeight = 0;
double wallClock = e.getMetrics().getTotal().getAverage();
for (double j : timings.values()) {
totalWeight += j;
}
for (String j : timings.k()) {
weights.put(e.getName() + "[" + e.getIndex() + "]." + j, (wallClock / totalWeight) * timings.get(j));
}
totals.put(e.getName() + "[" + e.getIndex() + "]", wallClock);
}
double mtotals = 0;
for (double i : totals.values()) {
mtotals += i;
}
for (String i : totals.k()) {
totals.put(i, (masterWallClock / mtotals) * totals.get(i));
}
double v = 0;
for (double i : weights.values()) {
v += i;
}
for (String i : weights.k()) {
weights.put(i, weights.get(i) / v);
}
sender.sendMessage("Total: " + C.BOLD + C.WHITE + Form.duration(masterWallClock, 0));
for (String i : totals.k()) {
sender.sendMessage(" Engine " + C.UNDERLINE + C.GREEN + i + C.RESET + ": " + C.BOLD + C.WHITE + Form.duration(totals.get(i), 0));
}
sender.sendMessage("Details: ");
for (String i : weights.sortKNumber().reverse()) {
String befb = C.UNDERLINE + "" + C.GREEN + "" + i.split("\\Q[\\E")[0] + C.RESET + C.GRAY + "[";
String num = C.GOLD + i.split("\\Q[\\E")[1].split("]")[0] + C.RESET + C.GRAY + "].";
String afb = C.ITALIC + "" + C.AQUA + i.split("\\Q]\\E")[1].substring(1) + C.RESET + C.GRAY;
sender.sendMessage(" " + befb + num + afb + ": " + C.BOLD + C.WHITE + Form.pc(weights.get(i), 0));
}
}
private File getEngineMetadataFile() {
return new File(world.worldFolder(), "iris/engine-metadata.json");
}
@ChunkCoordinates
@Override
public void generate(int x, int z, Hunk<BlockData> blocks, Hunk<BlockData> postblocks, Hunk<Biome> biomes, boolean multicore) {
recycle();
PrecisionStopwatch p = PrecisionStopwatch.start();
if (engines.length == 1 && !getEngine(0).getTarget().isInverted()) {
engines[0].generate(x, z, blocks, biomes, multicore);
} else {
int i;
int offset = 0;
for (i = 0; i < engines.length; i++) {
Engine engine = engines[i];
int doffset = offset;
int height = engine.getTarget().getHeight();
Hunk<BlockData> cblock = Hunk.newArrayHunk(16, height, 16);
Hunk<Biome> cbiome = Hunk.newArrayHunk(16, height, 16);
if (engine.getTarget().isInverted()) {
cblock = cblock.invertY();
cbiome = cbiome.invertY();
}
engine.generate(x, z, cblock, cbiome, multicore);
blocks.insert(0, doffset, 0, cblock);
biomes.insert(0, doffset, 0, cbiome);
offset += height;
}
}
wallClock.put(p.getMilliseconds());
}
@Override
public int getSize() {
return engines.length;
}
@Override
public Engine getEngine(int index) {
return engines[index];
}
@Override
public void saveEngineMetadata() {
engineMetadata.save(getEngineMetadataFile());
}
@BlockCoordinates
@Override
public IrisData getData(int height) {
return getEngineForHeight(height).getData();
}
//TODO: FAIL
@Override
public boolean isFailing() {
return false;
}
@Override
public Engine getDefaultEngine() {
return defaultEngine;
}
@Override
public void hotload() {
for (int i = 0; i < getSize(); i++) {
getEngine(i).hotload();
}
}
}

View File

@ -1,810 +0,0 @@
/*
* 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.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.IrisSettings;
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.core.project.loader.IrisData;
import com.volmit.iris.engine.IrisEngineCompound;
import com.volmit.iris.engine.data.chunk.MCATerrainChunk;
import com.volmit.iris.engine.data.chunk.TerrainChunk;
import com.volmit.iris.engine.framework.headless.HeadlessGenerator;
import com.volmit.iris.engine.object.basic.IrisPosition;
import com.volmit.iris.engine.object.biome.IrisBiome;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.object.dimensional.IrisDimension;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.B;
import com.volmit.iris.util.format.C;
import com.volmit.iris.util.format.Form;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.io.ReactiveFolder;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.nbt.tag.CompoundTag;
import com.volmit.iris.util.parallel.BurstExecutor;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.plugin.VolmitSender;
import com.volmit.iris.util.reflect.V;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import com.volmit.iris.util.scheduling.Looper;
import com.volmit.iris.util.scheduling.PrecisionStopwatch;
import io.netty.util.internal.ConcurrentSet;
import lombok.Getter;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.ChunkGenerator;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class EngineCompositeGenerator extends ChunkGenerator implements IrisAccess {
private static final BlockData ERROR_BLOCK = Material.RED_GLAZED_TERRACOTTA.createBlockData();
private final AtomicReference<EngineCompound> compound = new AtomicReference<>();
private final AtomicBoolean initialized;
private final String dimensionQuery;
private final boolean production;
private final KList<BlockPopulator> populators;
private long mst = 0;
private HeadlessGenerator headlessGenerator;
private NBTWorld nbtWorld;
private int generated = 0;
private int lgenerated = 0;
private final ChronoLatch hotloadcd;
@Getter
private double generatedPerSecond = 0;
private ReactiveFolder hotloader = null;
private IrisWorld cworld = null;
private final Looper ticker;
private final Looper cleaner;
private int hotloaderMisses = 0;
private long lastHotloadTime = 100;
public EngineCompositeGenerator() {
this(null, true);
}
public EngineCompositeGenerator(String query, boolean production) {
super();
ticker = new Looper() {
@Override
protected long loop() {
PrecisionStopwatch p = PrecisionStopwatch.start();
if (!tickHotloader()) {
hotloaderMisses++;
} else {
hotloaderMisses = 0;
}
lastHotloadTime += p.getMilliseconds();
lastHotloadTime /= 2;
return 120 + (lastHotloadTime / 2) + Math.min(hotloaderMisses * 125, 1375);
}
};
ticker.setPriority(Thread.MIN_PRIORITY);
ticker.setName("Iris Project Manager");
cleaner = new Looper() {
@Override
protected long loop() {
if (getComposite() != null) {
getComposite().clean();
}
return 10000;
}
};
cleaner.setPriority(Thread.MIN_PRIORITY);
cleaner.setName("Iris Parallax Manager");
cleaner.start();
if (isStudio()) {
ticker.start();
}
hotloadcd = new ChronoLatch(3500);
mst = M.ms();
this.production = production;
this.dimensionQuery = query;
initialized = new AtomicBoolean(false);
populators = new KList<BlockPopulator>().qadd(new BlockPopulator() {
@Override
public void populate(World world, Random random, Chunk chunk) {
if (compound.get() != null) {
for (BlockPopulator i : compound.get().getPopulators()) {
i.populate(world, random, chunk);
}
}
}
});
}
@Override
public void hotload() {
if (isStudio()) {
Iris.proj.updateWorkspace();
getData().dump();
J.s(() -> {
try {
for (Player i : getTarget().getWorld().getPlayers()) {
new VolmitSender(i, Iris.instance.getTag()).sendMessage("Dimension Hotloaded");
i.playSound(i.getLocation(), Sound.BLOCK_COPPER_PLACE, 1f, 1.25f);
}
} catch (Throwable e) {
Iris.reportError(e);
}
});
getComposite().close();
initialized.lazySet(false);
if (cworld != null) {
initialize(cworld);
}
}
}
public boolean tickHotloader() {
if (getComposite() == null || isClosed()) {
return false;
}
if (!initialized.get()) {
return false;
}
try {
if (hotloader != null) {
return hotloader.check();
}
} catch (Throwable e) {
Iris.reportError(e);
}
return false;
}
private synchronized IrisDimension getDimension(IrisWorld world) {
String query = dimensionQuery;
query = Iris.linkMultiverseCore.getWorldNameType(world.name(), query);
IrisDimension dim = null;
if (query == null) {
File iris = new File(world.worldFolder(), "iris");
if (iris.exists() && iris.isDirectory()) {
for (File i : iris.listFiles()) {
// Look for v1 location
if (i.isDirectory() && i.getName().equals("dimensions")) {
for (File j : i.listFiles()) {
if (j.isFile() && j.getName().endsWith(".json")) {
query = j.getName().replaceAll("\\Q.json\\E", "");
Iris.error("Found v1 install. Please create a new world, this will cause chunks to change in your existing iris worlds!");
throw new RuntimeException();
}
}
}
// Look for v2 location
else if (i.isFile() && i.getName().equals("engine-metadata.json")) {
EngineData metadata = EngineData.load(i);
query = metadata.getDimension();
break;
}
}
}
}
if (query == null) {
Iris.error("Cannot find iris dimension data for world: " + world.name() + "! Assuming " + IrisSettings.get().getGenerator().getDefaultWorldType() + "!");
query = IrisSettings.get().getGenerator().getDefaultWorldType();
}
dim = IrisData.loadAnyDimension(query);
if (dim == null) {
Iris.proj.downloadSearch(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), query, false);
dim = IrisData.loadAnyDimension(query);
if (dim == null) {
throw new RuntimeException("Cannot find dimension: " + query);
} else {
Iris.info("Download pack: " + query);
}
}
if (production) {
IrisDimension od = dim;
dim = new IrisData(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) {
Iris.info("Installing Iris pack " + od.getName() + " into world " + world.name() + "...");
Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), od.getLoadKey(), world.worldFolder());
dim = new IrisData(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) {
throw new RuntimeException("Cannot find dimension: " + query);
}
}
}
return dim;
}
private synchronized IrisDimension getDimension(String world) {
String query = dimensionQuery;
IrisDimension dim = null;
if (query == null) {
File iris = new File(world + "/iris");
if (iris.exists() && iris.isDirectory()) {
for (File i : Objects.requireNonNull(iris.listFiles())) {
// Look for v1 location
if (i.isDirectory() && i.getName().equals("dimensions")) {
for (File j : Objects.requireNonNull(i.listFiles())) {
if (j.isFile() && j.getName().endsWith(".json")) {
query = j.getName().replaceAll("\\Q.json\\E", "");
Iris.error("Found v1 install. Please create a new world, this will cause chunks to change in your existing iris worlds!");
throw new RuntimeException();
}
}
}
// Look for v2 location
else if (i.isFile() && i.getName().equals("engine-metadata.json")) {
EngineData metadata = EngineData.load(i);
query = metadata.getDimension();
break;
}
}
}
}
if (query == null) {
Iris.error("Cannot find iris dimension data for world: " + world + "! Assuming " + IrisSettings.get().getGenerator().getDefaultWorldType() + "!");
query = IrisSettings.get().getGenerator().getDefaultWorldType();
}
dim = IrisData.loadAnyDimension(query);
if (dim == null) {
Iris.proj.downloadSearch(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), query, false);
dim = IrisData.loadAnyDimension(query);
if (dim == null) {
throw new RuntimeException("Cannot find dimension: " + query);
} else {
Iris.info("Download pack: " + query);
}
}
if (production) {
IrisDimension od = dim;
dim = new IrisData(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) {
Iris.info("Installing Iris pack " + od.getName() + " into world " + world + "...");
Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag()), od.getLoadKey(), new File(world));
dim = new IrisData(getDataFolder(world)).getDimensionLoader().load(od.getLoadKey());
if (dim == null) {
throw new RuntimeException("Cannot find dimension: " + query);
}
}
}
Iris.info(world + " is configured to generate " + dim.getName() + "!");
return dim;
}
public synchronized void initialize(IrisWorld world) {
if (initialized.get()) {
return;
}
try {
initialized.set(true);
IrisDimension dim = getDimension(world);
IrisData data = production ? new IrisData(getDataFolder(world)) : dim.getLoader().copy();
compound.set(new IrisEngineCompound(world, dim, data, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getEngineThreadCount())));
compound.get().setStudio(!production);
populators.clear();
populators.addAll(compound.get().getPopulators());
hotloader = new ReactiveFolder(data.getDataFolder(), (a, c, d) -> hotload());
cworld = world;
if (isStudio()) {
dim.installDataPack(() -> data, Iris.instance.getDatapacksFolder());
}
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
Iris.error("FAILED TO INITIALIZE DIMENSION FROM " + world.toString());
}
}
/**
* Place strongholds in the world
*/
public void placeStrongholds(World world) {
EngineData metadata = getComposite().getEngineMetadata();
// TODO: In nms class, not here. Also it doesnt work
if (metadata.getStrongholdPositions() == null || metadata.getStrongholdPositions().size() == 0) {
List<IrisPosition> strongholds = new ArrayList<>();
Object nmsWorld = new V(world).invoke("getHandle");
Object chunkProvider = new V(nmsWorld).invoke("getChunkProvider");
Object chunkGenerator = new V(chunkProvider).invoke("getChunkGenerator");
try {
Class<?> clazz = Class.forName("net.minecraft.world.level.chunk.ChunkGenerator");
Class<?> clazzSG = Class.forName("net.minecraft.world.level.levelgen.feature.StructureGenerator");
Class<?> clazzBP = Class.forName("net.minecraft.core.BlockPosition");
@SuppressWarnings("rawtypes") Constructor bpCon = clazzBP.getConstructor(int.class, int.class, int.class);
//By default, we place 9 strongholds. One near 0,0 and 8 all around it at about 10_000 blocks out
int[][] coords = {{0, 0}, {7000, -7000}, {10000, 0}, {7000, 7000}, {0, 10000}, {-7000, 7000}, {-10000, 0}, {-7000, -7000}, {0, -10000}};
//Set of stronghold locations so we don't place 2 strongholds at the same location
Set<Long> existing = new ConcurrentSet<>();
Set<CompletableFuture<Object>> futures = new HashSet<>();
for (int[] currCoords : coords) {
//Create a NMS BlockPosition
Object blockPosToTest = bpCon.newInstance(currCoords[0], 0, currCoords[1]);
//Create a CompletableFuture so we can track once the sync code is complete
CompletableFuture<Object> future = new CompletableFuture<>();
futures.add(future);
//We have to run this code synchronously because it uses NMS
J.s(() -> {
try {
Object o = getBP(clazz, clazzSG, clazzBP, nmsWorld, blockPosToTest, chunkGenerator);
future.complete(o);
} catch (Exception e) {
Iris.reportError(e);
e.printStackTrace();
future.complete(e);
}
});
}
CompletableFuture<Void> all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
all.thenAccept((_void) -> { //Once all futures for all 9 strongholds have completed
for (CompletableFuture<Object> future : futures) {
try {
Object pos = future.getNow(null);
if (pos != null) {
IrisPosition ipos = new IrisPosition((int) new V(pos, false).invoke("getX"), (int) new V(pos,
false).invoke("getY"), (int) new V(pos, false).invoke("getZ"));
long xz = (((long) ipos.getX()) << 32) | (ipos.getZ() & 0xffffffffL);
if (existing.contains(xz)) return; //Make sure we don't double up on stronghold locs
existing.add(xz);
strongholds.add(ipos);
}
} catch (Exception e) {
Iris.reportError(e);
e.printStackTrace();
}
}
StringBuilder positions = new StringBuilder();
for (IrisPosition pos : strongholds) {
positions.append("(").append(pos.getX()).append(",").append(pos.getY()).append(",").append(pos.getZ()).append(") ");
}
Iris.info("Strongholds (" + strongholds.size() + ") found at [" + positions + "]");
metadata.setStrongholdPositions(strongholds);
getComposite().saveEngineMetadata();
});
} catch (Exception e) {
Iris.reportError(e);
strongholds.add(new IrisPosition(1337, 32, -1337));
metadata.setStrongholdPositions(strongholds);
Iris.warn("Couldn't properly find the stronghold position for this world. Is this headless mode? Are you not using 1.16 or higher?");
Iris.warn(" -> Setting default stronghold position");
e.printStackTrace();
StringBuilder positions = new StringBuilder();
for (IrisPosition pos : strongholds) {
positions.append("(").append(pos.getX()).append(",").append(pos.getY()).append(",").append(pos.getZ()).append(") ");
}
Iris.info("Strongholds (" + metadata.getStrongholdPositions().size() + ") found at [" + positions + "]");
}
}
}
/**
* Get BlockPosition for nearest stronghold from the provided position
*/
private Object getBP(Class<?> clazz, Class<?> clazzSG, Class<?> clazzBP, Object nmsWorld, Object pos, Object chunkGenerator) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
final String stronghold = "k"; //1.17_01 mapping
Object structureGeneratorStronghold = clazzSG.getDeclaredField(stronghold).get(null);
Method getNearestGeneratedFeature = clazz.getDeclaredMethod("findNearestMapFeature",
nmsWorld.getClass(),
clazzSG,
clazzBP,
int.class,
boolean.class
);
return getNearestGeneratedFeature.invoke(chunkGenerator,
nmsWorld,
structureGeneratorStronghold,
pos,
100,
false
);
}
private File getDataFolder(IrisWorld world) {
return new File(world.worldFolder(), "iris/pack");
}
private File getDataFolder(String world) {
return new File(world + "/iris/pack");
}
@Override
public ChunkData generateChunkData(World world, Random ignored, int x, int z, BiomeGrid biome) {
try {
PrecisionStopwatch ps = PrecisionStopwatch.start();
TerrainChunk tc = TerrainChunk.create(world, biome);
IrisWorld ww = (getComposite() == null || getComposite().getWorld() == null) ? IrisWorld.fromWorld(world) : getComposite().getWorld();
generateChunkRawData(ww, x, z, tc, true).run();
if (!getComposite().getWorld().hasRealWorld()) {
getComposite().getWorld().bind(world);
}
generated++;
ps.end();
if (IrisSettings.get().getGeneral().isDebug()) {
Iris.debug("Chunk " + C.GREEN + x + "," + z + C.LIGHT_PURPLE + " in " + C.YELLOW + Form.duration(ps.getMillis(), 2) + C.LIGHT_PURPLE + " Rate: " + C.BLUE + Form.f(getGeneratedPerSecond(), 0) + "/s");
}
return tc.getRaw();
} catch (Throwable e) {
Iris.error("======================================");
e.printStackTrace();
Iris.reportErrorChunk(x, z, e, "CHUNK");
Iris.error("======================================");
ChunkData d = Bukkit.createChunkData(world);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
d.setBlock(i, 0, j, ERROR_BLOCK);
}
}
return d;
}
}
public void assignHeadlessGenerator(HeadlessGenerator headlessGenerator) {
this.headlessGenerator = headlessGenerator;
}
@Override
public HeadlessGenerator getHeadlessGenerator() {
return headlessGenerator;
}
public void assignHeadlessNBTWriter(NBTWorld writer) {
this.nbtWorld = writer;
}
@Override
public NBTWorld getHeadlessNBTWriter() {
return nbtWorld;
}
@Override
public void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst) {
directWriteMCA(w, x, z, writer, burst, null);
}
@Override
public void directWriteMCA(IrisWorld w, int x, int z, NBTWorld writer, MultiBurst burst, PregenListener l) {
BurstExecutor e = burst.burst(1024);
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();
}
@Override
public void directWriteChunk(IrisWorld w, int x, int z, NBTWorld writer) {
try {
int ox = x << 4;
int oz = z << 4;
com.volmit.iris.util.nbt.mca.Chunk chunk = writer.getChunk(x, z);
generateChunkRawData(w, x, z, MCATerrainChunk.builder()
.writer(writer).ox(ox).oz(oz).mcaChunk(chunk)
.minHeight(w.minHeight()).maxHeight(w.maxHeight())
.injector((xx, yy, zz, biomeBase) -> chunk.setBiomeAt(ox + xx, yy, oz + zz,
INMS.get().getTrueBiomeBaseId(biomeBase)))
.build(), false).run();
} catch (Throwable e) {
Iris.error("======================================");
e.printStackTrace();
Iris.reportErrorChunk(x, z, e, "MCA");
Iris.error("======================================");
com.volmit.iris.util.nbt.mca.Chunk chunk = writer.getChunk(x, z);
CompoundTag c = NBTWorld.getCompound(ERROR_BLOCK);
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
chunk.setBlockStateAt(i, 0, j, c, false);
}
}
}
}
public Runnable generateChunkRawData(IrisWorld world, int x, int z, TerrainChunk tc, boolean multicore) {
initialize(world);
tickMetrics();
Hunk<BlockData> blocks = Hunk.view((ChunkData) tc);
Hunk<Biome> biomes = Hunk.view((BiomeGrid) tc);
Hunk<BlockData> post = Hunk.newAtomicHunk(biomes.getWidth(), biomes.getHeight(), biomes.getDepth());
compound.get().generate(x * 16, z * 16, blocks, post, biomes, multicore);
return () -> blocks.insertSoftly(0, 0, 0, post, (b) -> b == null || B.isAirOrFluid(b));
}
private void tickMetrics() {
if (M.ms() - mst > 1000) {
generatedPerSecond = (double) (generated - lgenerated) / ((double) (M.ms() - mst) / 1000D);
mst = M.ms();
lgenerated = generated;
}
}
@Override
public boolean canSpawn(World world, int x, int z) {
return super.canSpawn(world, x, z);
}
@Override
public List<BlockPopulator> getDefaultPopulators(World world) {
return populators;
}
@Override
public Location getFixedSpawnLocation(World world, Random random) {
return super.getFixedSpawnLocation(world, random);
}
@Override
public boolean isParallelCapable() {
return true;
}
@Override
public boolean shouldGenerateCaves() {
return false;
}
@Override
public boolean shouldGenerateDecorations() {
return false;
}
@Override
public boolean shouldGenerateMobs() {
return false;
}
@Override
public boolean shouldGenerateStructures() {
return false;
}
public static EngineCompositeGenerator newStudioWorld(String dimension) {
return new EngineCompositeGenerator(dimension, false);
}
public static EngineCompositeGenerator newProductionWorld(String dimension) {
return new EngineCompositeGenerator(dimension, true);
}
public static EngineCompositeGenerator newProductionWorld() {
return new EngineCompositeGenerator(null, true);
}
public EngineCompound getComposite() {
return compound.get();
}
@Override
public IrisBiome getBiome(int x, int z) {
return getBiome(x, 0, z);
}
@Override
public IrisBiome getCaveBiome(int x, int z) {
return getCaveBiome(x, 0, z);
}
@Override
public int getGenerated() {
return generated;
}
@Override
public void printMetrics(CommandSender sender) {
getComposite().printMetrics(sender);
}
@Override
public IrisBiome getBiome(int x, int y, int z) {
// TODO: REMOVE GET ABS BIOME OR THIS ONE
return getEngineAccess(y).getBiome(x, y - getComposite().getEngineForHeight(y).getMinHeight(), z);
}
@Override
public IrisBiome getCaveBiome(int x, int y, int z) {
return getEngineAccess(y).getCaveBiome(x, z);
}
@Override
public GeneratorAccess getEngineAccess(int y) {
return getComposite().getEngineForHeight(y);
}
@Override
public IrisData getData() {
if (getCompound() == null) {
return null;
}
return getComposite().getData();
}
@Override
public int getHeight(int x, int y, int z) {
return getEngineAccess(y).getHeight(x, z);
}
@Override
public int getThreadCount() {
return getComposite().getThreadCount();
}
@Override
public void changeThreadCount(int m) {
// TODO: DO IT
}
@Override
public void close() {
if (isStudio()) {
ticker.interrupt();
}
cleaner.interrupt();
if (getComposite() != null) {
getComposite().close();
if (isStudio() && getComposite().getWorld().hasRealWorld()) {
getComposite().getWorld().evacuate();
Bukkit.unloadWorld(getComposite().getWorld().realWorld(), !isStudio());
}
}
}
@Override
public boolean isClosed() {
try {
return getComposite().getEngine(0).isClosed();
} catch (Throwable e) {
Iris.reportError(e);
return false;
}
}
@Override
public EngineTarget getTarget() {
try {
return getComposite().getEngine(0).getTarget();
} catch (NullPointerException e) {
Iris.reportError(e);
Iris.info("Failed to get composite engine. Please re-create the world in case you notice issues");
return null;
}
}
@Override
public EngineCompound getCompound() {
return getComposite();
}
@Override
public boolean isFailing() {
if (getComposite() == null) {
return false;
}
return getComposite().isFailing();
}
@Override
public boolean isStudio() {
return !production;
}
public boolean isVanillaCaves() {
return false;
}
public KList<IrisBiome> getAllBiomes(String worldName) {
if (getComposite() != null) {
return getComposite().getAllBiomes();
} else {
KMap<String, IrisBiome> v = new KMap<>();
IrisDimension dim = getDimension(worldName);
dim.getAllAnyBiomes().forEach((i) -> v.put(i.getLoadKey(), i));
try {
dim.getDimensionalComposite().forEach((m) -> IrisData.loadAnyDimension(m.getDimension()).getAllAnyBiomes().forEach((i) -> v.put(i.getLoadKey(), i)));
} catch (Throwable ignored) {
Iris.reportError(ignored);
}
Iris.info("Injecting " + v.size() + " biomes into the NMS World Chunk Provider (Iris)");
return v.v();
}
}
}

View File

@ -1,169 +0,0 @@
/*
* 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.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.project.loader.IrisData;
import com.volmit.iris.engine.actuator.IrisTerrainNormalActuator;
import com.volmit.iris.engine.object.basic.IrisPosition;
import com.volmit.iris.engine.object.biome.IrisBiome;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.object.dimensional.IrisDimension;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.collection.KMap;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.hunk.Hunk;
import com.volmit.iris.util.parallel.MultiBurst;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Listener;
import org.bukkit.generator.BlockPopulator;
import java.util.List;
public interface EngineCompound extends Listener, Hotloadable, DataProvider {
IrisDimension getRootDimension();
void generate(int x, int z, Hunk<BlockData> blocks, Hunk<BlockData> postblocks, Hunk<Biome> biomes, boolean multicore);
IrisWorld getWorld();
List<IrisPosition> getStrongholdPositions();
void printMetrics(CommandSender sender);
int getSize();
default int getHeight() {
// TODO: WARNING HEIGHT
return 256;
}
Engine getEngine(int index);
MultiBurst getBurster();
EngineData getEngineMetadata();
void saveEngineMetadata();
KList<BlockPopulator> getPopulators();
default Engine getEngineForHeight(int height) {
if (getSize() == 1) {
return getEngine(0);
}
int buf = 0;
for (int i = 0; i < getSize(); i++) {
Engine e = getEngine(i);
buf += e.getHeight();
if (buf >= height) {
return e;
}
}
return getEngine(getSize() - 1);
}
default void recycle() {
for (int i = 0; i < getSize(); i++) {
getEngine(i).recycle();
}
}
default void save() {
saveEngineMetadata();
for (int i = 0; i < getSize(); i++) {
getEngine(i).save();
}
}
default void saveNOW() {
saveEngineMetadata();
for (int i = 0; i < getSize(); i++) {
getEngine(i).saveNow();
}
}
IrisData getData(int height);
default IrisData getData() {
return getData(0);
}
default void close() {
for (int i = 0; i < getSize(); i++) {
getEngine(i).close();
}
}
boolean isFailing();
int getThreadCount();
boolean isStudio();
void setStudio(boolean std);
default void clean() {
for (int i = 0; i < getSize(); i++) {
getEngine(i).clean();
}
}
Engine getDefaultEngine();
default KList<IrisBiome> getAllBiomes() {
KMap<String, IrisBiome> v = new KMap<>();
IrisDimension dim = getRootDimension();
dim.getAllBiomes(this).forEach((i) -> v.put(i.getLoadKey(), i));
try {
dim.getDimensionalComposite().forEach((m) -> getData().getDimensionLoader().load(m.getDimension()).getAllBiomes(this).forEach((i) -> v.put(i.getLoadKey(), i)));
} catch (Throwable ignored) {
Iris.reportError(ignored);
}
return v.v();
}
default int getLowestBedrock() {
int f = Integer.MAX_VALUE;
for (int i = 0; i < getSize(); i++) {
Engine e = getEngine(i);
if (e.getDimension().isBedrock()) {
int m = ((IrisTerrainNormalActuator) e.getTerrainActuator()).getLastBedrock();
if (f > m) {
f = m;
}
}
}
return f;
}
}

View File

@ -1,287 +0,0 @@
/*
* 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.engine.framework;
import com.volmit.iris.Iris;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.core.project.loader.IrisData;
import com.volmit.iris.engine.framework.headless.HeadlessGenerator;
import com.volmit.iris.engine.object.biome.IrisBiome;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.object.regional.IrisRegion;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.data.DataProvider;
import com.volmit.iris.util.math.M;
import com.volmit.iris.util.math.RNG;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.parallel.MultiBurst;
import com.volmit.iris.util.scheduling.ChronoLatch;
import com.volmit.iris.util.scheduling.J;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.util.Vector;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
@SuppressWarnings("EmptyMethod")
public interface IrisAccess extends Hotloadable, DataProvider {
HeadlessGenerator getHeadlessGenerator();
default boolean isHeadless() {
return getHeadlessGenerator() != null;
}
NBTWorld getHeadlessNBTWriter();
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);
int getGenerated();
double getGeneratedPerSecond();
void printMetrics(CommandSender sender);
/**
* Ignores the world, just uses the position
*
* @param l the location
* @return the biome
*/
default IrisBiome getBiome(Location l) {
return getBiome(l.toVector());
}
default IrisRegion getRegion(int x, int y, int z) {
return getEngineAccess(y).getRegion(x, z);
}
default IrisRegion getRegion(Location l) {
return getRegion(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
default IrisBiome getBiome(Vector l) {
return getBiome(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
IrisBiome getBiome(int x, int y, int z);
IrisBiome getCaveBiome(int x, int y, int z);
IrisBiome getBiome(int x, int z);
IrisBiome getCaveBiome(int x, int z);
GeneratorAccess getEngineAccess(int y);
IrisData getData();
int getHeight(int x, int y, int z);
int getThreadCount();
void changeThreadCount(int m);
void close();
boolean isClosed();
EngineTarget getTarget();
EngineCompound getCompound();
boolean isFailing();
boolean isStudio();
default Location lookForBiome(IrisBiome biome, long timeout, Consumer<Integer> triesc) {
if (!getCompound().getWorld().hasRealWorld()) {
Iris.error("Cannot GOTO without a bound world (headless mode)");
return null;
}
ChronoLatch cl = new ChronoLatch(250, false);
long s = M.ms();
int cpus = (Runtime.getRuntime().availableProcessors());
KList<Engine> engines = new KList<>();
for (int i = 0; i < getCompound().getSize(); i++) {
Engine e = getCompound().getEngine(i);
if (e.getDimension().getAllBiomes(e).contains(biome)) {
engines.add(e);
}
}
if (engines.isEmpty()) {
return null;
}
AtomicInteger tries = new AtomicInteger(0);
AtomicBoolean found = new AtomicBoolean(false);
AtomicBoolean running = new AtomicBoolean(true);
AtomicReference<Location> location = new AtomicReference<>();
for (int i = 0; i < cpus; i++) {
J.a(() -> {
try {
Engine e;
IrisBiome b;
int x, z;
while (!found.get() && running.get()) {
try {
synchronized (engines) {
e = engines.getRandom();
x = RNG.r.i(-29999970, 29999970);
z = RNG.r.i(-29999970, 29999970);
b = e.getSurfaceBiome(x, z);
}
if (b != null && b.getLoadKey() == null) {
continue;
}
if (b != null && b.getLoadKey().equals(biome.getLoadKey())) {
found.lazySet(true);
location.lazySet(new Location(e.getWorld().realWorld(), x, e.getHeight(x, z), z));
}
tries.getAndIncrement();
} catch (Throwable ex) {
Iris.reportError(ex);
ex.printStackTrace();
return;
}
}
} catch (Throwable e) {
Iris.reportError(e);
e.printStackTrace();
}
});
}
while (!found.get() || location.get() == null) {
J.sleep(50);
if (cl.flip()) {
triesc.accept(tries.get());
}
if (M.ms() - s > timeout) {
running.set(false);
return null;
}
}
running.set(false);
return location.get();
}
default Location lookForRegion(IrisRegion reg, long timeout, Consumer<Integer> triesc) {
if (!getCompound().getWorld().hasRealWorld()) {
Iris.error("Cannot GOTO without a bound world (headless mode)");
return null;
}
ChronoLatch cl = new ChronoLatch(3000, false);
long s = M.ms();
int cpus = (Runtime.getRuntime().availableProcessors());
KList<Engine> engines = new KList<>();
for (int i = 0; i < getCompound().getSize(); i++) {
Engine e = getCompound().getEngine(i);
if (e.getDimension().getRegions().contains(reg.getLoadKey())) {
engines.add(e);
}
}
if (engines.isEmpty()) {
return null;
}
AtomicInteger tries = new AtomicInteger(0);
AtomicBoolean found = new AtomicBoolean(false);
AtomicBoolean running = new AtomicBoolean(true);
AtomicReference<Location> location = new AtomicReference<>();
for (int i = 0; i < cpus; i++) {
J.a(() -> {
Engine e;
IrisRegion b;
int x, z;
while (!found.get() && running.get()) {
try {
e = engines.getRandom();
x = RNG.r.i(-29999970, 29999970);
z = RNG.r.i(-29999970, 29999970);
b = e.getRegion(x, z);
if (b != null && b.getLoadKey() != null && b.getLoadKey().equals(reg.getLoadKey())) {
found.lazySet(true);
location.lazySet(new Location(e.getWorld().realWorld(), x, e.getHeight(x, z) + e.getMinHeight(), z));
}
tries.getAndIncrement();
} catch (Throwable xe) {
Iris.reportError(xe);
xe.printStackTrace();
return;
}
}
});
}
while (!found.get() || location.get() != null) {
J.sleep(50);
if (cl.flip()) {
triesc.accept(tries.get());
}
if (M.ms() - s > timeout) {
triesc.accept(tries.get());
running.set(false);
return null;
}
}
triesc.accept(tries.get());
running.set(false);
return location.get();
}
default int getParallaxChunkCount() {
int v = 0;
for (int i = 0; i < getCompound().getSize(); i++) {
v += getCompound().getEngine(i).getParallax().getChunkCount();
}
return v;
}
default double getHeight(Location l) {
return getHeight(l.getBlockX(), l.getBlockY(), l.getBlockZ());
}
}

View File

@ -1,93 +0,0 @@
/*
* 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.engine.framework.headless;
import com.volmit.iris.core.IrisSettings;
import com.volmit.iris.core.pregenerator.PregenListener;
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
import com.volmit.iris.util.collection.KList;
import com.volmit.iris.util.math.Position2;
import com.volmit.iris.util.nbt.mca.MCAUtil;
import com.volmit.iris.util.nbt.mca.NBTWorld;
import com.volmit.iris.util.parallel.MultiBurst;
import lombok.Data;
import java.io.File;
import java.io.IOException;
@Data
public class HeadlessGenerator {
private static KList<Position2> EMPTYPOINTS = new KList<>();
private final HeadlessWorld world;
private final EngineCompositeGenerator generator;
private final NBTWorld writer;
private final MultiBurst burst;
public HeadlessGenerator(HeadlessWorld world) {
this.world = world;
burst = new MultiBurst("Iris Headless Generator", 9, IrisSettings.getThreadCount(IrisSettings.get().getConcurrency().getPregenThreadCount()));
writer = new NBTWorld(world.getWorld().worldFolder());
generator = new EngineCompositeGenerator(world.getDimension().getLoadKey(), !world.isStudio());
generator.assignHeadlessGenerator(this);
generator.assignHeadlessNBTWriter(writer);
generator.initialize(world.getWorld());
}
public void generateChunk(int x, int z) {
generator.directWriteChunk(world.getWorld(), x, z, writer);
}
public void generateRegion(int x, int z) {
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, PregenListener listener) {
generateRegionToFile(x, z, listener);
flush();
return writer.getRegionFile(x, z);
}
public void flush() {
writer.flushNow();
}
public void save() {
writer.save();
}
public void close() {
burst.shutdownAndAwait();
generator.close();
writer.close();
}
public KList<Position2> getChunksInRegion(int x, int z) {
try {
return MCAUtil.sampleChunkPositions(writer.getRegionFile(x, z));
} catch (IOException e) {
e.printStackTrace();
}
return EMPTYPOINTS;
}
}

View File

@ -1,88 +0,0 @@
/*
* 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.engine.framework.headless;
import com.volmit.iris.Iris;
import com.volmit.iris.core.project.loader.IrisData;
import com.volmit.iris.core.tools.IrisWorlds;
import com.volmit.iris.engine.framework.EngineCompositeGenerator;
import com.volmit.iris.engine.object.common.IrisWorld;
import com.volmit.iris.engine.object.dimensional.IrisDimension;
import com.volmit.iris.util.plugin.VolmitSender;
import lombok.Data;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import java.io.File;
@Data
@SuppressWarnings("ResultOfMethodCallIgnored")
public class HeadlessWorld {
private final IrisDimension dimension;
private final String worldName;
private final IrisWorld world;
private boolean studio = false;
public HeadlessWorld(String worldName, IrisDimension dimension, long seed) {
this(worldName, dimension, seed, false);
}
public HeadlessWorld(String worldName, IrisDimension dimension, long seed, boolean studio) {
this.worldName = worldName;
this.dimension = dimension;
this.studio = studio;
world = IrisWorld.builder()
.environment(dimension.getEnvironment())
.worldFolder(new File(worldName))
.seed(seed)
.maxHeight(256)
.minHeight(0)
.name(worldName)
.build();
world.worldFolder().mkdirs();
new File(world.worldFolder(), "region").mkdirs();
if (!studio && !new File(world.worldFolder(), "iris").exists()) {
Iris.proj.installIntoWorld(new VolmitSender(Bukkit.getConsoleSender(), Iris.instance.getTag("Headless")), dimension.getLoadKey(), world.worldFolder());
}
}
public HeadlessGenerator generate() {
return new HeadlessGenerator(this);
}
public World load() {
World w = new WorldCreator(worldName)
.environment(dimension.getEnvironment())
.seed(world.seed())
.generator(new EngineCompositeGenerator(dimension.getLoadKey(), !studio))
.createWorld();
world.realWorld(w);
return w;
}
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) {
return new HeadlessWorld(name, IrisData.loadAnyDimension(dimension), seed);
}
}