Entity spawns

This commit is contained in:
Daniel Mills 2020-11-14 22:27:37 -05:00
parent e0fc4b9443
commit 44d86bc350
17 changed files with 265 additions and 106 deletions

View File

@ -64,7 +64,7 @@ public class Iris extends VolmitPlugin
public static int getThreadCount()
{
int tc = IrisSettings.get().forceThreadCount;
int tc = IrisSettings.get().getForceThreadCount();
if(tc <= 0)
{
@ -407,7 +407,7 @@ public class Iris extends VolmitPlugin
public void splash()
{
if(!IrisSettings.get().isSplash())
if(!IrisSettings.get().isSplashLogoStartup())
{
return;
}

View File

@ -13,108 +13,64 @@ public class IrisSettings
public static transient IrisSettings settings;
@DontObfuscate
@Desc("Iris generator threads (must be 2 or higher). Threads in iris are not a perfect scale for performance as a lot of data has to be shared. 16 Threads is a good rule of thumb. Use 8 threads on a quad core processor.")
public int configurationVersion = 2;
@DontObfuscate
public int streamingCacheSize = 8192;
@DontObfuscate
public int forceThreadCount = -1;
@DontObfuscate
@Desc("The default world type incase iris doesnt have a dimension to use.")
public String defaultWorldType = "overworld";
@DontObfuscate
@Desc("Iris uses a lot of caching to speed up chunk generation. Setting this higher uses more memory, but may improve performance. Anything past 8,000 should be avoided because there is little benefit past this value.")
public int atomicCacheSize = 3000;
public int maxAsyncChunkPregenThreads = 32;
@DontObfuscate
@Desc("Max pregen async chunk threads.")
public int maxAsyncChunkPregenThreads = 300;
public boolean maximumPregenGuiFPS = false;
@DontObfuscate
@Desc("More cpu for pregen gui but looks nice.")
public boolean maxPregenGuiFPS = false;
@DontObfuscate
@Desc("Renders what the terrain looks like in the pregen map for iris worlds only.")
public boolean pregenRenderTerrain = true;
@DontObfuscate
@Desc("Adds sound to commands.")
public boolean commandSounds = true;
@DontObfuscate
@Desc("Compress parallax data in memory to reduce memory usage in exchange for more cpu usage.")
public boolean parallaxCompression = true;
@DontObfuscate
@Desc("Uses a lot of cpu and slows down hotloading")
public boolean regenerateLoadedChunksOnHotload = false;
@DontObfuscate
@Desc("Useful information when creating iris worlds. Shows object loads & more.")
public boolean verbose = false;
@DontObfuscate
@Desc("Experiments...")
public boolean allowExperimentalV2Generator = false;
@DontObfuscate
@Desc("If true, will not use world edit even if its on the server")
public boolean ignoreWorldEdit = false;
@DontObfuscate
@Desc("System Effects")
public boolean systemEffects = true;
@DontObfuscate
@Desc("Disable all nms")
public boolean disableNMS = false;
@DontObfuscate
@Desc("System Spawn Overrides")
public boolean systemEffects = true;
@DontObfuscate
public boolean systemEntitySpawnOverrides = true;
@DontObfuscate
@Desc("System Spawn Initials")
public boolean systemEntityInitialSpawns = true;
@DontObfuscate
@Desc("Compression level (0-9) lower is faster, but is not as good compression. Best results around 3-5")
public int parallaxCompressionLevel = 2;
@DontObfuscate
@Desc("If A is a child of B, and B is a child of A, how deep should iris follow the children in biomes. Lower is faster gen.")
public int maxBiomeChildDepth = 5;
@DontObfuscate
@Desc("The size of each tile pregen will generate (in chunks)")
public int pregenTileSize = 32;
@DontObfuscate
@Desc("When enabled, The cache is shared for all chunks and cleared periodically instead of per chunk. This uses more memory but provides a ~15% speedup.")
public boolean sharedCaching = true;
@DontObfuscate
@Desc("Allows Iris to use studio commands & design worlds.")
public boolean studio = true;
@DontObfuscate
@Desc("Allows iris to launch guis through the server process. Useful for local development.")
public boolean useServerLaunchedGuis = true;
@DontObfuscate
@Desc("When using studio open or create, open the codeworkspace automatically.")
public boolean openVSCode = true;
@DontObfuscate
@Desc("Collects anonymous metrics for bstats")
public boolean metrics = true;
@DontObfuscate
@Desc("Splash the screen")
public boolean splash = true;
@DontObfuscate
@Desc("Skips preparing spawn by using nms to hijack the world init phase")
public boolean skipPrepareSpawnNMS = true;
public boolean splashLogoStartup = true;
public static IrisSettings get()
{
@ -161,7 +117,17 @@ public class IrisSettings
{
u = true;
j.put(i, def.get(i));
Iris.verbose("Adding new config key: " + i);
Iris.warn("Adding new config key: " + i);
}
}
for(String i : j.keySet())
{
if(!def.has(i))
{
u = true;
j.remove(i);
Iris.warn("Removing unused config key: " + i);
}
}

View File

@ -1,6 +1,7 @@
package com.volmit.iris.generator;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.generator.actuator.IrisTerrainActuator;
import com.volmit.iris.generator.modifier.IrisCaveModifier;
import com.volmit.iris.generator.noise.CNG;
@ -74,7 +75,7 @@ public class IrisComplex implements DataProvider
public IrisComplex(Engine engine)
{
int cacheSize = 8192;
int cacheSize = IrisSettings.get().getStreamingCacheSize();
this.rng = new RNG(engine.getWorld().getSeed());
this.data = engine.getData();
double height = engine.getHeight();

View File

@ -99,7 +99,6 @@ public class IrisEngine extends BlockPopulator implements Engine
() -> getFramework().getPostModifier().modify(x, z, blocks),
() -> getFramework().getDecorantActuator().actuate(x, z, blocks)
);
;
getFramework().getEngineParallax().insertParallax(x, z, blocks);
getFramework().recycle();

View File

@ -4,7 +4,6 @@ import com.volmit.iris.Iris;
import com.volmit.iris.manager.IrisDataManager;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.object.IrisDimensionIndex;
import com.volmit.iris.util.KList;
import com.volmit.iris.scaffold.engine.Engine;
import com.volmit.iris.scaffold.engine.EngineCompound;
import com.volmit.iris.scaffold.engine.EngineData;
@ -12,7 +11,9 @@ import com.volmit.iris.scaffold.engine.EngineTarget;
import com.volmit.iris.scaffold.hunk.Hunk;
import com.volmit.iris.scaffold.parallel.BurstExecutor;
import com.volmit.iris.scaffold.parallel.MultiBurst;
import com.volmit.iris.util.KList;
import lombok.Getter;
import lombok.Setter;
import org.bukkit.World;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
@ -45,6 +46,10 @@ public class IrisEngineCompound implements EngineCompound {
@Getter
private int threadCount;
@Getter
@Setter
private boolean studio;
public IrisEngineCompound(World world, IrisDimension rootDimension, IrisDataManager data, int maximumThreads)
{
this.rootDimension = rootDimension;

View File

@ -1,20 +1,24 @@
package com.volmit.iris.generator;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.object.*;
import com.volmit.iris.scaffold.cache.Cache;
import com.volmit.iris.scaffold.engine.Engine;
import com.volmit.iris.scaffold.engine.EngineAssignedWorldManager;
import com.volmit.iris.util.J;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.RNG;
import org.bukkit.Chunk;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntitySpawnEvent;
public class IrisWorldManager extends EngineAssignedWorldManager {
private boolean spawnable;
public IrisWorldManager(Engine engine) {
super(engine);
}
@Override
public void onEntitySpawn(EntitySpawnEvent e) {
spawnable = true;
}
@Override
@ -28,8 +32,116 @@ public class IrisWorldManager extends EngineAssignedWorldManager {
}
@Override
public void spawnInitialEntities(Chunk chunk) {
public void spawnInitialEntities(Chunk c) {
RNG rng = new RNG(Cache.key(c));
int x = (c.getX() * 16) + rng.nextInt(15);
int z = (c.getZ() * 16) + rng.nextInt(15);
int y = getEngine().getHeight(x, z) + 1;
IrisDimension dim = getDimension();
IrisRegion region = getEngine().getRegion(x, z);
IrisBiome above = getEngine().getSurfaceBiome(x, z);
trySpawn(above.getEntityInitialSpawns(), c, rng);
trySpawn(region.getEntityInitialSpawns(), c, rng);
trySpawn(dim.getEntityInitialSpawns(), c, rng);
}
@Override
public void onEntitySpawn(EntitySpawnEvent e)
{
if(getTarget().getWorld() == null || !getTarget().getWorld().equals(e.getEntity().getWorld()))
{
return;
}
try
{
if(!IrisSettings.get().isSystemEntitySpawnOverrides())
{
return;
}
int x = e.getEntity().getLocation().getBlockX();
int y = e.getEntity().getLocation().getBlockY();
int z = e.getEntity().getLocation().getBlockZ();
J.a(() ->
{
if(spawnable)
{
IrisDimension dim = getDimension();
IrisRegion region = getEngine().getRegion(x, z);
IrisBiome above = getEngine().getSurfaceBiome(x, z);
IrisBiome bbelow = getEngine().getBiome(x, y, z);
if(above.getLoadKey().equals(bbelow.getLoadKey()))
{
bbelow = null;
}
IrisBiome below = bbelow;
J.s(() ->
{
if(below != null)
{
if(trySpawn(below.getEntitySpawnOverrides(), e))
{
return;
}
}
if(trySpawn(above.getEntitySpawnOverrides(), e))
{
return;
}
if(trySpawn(region.getEntitySpawnOverrides(), e))
{
return;
}
if(trySpawn(dim.getEntitySpawnOverrides(), e))
{
return;
}
});
}
});
}
catch(Throwable xe)
{
}
}
private boolean trySpawn(KList<IrisEntitySpawnOverride> s, EntitySpawnEvent e)
{
for(IrisEntitySpawnOverride i : s)
{
spawnable = false;
if(i.on(getEngine(), e.getLocation(), e.getEntityType(), e) != null)
{
e.setCancelled(true);
e.getEntity().remove();
return true;
}
else
{
spawnable = true;
}
}
return false;
}
private void trySpawn(KList<IrisEntityInitialSpawn> s, Chunk c, RNG rng)
{
for(IrisEntityInitialSpawn i : s)
{
i.spawn(getEngine(), c, rng);
}
}
@Override

View File

@ -4,10 +4,12 @@ import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.object.IrisEntity;
import com.volmit.iris.scaffold.IrisWorlds;
import com.volmit.iris.scaffold.engine.Engine;
import com.volmit.iris.scaffold.engine.IrisAccess;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.MortarCommand;
import com.volmit.iris.util.MortarSender;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.entity.Player;
@ -64,7 +66,8 @@ public class CommandIrisStudioSummon extends MortarCommand
return true;
}
e.spawn(g, sender.player().getLocation().clone().add(0, 3, 0));
Location vl = sender.player().getLocation().clone().add(0, 3, 0);
e.spawn((Engine) g.getEngineAccess(vl.getBlockY()), vl);
}
}

View File

@ -1,10 +1,12 @@
package com.volmit.iris.manager.gui;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
@ -13,18 +15,6 @@ import java.io.File;
import java.io.IOException;
import java.util.concurrent.locks.ReentrantLock;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import com.volmit.iris.Iris;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.util.ChunkPosition;
import com.volmit.iris.util.J;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.M;
import com.volmit.iris.util.PregenJob;
public class PregenGui extends JPanel implements KeyListener
{
private PregenJob job;
@ -97,7 +87,7 @@ public class PregenGui extends JPanel implements KeyListener
g.drawString("Press P to Pause", 20, hh += h);
}
J.sleep((long) (IrisSettings.get().isMaxPregenGuiFPS() ? 4 : 250));
J.sleep((long) (IrisSettings.get().isMaximumPregenGuiFPS() ? 4 : 250));
repaint();
}

View File

@ -1,7 +1,7 @@
package com.volmit.iris.object;
import com.volmit.iris.Iris;
import com.volmit.iris.scaffold.engine.IrisAccess;
import com.volmit.iris.scaffold.engine.Engine;
import com.volmit.iris.util.*;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -135,12 +135,12 @@ public class IrisEntity extends IrisRegistrant
@Desc("The this entity is ageable, set it's baby status")
private boolean baby = false;
public Entity spawn(IrisAccess gen, Location at)
public Entity spawn(Engine gen, Location at)
{
return spawn(gen, at, new RNG(at.hashCode()));
}
public Entity spawn(IrisAccess gen, Location at, RNG rng)
public Entity spawn(Engine gen, Location at, RNG rng)
{
Entity e = doSpawn(at);
e.setCustomName(getCustomName() != null ? C.translateAlternateColorCodes('&', getCustomName()) : null);

View File

@ -1,7 +1,7 @@
package com.volmit.iris.object;
import com.volmit.iris.scaffold.cache.AtomicCache;
import com.volmit.iris.scaffold.engine.IrisAccess;
import com.volmit.iris.scaffold.engine.Engine;
import com.volmit.iris.util.*;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -43,7 +43,7 @@ public class IrisEntityInitialSpawn
private final transient AtomicCache<RNG> rng = new AtomicCache<>();
private final transient AtomicCache<IrisEntity> ent = new AtomicCache<>();
public void spawn(IrisAccess gen, Chunk c, RNG rng)
public void spawn(Engine gen, Chunk c, RNG rng)
{
int spawns = rng.i(1, rarity) == 1 ? rng.i(minSpawns, maxSpawns) : 0;
@ -53,18 +53,18 @@ public class IrisEntityInitialSpawn
{
int x = (c.getX() * 16) + rng.i(15);
int z = (c.getZ() * 16) + rng.i(15);
int h = gen.getHeight(x, 0, z);
int h = gen.getHeight(x, z) + gen.getMinHeight();
spawn100(gen, new Location(c.getWorld(), x, h, z));
}
}
}
public IrisEntity getRealEntity(IrisAccess g)
public IrisEntity getRealEntity(Engine g)
{
return ent.aquire(() -> g.getData().getEntityLoader().load(getEntity()));
}
public Entity spawn(IrisAccess g, Location at)
public Entity spawn(Engine g, Location at)
{
if(getRealEntity(g) == null)
{
@ -79,7 +79,7 @@ public class IrisEntityInitialSpawn
return null;
}
private Entity spawn100(IrisAccess g, Location at)
private Entity spawn100(Engine g, Location at)
{
return getRealEntity(g).spawn(g, at.clone().add(0, 1, 0), rng.aquire(() -> new RNG(g.getTarget().getWorld().getSeed() + 4)));
}

View File

@ -1,7 +1,7 @@
package com.volmit.iris.object;
import com.volmit.iris.scaffold.cache.AtomicCache;
import com.volmit.iris.scaffold.engine.IrisAccess;
import com.volmit.iris.scaffold.engine.Engine;
import com.volmit.iris.util.*;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -47,7 +47,7 @@ public class IrisEntitySpawnOverride
private final transient AtomicCache<IrisEntity> ent = new AtomicCache<>();
public Entity on(IrisAccess g, Location at, EntityType t, EntitySpawnEvent ee)
public Entity on(Engine g, Location at, EntityType t, EntitySpawnEvent ee)
{
if(!trigger.equals(EntityType.UNKNOWN))
{
@ -68,7 +68,7 @@ public class IrisEntitySpawnOverride
return e;
}
public Entity spawn(IrisAccess g, Location at)
public Entity spawn(Engine g, Location at)
{
if(getRealEntity(g) == null)
{
@ -83,7 +83,7 @@ public class IrisEntitySpawnOverride
return null;
}
public IrisEntity getRealEntity(IrisAccess g)
public IrisEntity getRealEntity(Engine g)
{
return ent.aquire(() -> g.getData().getEntityLoader().load(getEntity()));
}

View File

@ -1,7 +1,13 @@
package com.volmit.iris.scaffold.cache;
import org.bukkit.Chunk;
public interface Cache<V>
{
static long key(Chunk chunk) {
return key(chunk.getX(), chunk.getZ());
}
public int getId();
public V get(int x, int z);

View File

@ -6,6 +6,7 @@ import com.volmit.iris.scaffold.cache.Cache;
import com.volmit.iris.scaffold.data.DataProvider;
import com.volmit.iris.scaffold.hunk.Hunk;
import com.volmit.iris.scaffold.parallax.ParallaxAccess;
import com.volmit.iris.scaffold.parallel.MultiBurst;
import com.volmit.iris.util.B;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.RNG;
@ -320,4 +321,16 @@ public interface Engine extends DataProvider, Fallible, GeneratorAccess, LootPro
{
return getHeight() + getMinHeight();
}
public EngineCompound getCompound();
public default boolean isStudio()
{
return getCompound().isStudio();
}
public default void clean()
{
MultiBurst.burst.lazy(() -> getParallax().cleanup());
}
}

View File

@ -2,16 +2,13 @@ package com.volmit.iris.scaffold.engine;
import com.volmit.iris.Iris;
import com.volmit.iris.generator.IrisEngineCompound;
import com.volmit.iris.util.TerrainChunk;
import com.volmit.iris.manager.IrisDataManager;
import com.volmit.iris.object.IrisBiome;
import com.volmit.iris.object.IrisDimension;
import com.volmit.iris.scaffold.IrisWorlds;
import com.volmit.iris.scaffold.cache.Cache;
import com.volmit.iris.scaffold.hunk.Hunk;
import com.volmit.iris.util.KList;
import com.volmit.iris.util.M;
import com.volmit.iris.util.RNG;
import com.volmit.iris.util.*;
import org.bukkit.*;
import org.bukkit.block.Biome;
import org.bukkit.block.data.BlockData;
@ -33,6 +30,8 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
private final boolean production;
private final KList<BlockPopulator> populators;
private int generated = 0;
private int art;
private ReactiveFolder hotloader = null;
public EngineCompositeGenerator() {
this(null, true);
@ -43,6 +42,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
this.production = production;
this.dimensionHint = hint;
initialized = new AtomicBoolean(false);
art = J.ar(this::tick, 20);
populators = new KList<BlockPopulator>().qadd(new BlockPopulator() {
@Override
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk chunk) {
@ -63,6 +63,30 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
initialized.lazySet(false);
}
public void tick()
{
if(isClosed())
{
return;
}
if(!initialized.get())
{
return;
}
try
{
hotloader.check();
getComposite().clean();
}
catch(Throwable e)
{
}
}
private synchronized IrisDimension getDimension(World world) {
String hint = dimensionHint;
IrisDimension dim = null;
@ -124,9 +148,11 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
IrisDimension dim = getDimension(world);
IrisDataManager data = production ? new IrisDataManager(getDataFolder(world)) : dim.getLoader().copy();
compound = new IrisEngineCompound(world, dim, data, Iris.getThreadCount());
compound.setStudio(!production);
initialized.set(true);
populators.clear();
populators.addAll(compound.getPopulators());
hotloader = new ReactiveFolder(data.getDataFolder(), (a, c, d) -> hotload());
}
private File getDataFolder(World world) {
@ -385,6 +411,7 @@ public class EngineCompositeGenerator extends ChunkGenerator implements IrisAcce
@Override
public void close() {
J.car(art);
getComposite().close();
IrisWorlds.evacuate(getComposite().getWorld());
Bukkit.unloadWorld(getComposite().getWorld(), !isStudio());

View File

@ -91,4 +91,16 @@ public interface EngineCompound extends Listener
public boolean isFailing();
public int getThreadCount();
public boolean isStudio();
public void setStudio(boolean std);
public default void clean()
{
for(int i = 0; i < getSize(); i++)
{
getEngine(i).clean();
}
}
}

View File

@ -1,6 +1,5 @@
package com.volmit.iris.scaffold.hunk.io;
import com.volmit.iris.IrisSettings;
import com.volmit.iris.scaffold.data.IOAdapter;
import com.volmit.iris.scaffold.hunk.Hunk;
import com.volmit.iris.util.ByteArrayTag;
@ -21,7 +20,7 @@ public interface HunkIOAdapter<T> extends IOAdapter<T>
{
f.getParentFile().mkdirs();
FileOutputStream fos = new FileOutputStream(f);
GZIPOutputStream gzo = new CustomOutputStream(fos, IrisSettings.get().parallaxCompressionLevel);
GZIPOutputStream gzo = new CustomOutputStream(fos, 6);
write(t, gzo);
}

View File

@ -0,0 +1,26 @@
package com.volmit.iris.util;
import java.io.File;
public class ReactiveFolder
{
private File folder;
private Consumer3<KList<File>, KList<File>, KList<File>> hotload;
private FolderWatcher fw;
public ReactiveFolder(File folder, Consumer3<KList<File>, KList<File>, KList<File>> hotload)
{
this.folder = folder;
this.hotload = hotload;
this.fw = new FolderWatcher(folder);
fw.checkModified();
}
public void check()
{
if(fw.checkModified())
{
hotload.accept(fw.getCreated(), fw.getChanged(), fw.getDeleted());
}
}
}