diff --git a/build.gradle b/build.gradle index cfced68df..d1c56c2c6 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ plugins { id "de.undercouch.download" version "5.0.1" } -version '2.2.19-1.19.2' // Needs to be version specific +version '2.3.0-1.19.2' // Needs to be version specific def nmsVersion = "1.19.2" //[NMS] def apiVersion = '1.19' def specialSourceVersion = '1.11.0' //[NMS] diff --git a/src/main/java/com/volmit/iris/Iris.java b/src/main/java/com/volmit/iris/Iris.java index 5ac77569f..28e5f1470 100644 --- a/src/main/java/com/volmit/iris/Iris.java +++ b/src/main/java/com/volmit/iris/Iris.java @@ -23,7 +23,9 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.ServerConfigurator; -import com.volmit.iris.core.link.*; +import com.volmit.iris.core.link.IrisPapiExpansion; +import com.volmit.iris.core.link.MultiverseCoreLink; +import com.volmit.iris.core.link.MythicMobsLink; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.core.nms.INMS; import com.volmit.iris.core.pregenerator.LazyPregenerator; @@ -41,7 +43,10 @@ import com.volmit.iris.util.exceptions.IrisException; import com.volmit.iris.util.format.C; import com.volmit.iris.util.format.Form; import com.volmit.iris.util.function.NastyRunnable; -import com.volmit.iris.util.io.*; +import com.volmit.iris.util.io.FileWatcher; +import com.volmit.iris.util.io.IO; +import com.volmit.iris.util.io.InstanceState; +import com.volmit.iris.util.io.JarScanner; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.parallel.MultiBurst; @@ -56,11 +61,7 @@ import com.volmit.iris.util.scheduling.ShurikenQueue; import io.papermc.lib.PaperLib; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import net.kyori.adventure.text.serializer.ComponentSerializer; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.WorldCreator; +import org.bukkit.*; import org.bukkit.block.data.BlockData; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -82,12 +83,11 @@ import java.lang.annotation.Annotation; import java.net.URL; import java.util.Date; import java.util.Map; -import java.util.Objects; @SuppressWarnings("CanBeFinal") public class Iris extends VolmitPlugin implements Listener { - public static final String OVERWORLD_TAG = "2086"; + public static final String OVERWORLD_TAG = "2087"; private static final Queue syncJobs = new ShurikenQueue<>(); diff --git a/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 031766349..2420cc6eb 100644 --- a/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -18,9 +18,11 @@ package com.volmit.iris.core.nms; +import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; import com.volmit.iris.util.nbt.tag.CompoundTag; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.WorldCreator; @@ -56,6 +58,8 @@ public interface INMSBinding { Object getCustomBiomeBaseFor(String mckey); Object getCustomBiomeBaseHolderFor(String mckey); + int getBiomeBaseIdForKey(String key); + String getKeyForBiomeBase(Object biomeBase); Object getBiomeBase(World world, Biome biome); @@ -83,4 +87,6 @@ public interface INMSBinding { } MCAPaletteAccess createPalette(); + + void injectBiomesFromMantle(Chunk e, Mantle mantle); } diff --git a/src/main/java/com/volmit/iris/core/nms/v19_2/CustomBiomeSource.java b/src/main/java/com/volmit/iris/core/nms/v19_2/CustomBiomeSource.java new file mode 100644 index 000000000..dcd4c999f --- /dev/null +++ b/src/main/java/com/volmit/iris/core/nms/v19_2/CustomBiomeSource.java @@ -0,0 +1,155 @@ +package com.volmit.iris.core.nms.v19_2; + +import com.mojang.serialization.Codec; +import com.volmit.iris.Iris; +import com.volmit.iris.engine.data.cache.AtomicCache; +import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.object.IrisBiome; +import com.volmit.iris.engine.object.IrisBiomeCustom; +import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.math.RNG; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeSource; +import net.minecraft.world.level.biome.Climate; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_19_R1.CraftServer; +import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R1.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.v1_19_R1.generator.InternalChunkGenerator; +import org.bukkit.generator.BiomeProvider; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +public class CustomBiomeSource extends BiomeSource { + private final long seed; + private final Engine engine; + private final Registry biomeCustomRegistry; + private final Registry biomeRegistry; + private final AtomicCache registryAccess = new AtomicCache<>(); + private final RNG rng; + private final KMap> customBiomes; + + public CustomBiomeSource(long seed, Engine engine, World world) { + super(getAllBiomes( + ((RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())) + .registry(Registry.BIOME_REGISTRY).orElse(null), + ((CraftWorld) world).getHandle().registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null), + engine)); + this.engine = engine; + this.seed = seed; + this.biomeCustomRegistry = registry().registry(Registry.BIOME_REGISTRY).orElse(null); + this.biomeRegistry = ((CraftWorld) world).getHandle().registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null); + this.rng = new RNG(engine.getSeedManager().getBiome()); + this.customBiomes = fillCustomBiomes(biomeCustomRegistry, engine); + } + + private KMap> fillCustomBiomes(Registry customRegistry, Engine engine) { + KMap> m = new KMap<>(); + + for(IrisBiome i : engine.getAllBiomes()) { + if(i.isCustom()) { + for(IrisBiomeCustom j : i.getCustomDerivitives()) { + m.put(j.getId(), customRegistry.getHolder(customRegistry.getResourceKey(customRegistry + .get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get()); + } + } + } + + return m; + } + + private static List> getAllBiomes(Registry customRegistry, Registry registry, Engine engine) { + List> b = new ArrayList<>(); + + for(IrisBiome i : engine.getAllBiomes()) { + if(i.isCustom()) { + for(IrisBiomeCustom j : i.getCustomDerivitives()) { + b.add(customRegistry.getHolder(customRegistry.getResourceKey(customRegistry + .get(new ResourceLocation(engine.getDimension().getLoadKey() + ":" + j.getId()))).get()).get()); + } + } else { + b.add(CraftBlock.biomeToBiomeBase(registry, i.getVanillaDerivative())); + } + } + + return b; + } + + private RegistryAccess registry() { + return registryAccess.aquire(() -> (RegistryAccess) getFor(RegistryAccess.Frozen.class, ((CraftServer) Bukkit.getServer()).getHandle().getServer())); + } + + private static Object getFor(Class type, Object source) { + Object o = fieldFor(type, source); + + if(o != null) { + return o; + } + + return invokeFor(type, source); + } + + private static Object fieldFor(Class returns, Object in) { + return fieldForClass(returns, in.getClass(), in); + } + + + private static Object invokeFor(Class returns, Object in) { + for(Method i : in.getClass().getMethods()) { + if(i.getReturnType().equals(returns)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returns.getSimpleName() + " in " + in.getClass().getSimpleName() + "." + i.getName() + "()"); + return i.invoke(in); + } catch(Throwable e) { + e.printStackTrace(); + } + } + } + + return null; + } + + @SuppressWarnings("unchecked") + private static T fieldForClass(Class returnType, Class sourceType, Object in) { + for(Field i : sourceType.getDeclaredFields()) { + if(i.getType().equals(returnType)) { + i.setAccessible(true); + try { + Iris.debug("[NMS] Found " + returnType.getSimpleName() + " in " + sourceType.getSimpleName() + "." + i.getName()); + return (T) i.get(in); + } catch(IllegalAccessException e) { + e.printStackTrace(); + } + } + } + return null; + } + + @Override + protected Codec codec() { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Holder getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { + int m = (y - engine.getMinHeight()) << 2; + IrisBiome ib = engine.getComplex().getTrueBiomeStream().get(x << 2, z << 2); + if(ib.isCustom()) { + return customBiomes.get(ib.getCustomBiome(rng, x << 2, m, z << 2).getId()); + } else { + org.bukkit.block.Biome v = ib.getSkyBiome(rng, x << 2, m, z << 2); + return CraftBlock.biomeToBiomeBase(biomeRegistry, v); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/volmit/iris/core/nms/v19_2/NMSBinding19_2.java b/src/main/java/com/volmit/iris/core/nms/v19_2/NMSBinding19_2.java index 6663b563f..3d46e42eb 100644 --- a/src/main/java/com/volmit/iris/core/nms/v19_2/NMSBinding19_2.java +++ b/src/main/java/com/volmit/iris/core/nms/v19_2/NMSBinding19_2.java @@ -23,6 +23,9 @@ import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; import com.volmit.iris.engine.data.cache.AtomicCache; import com.volmit.iris.util.collection.KMap; +import com.volmit.iris.util.hunk.Hunk; +import com.volmit.iris.util.mantle.Mantle; +import com.volmit.iris.util.matter.MatterBiomeInject; import com.volmit.iris.util.nbt.io.NBTUtil; import com.volmit.iris.util.nbt.mca.NBTWorld; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; @@ -37,20 +40,20 @@ import com.volmit.iris.util.nbt.mca.palette.MCAWrappedPalettedContainer; import com.volmit.iris.util.nbt.tag.CompoundTag; import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.core.*; +import net.minecraft.core.Registry; import net.minecraft.nbt.NbtIo; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import net.minecraft.world.level.chunk.LevelChunk; +import org.bukkit.*; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_19_R1.CraftChunk; import org.bukkit.craftbukkit.v1_19_R1.CraftServer; import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData; @@ -161,23 +164,7 @@ public class NMSBinding19_2 implements INMSBinding { @Override public Object getBiomeBaseFromId(int id) { - try { - return byIdRef.aquire(() -> { - for(Method i : IdMap.class.getDeclaredMethods()) { - if(i.getParameterCount() == 1 && i.getParameterTypes()[0].equals(int.class)) { - Iris.info("[NMS] Found byId method in " + IdMap.class.getSimpleName() + "." + i.getName() + "(int) => " + Biome.class.getSimpleName()); - return i; - } - } - - Iris.error("Cannot find byId method!"); - return null; - }).invoke(getCustomBiomeRegistry(), id); - } catch(IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - - return null; + return getCustomBiomeRegistry().getHolder(id); } @Override @@ -192,7 +179,7 @@ public class NMSBinding19_2 implements INMSBinding { @Override public int getTrueBiomeBaseId(Object biomeBase) { - return getCustomBiomeRegistry().getId((net.minecraft.world.level.biome.Biome) biomeBase); + return getCustomBiomeRegistry().getId(((Holder) biomeBase).value()); } @Override @@ -214,6 +201,10 @@ public class NMSBinding19_2 implements INMSBinding { return getCustomBiomeRegistry().getHolder(getTrueBiomeBaseId(getCustomBiomeRegistry().get(new ResourceLocation(mckey)))).get(); } + public int getBiomeBaseIdForKey(String key) { + return getCustomBiomeRegistry().getId(getCustomBiomeRegistry().get(new ResourceLocation(key))); + } + @Override public String getKeyForBiomeBase(Object biomeBase) { return getCustomBiomeRegistry().getKey((net.minecraft.world.level.biome.Biome) biomeBase).getPath(); // something, not something:something @@ -221,7 +212,8 @@ public class NMSBinding19_2 implements INMSBinding { @Override public Object getBiomeBase(World world, Biome biome) { - return getBiomeBase(((CraftWorld) world).getHandle().registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null), biome); + return org.bukkit.craftbukkit.v1_19_R1.block.CraftBlock.biomeToBiomeBase(((CraftWorld) world).getHandle() + .registryAccess().registry(Registry.BIOME_REGISTRY).orElse(null), biome); } @Override @@ -333,6 +325,12 @@ public class NMSBinding19_2 implements INMSBinding { return true; } + public void setBiomes(int cx, int cz, World world, Hunk biomes) { + LevelChunk c = ((CraftWorld)world).getHandle().getChunk(cx, cz); + biomes.iterateSync((x,y,z,b) -> c.setBiome(x, y, z, (Holder)b)); + c.setUnsaved(true); + } + @Override public void forceBiomeInto(int x, int y, int z, Object somethingVeryDirty, ChunkGenerator.BiomeGrid chunk) { try { @@ -391,6 +389,26 @@ public class NMSBinding19_2 implements INMSBinding { i -> ((CraftBlockData) NBTWorld.getBlockData(i)).getState()); } + @Override + public void injectBiomesFromMantle(Chunk e, Mantle mantle) { + LevelChunk chunk = ((CraftChunk)e).getHandle(); + AtomicInteger c = new AtomicInteger(); + AtomicInteger r = new AtomicInteger(); + mantle.iterateChunk(e.getX(), e.getZ(), MatterBiomeInject.class, (x,y,z,b) -> { + if(b != null) { + if(b.isCustom()) { + chunk.setBiome(x, y, z, getCustomBiomeRegistry().getHolder(b.getBiomeId()).get()); + c.getAndIncrement(); + } + + else { + chunk.setBiome(x, y, z, (Holder) getBiomeBase(e.getWorld(), b.getBiome())); + r.getAndIncrement(); + } + } + }); + } + private static Object getFor(Class type, Object source) { Object o = fieldFor(type, source); diff --git a/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java index 6db7933ca..15bf05294 100644 --- a/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java +++ b/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java @@ -20,9 +20,11 @@ package com.volmit.iris.core.nms.v1X; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.nbt.mca.palette.MCABiomeContainer; import com.volmit.iris.util.nbt.mca.palette.MCAPaletteAccess; import com.volmit.iris.util.nbt.tag.CompoundTag; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; @@ -57,6 +59,11 @@ public class NMSBinding1X implements INMSBinding { return null; } + @Override + public void injectBiomesFromMantle(Chunk e, Mantle mantle) { + + } + @Override public void deserializeTile(CompoundTag s, Location newPosition) { @@ -117,6 +124,11 @@ public class NMSBinding1X implements INMSBinding { return null; } + @Override + public int getBiomeBaseIdForKey(String key) { + return 0; + } + @Override public String getKeyForBiomeBase(Object biomeBase) { return null; diff --git a/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java b/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java index 00f7fd6a0..fb0e45e0f 100644 --- a/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java +++ b/src/main/java/com/volmit/iris/core/pregenerator/IrisPregenerator.java @@ -61,7 +61,7 @@ public class IrisPregenerator { public IrisPregenerator(PregenTask task, PregeneratorMethod generator, PregenListener listener) { this.listener = listenify(listener); cl = new ChronoLatch(5000); - limiter = new Semaphore(Runtime.getRuntime().availableProcessors()); + limiter = new Semaphore(1024); generatedRegions = new KSet<>(); this.shutdown = new AtomicBoolean(false); this.paused = new AtomicBoolean(false); diff --git a/src/main/java/com/volmit/iris/core/service/StudioSVC.java b/src/main/java/com/volmit/iris/core/service/StudioSVC.java index e97ca5440..39165fb09 100644 --- a/src/main/java/com/volmit/iris/core/service/StudioSVC.java +++ b/src/main/java/com/volmit/iris/core/service/StudioSVC.java @@ -57,7 +57,7 @@ public class StudioSVC implements IrisService { @Override public void onEnable() { - J.a(() -> { + J.s(() -> { String pack = IrisSettings.get().getGenerator().getDefaultWorldType(); File f = IrisPack.packsPack(pack); diff --git a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index fe8920c60..3f39742e0 100644 --- a/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -21,6 +21,7 @@ package com.volmit.iris.engine; import com.volmit.iris.Iris; import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedWorldManager; import com.volmit.iris.engine.object.*; @@ -31,14 +32,14 @@ import com.volmit.iris.util.format.Form; import com.volmit.iris.util.mantle.Mantle; import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.math.M; +import com.volmit.iris.util.math.Position2; import com.volmit.iris.util.math.RNG; +import com.volmit.iris.util.matter.MatterBiomeInject; import com.volmit.iris.util.matter.MatterMarker; import com.volmit.iris.util.parallel.MultiBurst; import com.volmit.iris.util.plugin.Chunks; import com.volmit.iris.util.plugin.VolmitSender; -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.*; import com.volmit.iris.util.scheduling.jobs.QueueJob; import io.papermc.lib.PaperLib; import lombok.Data; @@ -81,6 +82,7 @@ public class IrisWorldManager extends EngineAssignedWorldManager { private int actuallySpawned = 0; private int cooldown = 0; private List precount = new KList<>(); + private KSet injectBiomes = new KSet<>(); public IrisWorldManager() { super(null); @@ -463,6 +465,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager { getEngine().getMantle().save(); } + public void requestBiomeInject(Position2 p) { + injectBiomes.add(p); + } + @Override public void onChunkLoad(Chunk e, boolean generated) { if(getEngine().isClosed()) { @@ -472,6 +478,10 @@ public class IrisWorldManager extends EngineAssignedWorldManager { energy += 0.3; fixEnergy(); getEngine().cleanupMantleChunk(e.getX(), e.getZ()); + + if(generated) { + //INMS.get().injectBiomesFromMantle(e, getMantle()); + } } private void spawn(IrisPosition block, IrisSpawner spawner, boolean initial) { diff --git a/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java b/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java index 71d0ffb43..7530f61c2 100644 --- a/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java +++ b/src/main/java/com/volmit/iris/engine/actuator/IrisBiomeActuator.java @@ -18,9 +18,7 @@ package com.volmit.iris.engine.actuator; -import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMS; -import com.volmit.iris.engine.data.chunk.TerrainChunk; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedActuator; import com.volmit.iris.engine.object.IrisBiome; @@ -28,15 +26,12 @@ import com.volmit.iris.engine.object.IrisBiomeCustom; import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.documentation.BlockCoordinates; import com.volmit.iris.util.hunk.Hunk; -import com.volmit.iris.util.hunk.view.BiomeGridHunkHolder; -import com.volmit.iris.util.hunk.view.BiomeGridHunkView; import com.volmit.iris.util.math.RNG; -import com.volmit.iris.util.parallel.BurstExecutor; +import com.volmit.iris.util.matter.MatterBiomeInject; +import com.volmit.iris.util.matter.slices.BiomeInjectMatter; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.PrecisionStopwatch; -import io.papermc.lib.PaperLib; import org.bukkit.block.Biome; -import org.bukkit.generator.ChunkGenerator; public class IrisBiomeActuator extends EngineAssignedActuator { private final RNG rng; @@ -48,75 +43,34 @@ public class IrisBiomeActuator extends EngineAssignedActuator { } @BlockCoordinates - private boolean injectBiome(Hunk h, int x, int y, int z, Object bb) { + @Override + public void onActuate(int x, int z, Hunk h, boolean multicore, ChunkContext context) { try { - if(h instanceof BiomeGridHunkView hh) { - ChunkGenerator.BiomeGrid g = hh.getChunk(); - if(g instanceof TerrainChunk) { - ((TerrainChunk) g).getBiomeBaseInjector().setBiome(x, y, z, bb); - } else { - hh.forceBiomeBaseInto(x, y, z, bb); + PrecisionStopwatch p = PrecisionStopwatch.start(); + + int m = 0; + for(int xf = 0; xf < h.getWidth(); xf++) { + IrisBiome ib; + for(int zf = 0; zf < h.getDepth(); zf++) { + ib = context.getBiome().get(xf, zf); + MatterBiomeInject matter = null; + + if(ib.isCustom()) { + IrisBiomeCustom custom = ib.getCustomBiome(rng, x, 0, z); + matter = BiomeInjectMatter.get(INMS.get().getBiomeBaseIdForKey(getDimension().getLoadKey() + ":" + custom.getId())); + } else { + Biome v = ib.getSkyBiome(rng, x, 0, z); + matter = BiomeInjectMatter.get(v); + } + + getEngine().getMantle().getMantle().set(x + xf, 0, z + zf, matter); + m++; } - return true; - } else if(h instanceof BiomeGridHunkHolder hh) { - ChunkGenerator.BiomeGrid g = hh.getChunk(); - if(g instanceof TerrainChunk) { - ((TerrainChunk) g).getBiomeBaseInjector().setBiome(x, y, z, bb); - } else { - hh.forceBiomeBaseInto(x, y, z, bb); - } - return true; } + + getEngine().getMetrics().getBiome().put(p.getMilliseconds()); } catch(Throwable e) { e.printStackTrace(); } - - return false; - } - - @BlockCoordinates - @Override - public void onActuate(int x, int z, Hunk h, boolean multicore, ChunkContext context) { - PrecisionStopwatch p = PrecisionStopwatch.start(); - - for(int xf = 0; xf < h.getWidth(); xf++) { - IrisBiome ib; - for(int zf = 0; zf < h.getDepth(); zf++) { - ib = context.getBiome().get(xf, zf); - int maxHeight = (int) (getComplex().getFluidHeight() + ib.getMaxWithObjectHeight(getData())); - if(ib.isCustom()) { - try { - IrisBiomeCustom custom = ib.getCustomBiome(rng, x, 0, z); - Object biomeBase = INMS.get().getCustomBiomeBaseHolderFor(getDimension().getLoadKey() + ":" + custom.getId()); - - if(biomeBase == null || !injectBiome(h, x, 0, z, biomeBase)) { - throw new RuntimeException("Cant inject biome!"); - } - - for(int i = 0; i < maxHeight; i++) { - injectBiome(h, xf, i, zf, biomeBase); - } - } catch(Throwable e) { - Iris.reportError(e); - Biome v = ib.getSkyBiome(rng, x, 0, z); - for(int i = 0; i < maxHeight; i++) { - h.set(xf, i, zf, v); - } - } - } else { - Biome v = ib.getSkyBiome(rng, x, 0, z); - - if(v != null) { - for(int i = 0; i < maxHeight; i++) { - h.set(xf, i, zf, v); - } - } else if(cl.flip()) { - Iris.error("No biome provided for " + ib.getLoadKey()); - } - } - } - } - - getEngine().getMetrics().getBiome().put(p.getMilliseconds()); } } diff --git a/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java b/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java index 38e9535b4..dc7775b19 100644 --- a/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java +++ b/src/main/java/com/volmit/iris/engine/data/chunk/LinkedTerrainChunk.java @@ -38,7 +38,7 @@ public class LinkedTerrainChunk implements TerrainChunk { private final BiomeGrid storage; private ChunkData rawChunkData; @Setter - private boolean unsafe = false; + private boolean unsafe = true; public LinkedTerrainChunk(World world) { this(null, Bukkit.createChunkData(world)); diff --git a/src/main/java/com/volmit/iris/engine/mode/ModeOverworld.java b/src/main/java/com/volmit/iris/engine/mode/ModeOverworld.java index bd19cf06a..ab4b0bbb4 100644 --- a/src/main/java/com/volmit/iris/engine/mode/ModeOverworld.java +++ b/src/main/java/com/volmit/iris/engine/mode/ModeOverworld.java @@ -52,7 +52,6 @@ public class ModeOverworld extends IrisEngineMode implements EngineMode { EngineStage sPerfection = (x, z, k, p, m, c) -> perfection.modify(x, z, k, m, c); registerStage(burst( - sBiome, sGenMatter, sTerrain )); diff --git a/src/main/java/com/volmit/iris/engine/object/IrisWorld.java b/src/main/java/com/volmit/iris/engine/object/IrisWorld.java index 0589521d8..2b5090d20 100644 --- a/src/main/java/com/volmit/iris/engine/object/IrisWorld.java +++ b/src/main/java/com/volmit/iris/engine/object/IrisWorld.java @@ -32,6 +32,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.generator.WorldInfo; import java.io.File; import java.util.Collection; @@ -109,6 +110,14 @@ public class IrisWorld { } } + public void bind(WorldInfo worldInfo) { + name(worldInfo.getName()) + .worldFolder(new File(worldInfo.getName())) + .minHeight(worldInfo.getMinHeight()) + .maxHeight(worldInfo.getMaxHeight()) + .environment(worldInfo.getEnvironment()); + } + public void bind(World world) { if(hasRealWorld()) { return; diff --git a/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java b/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java index eff5384cc..0c5136f0c 100644 --- a/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java +++ b/src/main/java/com/volmit/iris/engine/platform/BukkitChunkGenerator.java @@ -20,6 +20,7 @@ package com.volmit.iris.engine.platform; import com.volmit.iris.Iris; import com.volmit.iris.core.loader.IrisData; +import com.volmit.iris.core.nms.v19_2.CustomBiomeSource; import com.volmit.iris.core.service.StudioSVC; import com.volmit.iris.engine.IrisEngine; import com.volmit.iris.engine.data.chunk.TerrainChunk; @@ -44,37 +45,55 @@ import com.volmit.iris.util.stream.utility.ProfiledStream; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Setter; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.WorldGenLevel; +import org.apache.commons.lang3.reflect.FieldUtils; import org.bukkit.Bukkit; import org.bukkit.Chunk; +import org.bukkit.HeightMap; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_19_R1.CraftServer; +import org.bukkit.craftbukkit.v1_19_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R1.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.v1_19_R1.generator.InternalChunkGenerator; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldInitEvent; import org.bukkit.generator.BiomeProvider; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.WorldInfo; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import sun.misc.Unsafe; import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.List; import java.util.Random; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; @EqualsAndHashCode(callSuper = true) @Data -public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator { +public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChunkGenerator, Listener { private static final int LOAD_LOCKS = Runtime.getRuntime().availableProcessors() * 4; private final Semaphore loadLock; private final IrisWorld world; private final File dataLocation; private final String dimensionKey; private final ReactiveFolder folder; + private final ReentrantLock lock = new ReentrantLock(); private final KList populators; private final ChronoLatch hotloadChecker; private final AtomicBoolean setup; @@ -98,6 +117,49 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun this.dataLocation = dataLocation; this.dimensionKey = dimensionKey; this.folder = new ReactiveFolder(dataLocation, (_a, _b, _c) -> hotload()); + Bukkit.getServer().getPluginManager().registerEvents(this, Iris.instance); + } + + @EventHandler + public void onWorldInit(WorldInitEvent event) { + try { + if(world.name().equals(event.getWorld().getName()) && world.getRawWorldSeed() == event.getWorld().getSeed()) { + ServerLevel serverLevel = ((CraftWorld)event.getWorld()).getHandle(); + Engine engine = getEngine(event.getWorld()); + Class clazz = serverLevel.getChunkSource().chunkMap.generator.getClass(); + Field biomeSource = getField(clazz, "c"); + biomeSource.setAccessible(true); + Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + unsafeField.setAccessible(true); + Unsafe unsafe = (Unsafe) unsafeField.get(null); + CustomBiomeSource customBiomeSource = new CustomBiomeSource(event.getWorld().getSeed(), engine, event.getWorld()); + unsafe.putObject(biomeSource.get(serverLevel.getChunkSource().chunkMap.generator), unsafe.objectFieldOffset(biomeSource), customBiomeSource); + biomeSource.set(serverLevel.getChunkSource().chunkMap.generator, customBiomeSource); + Iris.info("Injected Iris Biome Source into " + event.getWorld().getName()); + } + + else { + Iris.info("World " + event.getWorld().getName() + " is not an Iris world in this context"); + } + } + + catch(Throwable e) { + e.printStackTrace(); + } + } + + private static Field getField(Class clazz, String fieldName) + throws NoSuchFieldException { + try { + return clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if (superClass == null) { + throw e; + } else { + return getField(superClass, fieldName); + } + } } private void setupEngine() { @@ -143,7 +205,7 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun Hunk blocks = Hunk.view(tc); Hunk biomes = Hunk.view(tc, tc.getMinHeight(), tc.getMaxHeight()); this.world.bind(world); - getEngine().generate(x << 4, z << 4, blocks, biomes, true); + getEngine().generate(x << 4, z << 4, blocks, biomes, false); Iris.debug("Regenerated " + x + " " + z); int t = 0; for(int i = getEngine().getHeight() >> 4; i >= 0; i--) { @@ -197,34 +259,41 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun } } - private Engine getEngine(World world) { + private Engine getEngine(WorldInfo world) { if(setup.get()) { return getEngine(); } - synchronized(this) { - getWorld().setRawWorldSeed(world.getSeed()); - setupEngine(); - this.hotloader = studio ? new Looper() { - @Override - protected long loop() { - if(hotloadChecker.flip()) { - folder.check(); - } + lock.lock(); - return 250; - } - } : null; - - if(studio) { - hotloader.setPriority(Thread.MIN_PRIORITY); - hotloader.start(); - hotloader.setName(getTarget().getWorld().name() + " Hotloader"); - } - - setup.set(true); + if(setup.get()) + { + return getEngine(); } + + setup.set(true); + getWorld().setRawWorldSeed(world.getSeed()); + setupEngine(); + this.hotloader = studio ? new Looper() { + @Override + protected long loop() { + if(hotloadChecker.flip()) { + folder.check(); + } + + return 250; + } + } : null; + + if(studio) { + hotloader.setPriority(Thread.MIN_PRIORITY); + hotloader.start(); + hotloader.setName(getTarget().getWorld().name() + " Hotloader"); + } + + lock.unlock(); + return engine; } @@ -273,14 +342,15 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun getEngine(world); } + private final AtomicInteger a = new AtomicInteger(0); + @Override - public @NotNull ChunkData generateChunkData(@NotNull World world, @NotNull Random ignored, int x, int z, @NotNull BiomeGrid biome) { + public void generateNoise(@NotNull WorldInfo world, @NotNull Random random, int x, int z, @NotNull ChunkGenerator.ChunkData d) { try { getEngine(world); computeStudioGenerator(); - TerrainChunk tc = TerrainChunk.create(world, biome); + TerrainChunk tc = TerrainChunk.create(d, new IrisBiomeStorage()); this.world.bind(world); - if(studioGenerator != null) { studioGenerator.generateChunk(getEngine(), tc, x, z); } else { @@ -291,28 +361,26 @@ public class BukkitChunkGenerator extends ChunkGenerator implements PlatformChun biomes.apply(); } - ChunkData c = tc.getRaw(); Iris.debug("Generated " + x + " " + z); - - return c; } 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, Material.RED_GLAZED_TERRACOTTA.createBlockData()); } } - - return d; } } + @Override + public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) { + return 4; + } + private void computeStudioGenerator() { if(!getEngine().getDimension().getStudioMode().equals(lastMode)) { lastMode = getEngine().getDimension().getStudioMode(); diff --git a/src/main/java/com/volmit/iris/engine/platform/DummyBiomeGrid.java b/src/main/java/com/volmit/iris/engine/platform/DummyBiomeGrid.java new file mode 100644 index 000000000..0d9db538f --- /dev/null +++ b/src/main/java/com/volmit/iris/engine/platform/DummyBiomeGrid.java @@ -0,0 +1,29 @@ +package com.volmit.iris.engine.platform; + +import org.bukkit.block.Biome; +import org.bukkit.generator.ChunkGenerator; +import org.jetbrains.annotations.NotNull; + +public class DummyBiomeGrid implements ChunkGenerator.BiomeGrid { + @NotNull + @Override + public Biome getBiome(int x, int z) { + return null; + } + + @NotNull + @Override + public Biome getBiome(int x, int y, int z) { + return null; + } + + @Override + public void setBiome(int x, int z, @NotNull Biome bio) { + + } + + @Override + public void setBiome(int x, int y, int z, @NotNull Biome bio) { + + } +} diff --git a/src/main/java/com/volmit/iris/engine/platform/DummyBiomeProvider.java b/src/main/java/com/volmit/iris/engine/platform/DummyBiomeProvider.java index c453d5a62..5a5f4c4b7 100644 --- a/src/main/java/com/volmit/iris/engine/platform/DummyBiomeProvider.java +++ b/src/main/java/com/volmit/iris/engine/platform/DummyBiomeProvider.java @@ -1,5 +1,6 @@ package com.volmit.iris.engine.platform; +import com.volmit.iris.Iris; import com.volmit.iris.util.collection.KList; import org.bukkit.block.Biome; import org.bukkit.generator.BiomeProvider; diff --git a/src/main/java/com/volmit/iris/util/matter/MatterBiomeInject.java b/src/main/java/com/volmit/iris/util/matter/MatterBiomeInject.java new file mode 100644 index 000000000..038dad4ba --- /dev/null +++ b/src/main/java/com/volmit/iris/util/matter/MatterBiomeInject.java @@ -0,0 +1,31 @@ +/* + * 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 . + */ + +package com.volmit.iris.util.matter; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.bukkit.block.Biome; + +@Data +@AllArgsConstructor +public class MatterBiomeInject { + private final boolean custom; + private final Integer biomeId; + private final Biome biome; +} diff --git a/src/main/java/com/volmit/iris/util/matter/slices/BiomeInjectMatter.java b/src/main/java/com/volmit/iris/util/matter/slices/BiomeInjectMatter.java new file mode 100644 index 000000000..2db4194b3 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/matter/slices/BiomeInjectMatter.java @@ -0,0 +1,80 @@ +/* + * 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 . + */ + +package com.volmit.iris.util.matter.slices; + +import com.volmit.iris.util.data.palette.Palette; +import com.volmit.iris.util.matter.MatterBiomeInject; +import com.volmit.iris.util.matter.MatterCavern; +import com.volmit.iris.util.matter.Sliced; +import org.bukkit.block.Biome; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +@Sliced +public class BiomeInjectMatter extends RawMatter { + public BiomeInjectMatter() { + this(1, 1, 1); + } + + @Override + public Palette getGlobalPalette() { + return null; + } + + public BiomeInjectMatter(int width, int height, int depth) { + super(width, height, depth, MatterBiomeInject.class); + } + + public static MatterBiomeInject get(Biome biome) + { + return get(false, 0, biome); + } + + public static MatterBiomeInject get(int customBiome) { + return get(true, customBiome, null); + } + + public static MatterBiomeInject get(boolean custom, int customBiome, Biome biome) { + return new MatterBiomeInject(custom, customBiome, biome); + } + + @Override + public void writeNode(MatterBiomeInject b, DataOutputStream dos) throws IOException { + dos.writeBoolean(b.isCustom()); + + if(b.isCustom()) { + dos.writeShort(b.getBiomeId()); + } + + else { + dos.writeByte(b.getBiome().ordinal()); + } + } + + @Override + public MatterBiomeInject readNode(DataInputStream din) throws IOException { + boolean b = din.readBoolean(); + int id = b ? din.readShort() : 0; + Biome biome = !b ? Biome.values()[din.readByte()] : Biome.PLAINS; + + return new MatterBiomeInject(b, id, biome); + } +}