From 6480fb0bb6a59e21d002bcdce16653b48f8ac66d Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 12 Oct 2020 00:28:17 -0700 Subject: [PATCH] Improve ore performance by caching chunks --- .../com/dfsek/terra/command/OreCommand.java | 5 ++- .../terra/config/genconfig/OreConfig.java | 43 +++++++++++++++++-- .../dfsek/terra/population/OrePopulator.java | 10 +++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/dfsek/terra/command/OreCommand.java b/src/main/java/com/dfsek/terra/command/OreCommand.java index f15e9d193..df5f20a7a 100644 --- a/src/main/java/com/dfsek/terra/command/OreCommand.java +++ b/src/main/java/com/dfsek/terra/command/OreCommand.java @@ -3,11 +3,13 @@ package com.dfsek.terra.command; import com.dfsek.terra.TerraWorld; import com.dfsek.terra.config.genconfig.OreConfig; import com.dfsek.terra.config.lang.LangUtil; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.polydev.gaea.command.WorldCommand; @@ -33,7 +35,8 @@ public class OreCommand extends WorldCommand { LangUtil.send("command.ore.out-of-range", sender); return true; } - ore.doVein(bl.getLocation(), new Random()); + Vector source = new Vector(Math.floorMod(bl.getX(), 16), bl.getY(), Math.floorMod(bl.getZ(), 16)); + ore.doVein(source, bl.getChunk(), new Random()); } else { LangUtil.send("command.ore.main-menu", sender); } diff --git a/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java b/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java index 481278cea..0bade68e3 100644 --- a/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java +++ b/src/main/java/com/dfsek/terra/config/genconfig/OreConfig.java @@ -5,15 +5,20 @@ import com.dfsek.terra.config.base.ConfigUtil; import com.dfsek.terra.config.TerraConfig; import com.dfsek.terra.config.exception.ConfigException; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.util.Vector; import org.polydev.gaea.math.FastNoise; +import org.polydev.gaea.population.ChunkCoordinate; import java.io.File; import java.io.IOException; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import java.util.Random; import java.util.Set; @@ -26,6 +31,7 @@ public class OreConfig extends TerraConfig { private final double deformFrequency; private final String id; private final boolean update; + private final boolean crossChunks; Set replaceable; public OreConfig(File file, ConfigPack config) throws IOException, InvalidConfigurationException { super(file, config); @@ -39,6 +45,7 @@ public class OreConfig extends TerraConfig { deform = getDouble("deform", 0.75); deformFrequency = getDouble("deform-frequency", 0.1); update = getBoolean("update", false); + crossChunks = getBoolean("cross-chunks", true); replaceable = ConfigUtil.toBlockData(getStringList("replace"), "replaceable", getID()); @@ -52,7 +59,31 @@ public class OreConfig extends TerraConfig { private int randomInRange(Random r) { return r.nextInt(max-min+1)+min; } - public void doVein(Location l, Random r) { + public void doVein(Vector l, Chunk chunk, Random r) { + FastNoise ore = new FastNoise(r.nextInt()); + ore.setNoiseType(FastNoise.NoiseType.SimplexFractal); + ore.setFrequency((float) deformFrequency); + int rad = randomInRange(r); + Map chunks = new HashMap<>(); // Cache chunks to prevent re-loading chunks every time one is needed. + chunks.put(new ChunkCoordinate(chunk), chunk); + Vector orig = new Vector(l.getBlockX() + (chunk.getX() << 4), l.getBlockY(), l.getBlockZ() + (chunk.getZ() << 4)); + for(int x = -rad; x <= rad; x++) { + for(int y = -rad; y <= rad; y++) { + for(int z = -rad; z <= rad; z++) { + Vector oreLoc = orig.clone().add(new Vector(x, y, z)); + Vector source = l.clone().add(new Vector(x, y, z)); + if(oreLoc.getBlockY() > 255 || oreLoc.getBlockY() < 0) continue; + if(source.distance(l) < (rad + 0.5) * ((ore.getSimplexFractal(x, y, z)+1)*deform)) { + ChunkCoordinate coord = new ChunkCoordinate(Math.floorDiv(oreLoc.getBlockX(), 16), Math.floorDiv(oreLoc.getBlockZ(), 16), chunk.getWorld().getUID()); + Block b = chunks.computeIfAbsent(coord, k -> chunk.getWorld().getChunkAt(oreLoc.toLocation(chunk.getWorld()))) + .getBlock(Math.floorMod(source.getBlockX(), 16), source.getBlockY(), Math.floorMod(source.getBlockZ(), 16)); + if(replaceable.contains(b.getType()) && b.getLocation().getY() >= 0) b.setBlockData(oreData, update); + } + } + } + } + } + public void doVeinSingle(Vector l, Chunk chunk, Random r) { FastNoise ore = new FastNoise(r.nextInt()); ore.setNoiseType(FastNoise.NoiseType.SimplexFractal); ore.setFrequency((float) deformFrequency); @@ -60,8 +91,10 @@ public class OreConfig extends TerraConfig { for(int x = -rad; x <= rad; x++) { for(int y = -rad; y <= rad; y++) { for(int z = -rad; z <= rad; z++) { - if(l.clone().add(x, y, z).distance(l) < (rad + 0.5) * ((ore.getSimplexFractal(x, y, z)+1)*deform)) { - Block b = l.clone().add(x, y, z).getBlock(); + Vector oreLoc = l.clone().add(new Vector(x, y, z)); + if(oreLoc.getBlockX() > 15 || oreLoc.getBlockZ() > 15 || oreLoc.getBlockY() > 255 || oreLoc.getBlockX() < 0 || oreLoc.getBlockZ() < 0 || oreLoc.getBlockY() < 0) continue; + if(oreLoc.distance(l) < (rad + 0.5) * ((ore.getSimplexFractal(x, y, z)+1)*deform)) { + Block b = chunk.getBlock(oreLoc.getBlockX(), oreLoc.getBlockY(), oreLoc.getBlockZ()); if(replaceable.contains(b.getType()) && b.getLocation().getY() >= 0) b.setBlockData(oreData, update); } } @@ -77,4 +110,8 @@ public class OreConfig extends TerraConfig { public String getID() { return id; } + + public boolean crossChunks() { + return crossChunks; + } } diff --git a/src/main/java/com/dfsek/terra/population/OrePopulator.java b/src/main/java/com/dfsek/terra/population/OrePopulator.java index 1d4ccbe13..7c845c302 100644 --- a/src/main/java/com/dfsek/terra/population/OrePopulator.java +++ b/src/main/java/com/dfsek/terra/population/OrePopulator.java @@ -2,6 +2,8 @@ package com.dfsek.terra.population; import com.dfsek.terra.TerraWorld; import com.dfsek.terra.config.base.ConfigPack; +import com.dfsek.terra.config.genconfig.biome.BiomeOreConfig; +import org.bukkit.util.Vector; import org.polydev.gaea.math.Range; import com.dfsek.terra.TerraProfiler; import com.dfsek.terra.biome.UserDefinedBiome; @@ -25,13 +27,15 @@ public class OrePopulator extends GaeaBlockPopulator { if(!tw.isSafe()) return; ConfigPack config = tw.getConfig(); Biome b = TerraWorld.getWorld(world).getGrid().getBiome((chunk.getX() << 4)+8, (chunk.getZ() << 4) + 8, GenerationPhase.POPULATE); - for(Map.Entry e : config.getBiome((UserDefinedBiome) b).getOres().getOres().entrySet()) { + BiomeOreConfig ores = config.getBiome((UserDefinedBiome) b).getOres(); + for(Map.Entry e : ores.getOres().entrySet()) { int num = e.getValue().get(random); for(int i = 0; i < num; i++) { int x = random.nextInt(16); int z = random.nextInt(16); - int y = config.getBiome((UserDefinedBiome) b).getOres().getOreHeights().get(e.getKey()).get(random); - e.getKey().doVein(chunk.getBlock(x, y, z).getLocation(), random); + int y = ores.getOreHeights().get(e.getKey()).get(random); + if(e.getKey().crossChunks()) e.getKey().doVein(new Vector(x, y, z), chunk, random); + else e.getKey().doVeinSingle(new Vector(x, y, z), chunk, random); } } }