mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2025-07-04 00:45:57 +00:00
implement world api changes
This commit is contained in:
parent
01f6df4a19
commit
1e9e1dce75
@ -1,21 +0,0 @@
|
|||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,3 +0,0 @@
|
|||||||
# config-carver
|
|
||||||
|
|
||||||
Registers the default configuration for Terra Carvers, `CARVER`.
|
|
@ -1,7 +0,0 @@
|
|||||||
import com.dfsek.terra.version
|
|
||||||
|
|
||||||
version = version("0.1.0")
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
shadedApi(project(":common:addons:manifest-addon-loader"))
|
|
||||||
}
|
|
@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver;
|
|
||||||
|
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import com.dfsek.terra.addons.carver.carving.Worm;
|
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.util.MathUtil;
|
|
||||||
import com.dfsek.terra.api.util.PopulationUtil;
|
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
import com.dfsek.terra.api.world.biome.TerraBiome;
|
|
||||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
|
||||||
|
|
||||||
|
|
||||||
public class CarverCache {
|
|
||||||
|
|
||||||
private final LoadingCache<Long, List<Worm.WormPoint>> cache;
|
|
||||||
private final UserDefinedCarver carver;
|
|
||||||
|
|
||||||
public CarverCache(World w, Platform platform, UserDefinedCarver carver) {
|
|
||||||
this.carver = carver;
|
|
||||||
cache = CacheBuilder.newBuilder().maximumSize(platform.getTerraConfig().getCarverCacheSize())
|
|
||||||
.build(new CacheLoader<>() {
|
|
||||||
@Override
|
|
||||||
public List<Worm.WormPoint> load(@NotNull Long key) {
|
|
||||||
int chunkX = (int) (key >> 32);
|
|
||||||
int chunkZ = (int) key.longValue();
|
|
||||||
BiomeProvider provider = w.getBiomeProvider();
|
|
||||||
if(CarverCache.this.carver.isChunkCarved(w, chunkX, chunkZ, new Random(
|
|
||||||
PopulationUtil.getCarverChunkSeed(chunkX, chunkZ,
|
|
||||||
w.getSeed() + CarverCache.this.carver.hashCode())))) {
|
|
||||||
long seed = PopulationUtil.getCarverChunkSeed(chunkX, chunkZ, w.getSeed());
|
|
||||||
Random r = new Random(seed);
|
|
||||||
Worm carving = CarverCache.this.carver.getWorm(seed, new Vector3((chunkX << 4) + r.nextInt(16),
|
|
||||||
CarverCache.this.carver.getConfig()
|
|
||||||
.getHeight()
|
|
||||||
.get(r),
|
|
||||||
(chunkZ << 4) + r.nextInt(16)));
|
|
||||||
List<Worm.WormPoint> points = new ArrayList<>();
|
|
||||||
for(int i = 0; i < carving.getLength(); i++) {
|
|
||||||
carving.step();
|
|
||||||
TerraBiome biome = provider.getBiome(carving.getRunning(), w.getSeed());
|
|
||||||
/*
|
|
||||||
if(!((UserDefinedBiome) biome).getConfig().getCarvers().containsKey(CarverCache.this.carver)) { // Stop
|
|
||||||
if we enter a biome this carver is not present in
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
points.add(carving.getPoint());
|
|
||||||
}
|
|
||||||
return points;
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Worm.WormPoint> getPoints(int chunkX, int chunkZ) {
|
|
||||||
return cache.getUnchecked(MathUtil.squash(chunkX, chunkZ));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver;
|
|
||||||
|
|
||||||
import com.dfsek.paralithic.eval.parser.Scope;
|
|
||||||
import com.dfsek.paralithic.eval.tokenizer.ParseException;
|
|
||||||
import com.dfsek.tectonic.exception.LoadException;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.config.ConfigFactory;
|
|
||||||
import com.dfsek.terra.api.config.ConfigPack;
|
|
||||||
import com.dfsek.terra.api.util.MathUtil;
|
|
||||||
|
|
||||||
|
|
||||||
public class CarverFactory implements ConfigFactory<CarverTemplate, UserDefinedCarver> {
|
|
||||||
private final ConfigPack pack;
|
|
||||||
|
|
||||||
public CarverFactory(ConfigPack pack) {
|
|
||||||
this.pack = pack;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UserDefinedCarver build(CarverTemplate config, Platform platform) throws LoadException {
|
|
||||||
double[] start = { config.getStartX(), config.getStartY(), config.getStartZ() };
|
|
||||||
double[] mutate = { config.getMutateX(), config.getMutateY(), config.getMutateZ() };
|
|
||||||
List<String> radius = Arrays.asList(config.getRadMX(), config.getRadMY(), config.getRadMZ());
|
|
||||||
long hash = MathUtil.hashToLong(config.getID());
|
|
||||||
UserDefinedCarver carver;
|
|
||||||
try {
|
|
||||||
carver = new UserDefinedCarver(config.getHeight(), config.getLength(), start, mutate, radius, new Scope(), hash,
|
|
||||||
config.getCutTop(), config.getCutBottom(), config, platform);
|
|
||||||
} catch(ParseException e) {
|
|
||||||
throw new LoadException("Unable to parse radius equations", e);
|
|
||||||
}
|
|
||||||
carver.setRecalc(config.getRecalc());
|
|
||||||
carver.setRecalcMagnitude(config.getRecaclulateMagnitude());
|
|
||||||
return carver;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver;
|
|
||||||
|
|
||||||
import net.jafama.FastMath;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.block.BlockType;
|
|
||||||
import com.dfsek.terra.api.block.state.BlockState;
|
|
||||||
import com.dfsek.terra.api.util.collection.MaterialSet;
|
|
||||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes", "RedundantSuppression" })
|
|
||||||
public class CarverPalette {
|
|
||||||
private final boolean blacklist;
|
|
||||||
private final MaterialSet replace;
|
|
||||||
private final TreeMap<Integer, ProbabilityCollection<BlockState>> map = new TreeMap<>();
|
|
||||||
private ProbabilityCollection<BlockState>[] layers;
|
|
||||||
private int offset = 0;
|
|
||||||
|
|
||||||
public CarverPalette(MaterialSet replaceable, boolean blacklist) {
|
|
||||||
this.blacklist = blacklist;
|
|
||||||
this.replace = replaceable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CarverPalette add(ProbabilityCollection<BlockState> collection, int y) {
|
|
||||||
map.put(y, collection);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ProbabilityCollection<BlockState> get(int y) {
|
|
||||||
int index = y + offset;
|
|
||||||
return index >= 0
|
|
||||||
? index < layers.length
|
|
||||||
? layers[index]
|
|
||||||
: layers[layers.length - 1]
|
|
||||||
: layers[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean canReplace(BlockType material) {
|
|
||||||
return blacklist != replace.contains(material);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build the palette to an array.
|
|
||||||
*/
|
|
||||||
public void build() {
|
|
||||||
int min = FastMath.min(map.keySet().stream().min(Integer::compareTo).orElse(0), 0);
|
|
||||||
int max = FastMath.max(map.keySet().stream().max(Integer::compareTo).orElse(255), 255);
|
|
||||||
|
|
||||||
layers = new ProbabilityCollection[map.lastKey() + 1 - min];
|
|
||||||
for(int y = min; y <= FastMath.max(map.lastKey(), max); y++) {
|
|
||||||
ProbabilityCollection<BlockState> d = null;
|
|
||||||
for(Map.Entry<Integer, ProbabilityCollection<BlockState>> e : map.entrySet()) {
|
|
||||||
if(e.getKey() >= y) {
|
|
||||||
d = e.getValue();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(d == null) throw new IllegalArgumentException("No palette for Y=" + y);
|
|
||||||
layers[y - min] = d;
|
|
||||||
}
|
|
||||||
offset = -min;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,196 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver;
|
|
||||||
|
|
||||||
|
|
||||||
import com.dfsek.tectonic.annotations.Default;
|
|
||||||
import com.dfsek.tectonic.annotations.Final;
|
|
||||||
import com.dfsek.tectonic.annotations.Value;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.block.BlockType;
|
|
||||||
import com.dfsek.terra.api.config.AbstractableTemplate;
|
|
||||||
import com.dfsek.terra.api.config.meta.Meta;
|
|
||||||
import com.dfsek.terra.api.util.ConstantRange;
|
|
||||||
import com.dfsek.terra.api.util.Range;
|
|
||||||
import com.dfsek.terra.api.util.collection.MaterialSet;
|
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unused", "FieldMayBeFinal" })
|
|
||||||
public class CarverTemplate implements AbstractableTemplate {
|
|
||||||
@Value("id")
|
|
||||||
@Final
|
|
||||||
private String id;
|
|
||||||
|
|
||||||
@Value("step")
|
|
||||||
@Default
|
|
||||||
private @Meta int step = 2;
|
|
||||||
|
|
||||||
@Value("recalculate-magnitude")
|
|
||||||
@Default
|
|
||||||
private @Meta double recaclulateMagnitude = 4;
|
|
||||||
|
|
||||||
@Value("recalculate-direction")
|
|
||||||
@Default
|
|
||||||
private @Meta Range recalc = new ConstantRange(8, 10);
|
|
||||||
|
|
||||||
@Value("length")
|
|
||||||
private @Meta Range length;
|
|
||||||
|
|
||||||
@Value("start.x")
|
|
||||||
private @Meta double startX;
|
|
||||||
|
|
||||||
@Value("start.y")
|
|
||||||
private @Meta double startY;
|
|
||||||
|
|
||||||
@Value("start.z")
|
|
||||||
private @Meta double startZ;
|
|
||||||
|
|
||||||
@Value("start.radius.x")
|
|
||||||
private @Meta String radMX;
|
|
||||||
|
|
||||||
@Value("start.radius.y")
|
|
||||||
private @Meta String radMY;
|
|
||||||
|
|
||||||
@Value("start.radius.z")
|
|
||||||
private @Meta String radMZ;
|
|
||||||
|
|
||||||
@Value("start.height")
|
|
||||||
private @Meta Range height;
|
|
||||||
|
|
||||||
@Value("cut.bottom")
|
|
||||||
@Default
|
|
||||||
private @Meta int cutBottom = 0;
|
|
||||||
|
|
||||||
@Value("cut.top")
|
|
||||||
@Default
|
|
||||||
private @Meta int cutTop = 0;
|
|
||||||
|
|
||||||
@Value("mutate.x")
|
|
||||||
private @Meta double mutateX;
|
|
||||||
|
|
||||||
@Value("mutate.y")
|
|
||||||
private @Meta double mutateY;
|
|
||||||
|
|
||||||
@Value("mutate.z")
|
|
||||||
private @Meta double mutateZ;
|
|
||||||
|
|
||||||
@Value("palette.top")
|
|
||||||
private @Meta CarverPalette top;
|
|
||||||
|
|
||||||
@Value("palette.bottom")
|
|
||||||
private @Meta CarverPalette bottom;
|
|
||||||
|
|
||||||
@Value("palette.outer")
|
|
||||||
private @Meta CarverPalette outer;
|
|
||||||
|
|
||||||
@Value("palette.inner")
|
|
||||||
private @Meta CarverPalette inner;
|
|
||||||
|
|
||||||
@Value("shift")
|
|
||||||
@Default
|
|
||||||
private @Meta Map<@Meta BlockType, @Meta MaterialSet> shift = new HashMap<>();
|
|
||||||
|
|
||||||
@Value("update")
|
|
||||||
@Default
|
|
||||||
private @Meta MaterialSet update = new MaterialSet();
|
|
||||||
|
|
||||||
public String getID() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getStep() {
|
|
||||||
return step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Range getLength() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getStartX() {
|
|
||||||
return startX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getStartY() {
|
|
||||||
return startY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getStartZ() {
|
|
||||||
return startZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRadMX() {
|
|
||||||
return radMX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRadMY() {
|
|
||||||
return radMY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getRadMZ() {
|
|
||||||
return radMZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Range getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCutBottom() {
|
|
||||||
return cutBottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getCutTop() {
|
|
||||||
return cutTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getMutateX() {
|
|
||||||
return mutateX;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getMutateY() {
|
|
||||||
return mutateY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getMutateZ() {
|
|
||||||
return mutateZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CarverPalette getTop() {
|
|
||||||
return top;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CarverPalette getBottom() {
|
|
||||||
return bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CarverPalette getOuter() {
|
|
||||||
return outer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CarverPalette getInner() {
|
|
||||||
return inner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<BlockType, MaterialSet> getShift() {
|
|
||||||
return shift;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MaterialSet getUpdate() {
|
|
||||||
return update;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Range getRecalc() {
|
|
||||||
return recalc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double getRecaclulateMagnitude() {
|
|
||||||
return recaclulateMagnitude;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.block.BlockType;
|
|
||||||
import com.dfsek.terra.api.block.state.BlockState;
|
|
||||||
import com.dfsek.terra.api.config.WorldConfig;
|
|
||||||
import com.dfsek.terra.api.profiler.ProfileFrame;
|
|
||||||
import com.dfsek.terra.api.util.PopulationUtil;
|
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
|
||||||
|
|
||||||
|
|
||||||
public class CavePopulator implements GenerationStage, Chunkified {
|
|
||||||
private static final Map<BlockType, BlockState> shiftStorage = new HashMap<>();
|
|
||||||
// Persist BlockData created for shifts, to avoid re-calculating each time.
|
|
||||||
private final Platform platform;
|
|
||||||
|
|
||||||
public CavePopulator(Platform platform) {
|
|
||||||
this.platform = platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("try")
|
|
||||||
@Override
|
|
||||||
public void populate(@NotNull World world, @NotNull Chunk chunk) {
|
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("carving")) {
|
|
||||||
Random random = PopulationUtil.getRandom(chunk);
|
|
||||||
WorldConfig config = world.getConfig();
|
|
||||||
if(config.disableCarving()) return;
|
|
||||||
|
|
||||||
for(UserDefinedCarver c : config.getRegistry(UserDefinedCarver.class).entries()) {
|
|
||||||
CarverTemplate template = c.getConfig();
|
|
||||||
Map<Vector3, BlockState> shiftCandidate = new HashMap<>();
|
|
||||||
c.carve(chunk.getX(), chunk.getZ(), world, (v, type) -> {
|
|
||||||
try(ProfileFrame ignored = platform.getProfiler().profile("carving:" + c.getConfig().getID())) {
|
|
||||||
BlockState m = chunk.getBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ());
|
|
||||||
BlockType re = m.getBlockType();
|
|
||||||
switch(type) {
|
|
||||||
case CENTER:
|
|
||||||
if(template.getInner().canReplace(re)) {
|
|
||||||
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
|
|
||||||
template.getInner().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
|
|
||||||
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WALL:
|
|
||||||
if(template.getOuter().canReplace(re)) {
|
|
||||||
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
|
|
||||||
template.getOuter().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
|
|
||||||
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TOP:
|
|
||||||
if(template.getTop().canReplace(re)) {
|
|
||||||
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
|
|
||||||
template.getTop().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
|
|
||||||
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case BOTTOM:
|
|
||||||
if(template.getBottom().canReplace(re)) {
|
|
||||||
chunk.setBlock(v.getBlockX(), v.getBlockY(), v.getBlockZ(),
|
|
||||||
template.getBottom().get(v.getBlockY()).get(random), template.getUpdate().contains(re));
|
|
||||||
if(template.getShift().containsKey(re)) shiftCandidate.put(v, m);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for(Map.Entry<Vector3, BlockState> entry : shiftCandidate.entrySet()) {
|
|
||||||
Vector3 l = entry.getKey();
|
|
||||||
Vector3 mut = l.clone();
|
|
||||||
BlockState orig = chunk.getBlock(l.getBlockX(), l.getBlockY(), l.getBlockZ());
|
|
||||||
do mut.subtract(0, 1, 0);
|
|
||||||
while(mut.getY() > world.getMinHeight() && chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).matches(
|
|
||||||
orig));
|
|
||||||
try {
|
|
||||||
if(template.getShift().get(entry.getValue().getBlockType()).contains(
|
|
||||||
chunk.getBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ()).getBlockType())) {
|
|
||||||
chunk.setBlock(mut.getBlockX(), mut.getBlockY(), mut.getBlockZ(),
|
|
||||||
shiftStorage.computeIfAbsent(entry.getValue().getBlockType(), BlockType::getDefaultData), false);
|
|
||||||
}
|
|
||||||
} catch(NullPointerException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,179 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver;
|
|
||||||
|
|
||||||
import com.dfsek.paralithic.Expression;
|
|
||||||
import com.dfsek.paralithic.eval.parser.Parser;
|
|
||||||
import com.dfsek.paralithic.eval.parser.Scope;
|
|
||||||
import com.dfsek.paralithic.eval.tokenizer.ParseException;
|
|
||||||
import net.jafama.FastMath;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
import com.dfsek.terra.addons.carver.carving.Carver;
|
|
||||||
import com.dfsek.terra.addons.carver.carving.Worm;
|
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.util.ConstantRange;
|
|
||||||
import com.dfsek.terra.api.util.Range;
|
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
|
||||||
|
|
||||||
public class UserDefinedCarver extends Carver {
|
|
||||||
private final double[] start; // 0, 1, 2 = x, y, z.
|
|
||||||
private final double[] mutate; // 0, 1, 2 = x, y, z. 3 = radius.
|
|
||||||
private final Range length;
|
|
||||||
private final long hash;
|
|
||||||
private final int topCut;
|
|
||||||
private final int bottomCut;
|
|
||||||
private final CarverTemplate config;
|
|
||||||
private final Expression xRad;
|
|
||||||
private final Expression yRad;
|
|
||||||
private final Expression zRad;
|
|
||||||
|
|
||||||
private final Map<Long, CarverCache> cacheMap = new ConcurrentHashMap<>();
|
|
||||||
private final Platform platform;
|
|
||||||
private double step = 2;
|
|
||||||
private Range recalc = new ConstantRange(8, 10);
|
|
||||||
private double recalcMagnitude = 3;
|
|
||||||
|
|
||||||
public UserDefinedCarver(Range height, Range length, double[] start, double[] mutate, List<String> radii, Scope parent, long hash,
|
|
||||||
int topCut, int bottomCut, CarverTemplate config, Platform platform) throws ParseException {
|
|
||||||
super(height.getMin(), height.getMax());
|
|
||||||
this.length = length;
|
|
||||||
this.start = start;
|
|
||||||
this.mutate = mutate;
|
|
||||||
this.hash = hash;
|
|
||||||
this.topCut = topCut;
|
|
||||||
this.bottomCut = bottomCut;
|
|
||||||
this.config = config;
|
|
||||||
this.platform = platform;
|
|
||||||
|
|
||||||
Parser p = new Parser();
|
|
||||||
|
|
||||||
Scope s = new Scope().withParent(parent);
|
|
||||||
|
|
||||||
|
|
||||||
s.addInvocationVariable("x");
|
|
||||||
s.addInvocationVariable("y");
|
|
||||||
s.addInvocationVariable("z");
|
|
||||||
|
|
||||||
s.addInvocationVariable("length");
|
|
||||||
s.addInvocationVariable("position");
|
|
||||||
s.addInvocationVariable("seed");
|
|
||||||
|
|
||||||
|
|
||||||
xRad = p.parse(radii.get(0), s);
|
|
||||||
yRad = p.parse(radii.get(1), s);
|
|
||||||
zRad = p.parse(radii.get(2), s);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer) {
|
|
||||||
synchronized(cacheMap) {
|
|
||||||
CarverCache cache = cacheMap.computeIfAbsent(w.getSeed(), world -> new CarverCache(w, platform, this));
|
|
||||||
int carvingRadius = getCarvingRadius();
|
|
||||||
for(int x = chunkX - carvingRadius; x <= chunkX + carvingRadius; x++) {
|
|
||||||
for(int z = chunkZ - carvingRadius; z <= chunkZ + carvingRadius; z++) {
|
|
||||||
cache.getPoints(x, z).forEach(point -> {
|
|
||||||
Vector3 origin = point.getOrigin();
|
|
||||||
if(FastMath.floorDiv(origin.getBlockX(), 16) != chunkX && FastMath.floorDiv(origin.getBlockZ(), 16) !=
|
|
||||||
chunkZ) // We only want to carve this chunk.
|
|
||||||
return;
|
|
||||||
point.carve(chunkX, chunkZ, consumer, w);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Worm getWorm(long l, Vector3 vector) {
|
|
||||||
Random r = new Random(l + hash);
|
|
||||||
return new UserDefinedWorm(length.get(r) / 2, r, vector, topCut, bottomCut, l);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChunkCarved(World w, int chunkX, int chunkZ, Random random) {
|
|
||||||
/*BiomeTemplate conf = ((UserDefinedBiome) main.getWorld(w).getBiomeProvider().getBiome((chunkX << 4) + 8, (chunkZ << 4) + 8))
|
|
||||||
.getConfig();
|
|
||||||
if(conf.getCarvers().get(this) != null) {
|
|
||||||
return new Random(random.nextLong() + hash).nextInt(100) < conf.getCarvers().get(this);
|
|
||||||
}*/
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecalc(Range recalc) {
|
|
||||||
this.recalc = recalc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRecalcMagnitude(double recalcMagnitude) {
|
|
||||||
this.recalcMagnitude = recalcMagnitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStep(double step) {
|
|
||||||
this.step = step;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CarverTemplate getConfig() {
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class UserDefinedWorm extends Worm {
|
|
||||||
private final Vector3 direction;
|
|
||||||
private final Vector3 origin;
|
|
||||||
private final long seed;
|
|
||||||
private int steps;
|
|
||||||
private int nextDirection = 0;
|
|
||||||
private double[] currentRotation = new double[3];
|
|
||||||
|
|
||||||
public UserDefinedWorm(int length, Random r, Vector3 origin, int topCut, int bottomCut, long seed) {
|
|
||||||
super(length, r, origin);
|
|
||||||
this.origin = origin;
|
|
||||||
this.seed = seed;
|
|
||||||
super.setTopCut(topCut);
|
|
||||||
super.setBottomCut(bottomCut);
|
|
||||||
direction = new Vector3((r.nextDouble() - 0.5D) * start[0], (r.nextDouble() - 0.5D) * start[1],
|
|
||||||
(r.nextDouble() - 0.5D) * start[2]).normalize().multiply(step);
|
|
||||||
double[] args = { origin.getX(), origin.getY(), origin.getZ(), length, 0, seed };
|
|
||||||
setRadius(new int[]{ (int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args)) });
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void step() {
|
|
||||||
if(steps == nextDirection) {
|
|
||||||
direction.rotateAroundX(FastMath.toRadians((getRandom().nextGaussian()) * mutate[0] * recalcMagnitude));
|
|
||||||
direction.rotateAroundY(FastMath.toRadians((getRandom().nextGaussian()) * mutate[1] * recalcMagnitude));
|
|
||||||
direction.rotateAroundZ(FastMath.toRadians((getRandom().nextGaussian()) * mutate[2] * recalcMagnitude));
|
|
||||||
currentRotation = new double[]{
|
|
||||||
(getRandom().nextGaussian()) * mutate[0],
|
|
||||||
(getRandom().nextGaussian()) * mutate[1],
|
|
||||||
(getRandom().nextGaussian()) * mutate[2]
|
|
||||||
};
|
|
||||||
nextDirection += recalc.get(getRandom());
|
|
||||||
}
|
|
||||||
steps++;
|
|
||||||
double[] args = { origin.getX(), origin.getY(), origin.getZ(), getLength(), steps, seed };
|
|
||||||
setRadius(new int[]{ (int) (xRad.evaluate(args)), (int) (yRad.evaluate(args)), (int) (zRad.evaluate(args)) });
|
|
||||||
direction.rotateAroundX(FastMath.toRadians(currentRotation[0] * mutate[0]));
|
|
||||||
direction.rotateAroundY(FastMath.toRadians(currentRotation[1] * mutate[1]));
|
|
||||||
direction.rotateAroundZ(FastMath.toRadians(currentRotation[2] * mutate[2]));
|
|
||||||
getRunning().add(direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WormPoint getPoint() {
|
|
||||||
return new WormPoint(getRunning().clone(), getRadius(), config.getCutTop(), config.getCutBottom());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver.carving;
|
|
||||||
|
|
||||||
import net.jafama.FastMath;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class Carver {
|
|
||||||
private final int minY;
|
|
||||||
private final int maxY;
|
|
||||||
private final double sixtyFourSq = FastMath.pow(64, 2);
|
|
||||||
private int carvingRadius = 4;
|
|
||||||
|
|
||||||
public Carver(int minY, int maxY) {
|
|
||||||
this.minY = minY;
|
|
||||||
this.maxY = maxY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void carve(int chunkX, int chunkZ, World w, BiConsumer<Vector3, CarvingType> consumer);
|
|
||||||
|
|
||||||
public int getCarvingRadius() {
|
|
||||||
return carvingRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCarvingRadius(int carvingRadius) {
|
|
||||||
this.carvingRadius = carvingRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract Worm getWorm(long seed, Vector3 l);
|
|
||||||
|
|
||||||
public abstract boolean isChunkCarved(World w, int chunkX, int chunkZ, Random r);
|
|
||||||
|
|
||||||
public enum CarvingType {
|
|
||||||
CENTER,
|
|
||||||
WALL,
|
|
||||||
TOP,
|
|
||||||
BOTTOM
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.carver.carving;
|
|
||||||
|
|
||||||
import net.jafama.FastMath;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
|
||||||
|
|
||||||
public abstract class Worm {
|
|
||||||
private final Random r;
|
|
||||||
private final Vector3 origin;
|
|
||||||
private final Vector3 running;
|
|
||||||
private final int length;
|
|
||||||
private int topCut = 0;
|
|
||||||
private int bottomCut = 0;
|
|
||||||
private int[] radius = { 0, 0, 0 };
|
|
||||||
|
|
||||||
public Worm(int length, Random r, Vector3 origin) {
|
|
||||||
this.r = r;
|
|
||||||
this.length = length;
|
|
||||||
this.origin = origin;
|
|
||||||
this.running = origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void step();
|
|
||||||
|
|
||||||
public void setBottomCut(int bottomCut) {
|
|
||||||
this.bottomCut = bottomCut;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTopCut(int topCut) {
|
|
||||||
this.topCut = topCut;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3 getOrigin() {
|
|
||||||
return origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLength() {
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3 getRunning() {
|
|
||||||
return running;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WormPoint getPoint() {
|
|
||||||
return new WormPoint(running, radius, topCut, bottomCut);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] getRadius() {
|
|
||||||
return radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRadius(int[] radius) {
|
|
||||||
this.radius = radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Random getRandom() {
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class WormPoint {
|
|
||||||
private final Vector3 origin;
|
|
||||||
private final int topCut;
|
|
||||||
private final int bottomCut;
|
|
||||||
private final int[] rad;
|
|
||||||
|
|
||||||
public WormPoint(Vector3 origin, int[] rad, int topCut, int bottomCut) {
|
|
||||||
this.origin = origin;
|
|
||||||
this.rad = rad;
|
|
||||||
this.topCut = topCut;
|
|
||||||
this.bottomCut = bottomCut;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double ellipseEquation(int x, int y, int z, double xr, double yr, double zr) {
|
|
||||||
return (FastMath.pow2(x) / FastMath.pow2(xr + 0.5D)) + (FastMath.pow2(y) / FastMath.pow2(yr + 0.5D)) + (FastMath.pow2(z) /
|
|
||||||
FastMath.pow2(
|
|
||||||
zr + 0.5D));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void carve(int chunkX, int chunkZ, BiConsumer<Vector3, Carver.CarvingType> consumer, World world) {
|
|
||||||
int xRad = getRadius(0);
|
|
||||||
int yRad = getRadius(1);
|
|
||||||
int zRad = getRadius(2);
|
|
||||||
int originX = (chunkX << 4);
|
|
||||||
int originZ = (chunkZ << 4);
|
|
||||||
for(int x = -xRad - 1; x <= xRad + 1; x++) {
|
|
||||||
if(!(FastMath.floorDiv(origin.getBlockX() + x, 16) == chunkX)) continue;
|
|
||||||
for(int z = -zRad - 1; z <= zRad + 1; z++) {
|
|
||||||
if(!(FastMath.floorDiv(origin.getBlockZ() + z, 16) == chunkZ)) continue;
|
|
||||||
for(int y = -yRad - 1; y <= yRad + 1; y++) {
|
|
||||||
Vector3 position = origin.clone().add(new Vector3(x, y, z));
|
|
||||||
if(position.getY() < world.getMinHeight() || position.getY() > world.getMaxHeight()) continue;
|
|
||||||
double eq = ellipseEquation(x, y, z, xRad, yRad, zRad);
|
|
||||||
if(eq <= 1 &&
|
|
||||||
y >= -yRad - 1 + bottomCut && y <= yRad + 1 - topCut) {
|
|
||||||
consumer.accept(
|
|
||||||
new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ),
|
|
||||||
Carver.CarvingType.CENTER);
|
|
||||||
} else if(eq <= 1.5) {
|
|
||||||
Carver.CarvingType type = Carver.CarvingType.WALL;
|
|
||||||
if(y <= -yRad - 1 + bottomCut) {
|
|
||||||
type = Carver.CarvingType.BOTTOM;
|
|
||||||
} else if(y >= yRad + 1 - topCut) {
|
|
||||||
type = Carver.CarvingType.TOP;
|
|
||||||
}
|
|
||||||
consumer.accept(
|
|
||||||
new Vector3(position.getBlockX() - originX, position.getBlockY(), position.getBlockZ() - originZ),
|
|
||||||
type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vector3 getOrigin() {
|
|
||||||
return origin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getRadius(int index) {
|
|
||||||
return rad[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
schema-version: 1
|
|
||||||
contributors:
|
|
||||||
- Terra contributors
|
|
||||||
id: config-carver
|
|
||||||
version: @VERSION@
|
|
||||||
entrypoints: []
|
|
||||||
website:
|
|
||||||
issues: https://github.com/PolyhedralDev/Terra-config-carver/issues
|
|
||||||
source: https://github.com/PolyhedralDev/Terra-config-carver
|
|
||||||
docs: https://github.com/PolyhedralDev/Terra/wiki
|
|
||||||
license: GNU LGPL v3.0
|
|
@ -14,6 +14,7 @@ import com.dfsek.terra.api.structure.feature.Feature;
|
|||||||
import com.dfsek.terra.api.structure.feature.Locator;
|
import com.dfsek.terra.api.structure.feature.Locator;
|
||||||
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.access.World;
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
|
|
||||||
public class ConfiguredFeature implements Feature {
|
public class ConfiguredFeature implements Feature {
|
||||||
@ -32,7 +33,7 @@ public class ConfiguredFeature implements Feature {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Structure getStructure(World world, int x, int y, int z) {
|
public Structure getStructure(WorldAccess world, int x, int y, int z) {
|
||||||
return structures.get(structureSelector, x, y, z, world.getSeed());
|
return structures.get(structureSelector, x, y, z, world.getSeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.flora.flora.gen;
|
package com.dfsek.terra.addons.flora.flora.gen;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import net.jafama.FastMath;
|
import net.jafama.FastMath;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -56,7 +58,7 @@ public class TerraFlora implements Structure {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void test(EnumSet<Direction> faces, Direction f, Vector3 b, World world) {
|
private void test(EnumSet<Direction> faces, Direction f, Vector3 b, WorldAccess world) {
|
||||||
if(testRotation.contains(
|
if(testRotation.contains(
|
||||||
world.getBlockData(b.getBlockX() + f.getModX(), b.getBlockY() + f.getModY(), b.getBlockZ() + f.getModZ()).getBlockType()))
|
world.getBlockData(b.getBlockX() + f.getModX(), b.getBlockY() + f.getModY(), b.getBlockZ() + f.getModZ()).getBlockType()))
|
||||||
faces.add(f);
|
faces.add(f);
|
||||||
@ -66,7 +68,7 @@ public class TerraFlora implements Structure {
|
|||||||
return layers.get(FastMath.max(FastMath.min(layer, layers.size() - 1), 0));
|
return layers.get(FastMath.max(FastMath.min(layer, layers.size() - 1), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private EnumSet<Direction> getFaces(Vector3 b, World world) {
|
private EnumSet<Direction> getFaces(Vector3 b, WorldAccess world) {
|
||||||
EnumSet<Direction> faces = EnumSet.noneOf(Direction.class);
|
EnumSet<Direction> faces = EnumSet.noneOf(Direction.class);
|
||||||
test(faces, Direction.NORTH, b, world);
|
test(faces, Direction.NORTH, b, world);
|
||||||
test(faces, Direction.SOUTH, b, world);
|
test(faces, Direction.SOUTH, b, world);
|
||||||
@ -81,17 +83,17 @@ public class TerraFlora implements Structure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generate(Vector3 location, World world, Chunk chunk, Random random, Rotation rotation) {
|
public boolean generate(Vector3 location, WorldAccess world, Chunk chunk, Random random, Rotation rotation) {
|
||||||
return generate(location, world, random, rotation);
|
return generate(location, world, random, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generate(Buffer buffer, World world, Random random, Rotation rotation, int recursions) {
|
public boolean generate(Buffer buffer, WorldAccess world, Random random, Rotation rotation, int recursions) {
|
||||||
return generate(buffer.getOrigin(), world, random, rotation);
|
return generate(buffer.getOrigin(), world, random, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generate(Vector3 location, World world, Random random, Rotation rotation) {
|
public boolean generate(Vector3 location, WorldAccess world, Random random, Rotation rotation) {
|
||||||
boolean doRotation = testRotation.size() > 0;
|
boolean doRotation = testRotation.size() > 0;
|
||||||
int size = layers.size();
|
int size = layers.size();
|
||||||
int c = ceiling ? -1 : 1;
|
int c = ceiling ? -1 : 1;
|
||||||
|
@ -21,7 +21,7 @@ public class Noise3DLocator implements Locator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BinaryColumn getSuitableCoordinates(Column column) {
|
public BinaryColumn getSuitableCoordinates(Column<?> column) {
|
||||||
BinaryColumn results = column.newBinaryColumn();
|
BinaryColumn results = column.newBinaryColumn();
|
||||||
long seed = column.getWorld().getSeed();
|
long seed = column.getWorld().getSeed();
|
||||||
int x = column.getX();
|
int x = column.getX();
|
||||||
|
@ -25,7 +25,7 @@ public class NoiseLocator implements Locator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BinaryColumn getSuitableCoordinates(Column column) {
|
public BinaryColumn getSuitableCoordinates(Column<?> column) {
|
||||||
BinaryColumn results = new BinaryColumn(column.getMinY(), column.getMaxY());
|
BinaryColumn results = new BinaryColumn(column.getMinY(), column.getMaxY());
|
||||||
|
|
||||||
long seed = column.getWorld().getSeed();
|
long seed = column.getWorld().getSeed();
|
||||||
|
@ -24,7 +24,7 @@ public class PatternLocator implements Locator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BinaryColumn getSuitableCoordinates(Column column) {
|
public BinaryColumn getSuitableCoordinates(Column<?> column) {
|
||||||
BinaryColumn locations = new BinaryColumn(column.getMinY(), column.getMaxY());
|
BinaryColumn locations = new BinaryColumn(column.getMinY(), column.getMaxY());
|
||||||
|
|
||||||
for(int y : search) {
|
for(int y : search) {
|
||||||
|
@ -26,7 +26,7 @@ public class RandomLocator implements Locator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BinaryColumn getSuitableCoordinates(Column column) {
|
public BinaryColumn getSuitableCoordinates(Column<?> column) {
|
||||||
long seed = column.getWorld().getSeed();
|
long seed = column.getWorld().getSeed();
|
||||||
seed = 31 * seed + column.getX();
|
seed = 31 * seed + column.getX();
|
||||||
seed = 31 * seed + column.getZ();
|
seed = 31 * seed + column.getZ();
|
||||||
|
@ -21,7 +21,7 @@ public class SurfaceLocator implements Locator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BinaryColumn getSuitableCoordinates(Column column) {
|
public BinaryColumn getSuitableCoordinates(Column<?> column) {
|
||||||
BinaryColumn location = new BinaryColumn(column.getMinY(), column.getMaxY());
|
BinaryColumn location = new BinaryColumn(column.getMinY(), column.getMaxY());
|
||||||
for(int y : search) {
|
for(int y : search) {
|
||||||
if(column.getBlock(y).isAir() && !column.getBlock(y - 1).isAir()) {
|
if(column.getBlock(y).isAir() && !column.getBlock(y - 1).isAir()) {
|
||||||
|
@ -30,7 +30,6 @@ public class OreAddon implements AddonInitializer {
|
|||||||
.register(addon, ConfigPackPreLoadEvent.class)
|
.register(addon, ConfigPackPreLoadEvent.class)
|
||||||
.then(event -> {
|
.then(event -> {
|
||||||
event.getPack().registerConfigType(new OreConfigType(), "ORE", 1);
|
event.getPack().registerConfigType(new OreConfigType(), "ORE", 1);
|
||||||
event.getPack().getOrCreateRegistry(GenerationStageProvider.class).register("ORE", pack -> new OrePopulator(platform));
|
|
||||||
})
|
})
|
||||||
.failThrough();
|
.failThrough();
|
||||||
}
|
}
|
||||||
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.ore;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.profiler.ProfileFrame;
|
|
||||||
import com.dfsek.terra.api.util.PopulationUtil;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
import com.dfsek.terra.api.world.biome.TerraBiome;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
|
||||||
|
|
||||||
|
|
||||||
public class OrePopulator implements GenerationStage {
|
|
||||||
private final Platform platform;
|
|
||||||
|
|
||||||
public OrePopulator(Platform platform) {
|
|
||||||
this.platform = platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("try")
|
|
||||||
@Override
|
|
||||||
public void populate(@NotNull World world, @NotNull Chunk chunk) {
|
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("ore")) {
|
|
||||||
if(world.getConfig().disableOres()) return;
|
|
||||||
|
|
||||||
for(int cx = -1; cx <= 1; cx++) {
|
|
||||||
for(int cz = -1; cz <= 1; cz++) {
|
|
||||||
Random random = new Random(PopulationUtil.getCarverChunkSeed(chunk.getX() + cx, chunk.getZ() + cz, world.getSeed()));
|
|
||||||
int originX = ((chunk.getX() + cx) << 4);
|
|
||||||
int originZ = ((chunk.getZ() + cz) << 4);
|
|
||||||
TerraBiome b = world.getBiomeProvider().getBiome(originX + 8, originZ + 8, world.getSeed());
|
|
||||||
/*
|
|
||||||
BiomeTemplate config = ((UserDefinedBiome) b).getConfig();
|
|
||||||
int finalCx = cx;
|
|
||||||
int finalCz = cz;
|
|
||||||
config.getOreHolder().forEach((id, orePair) -> {
|
|
||||||
try(ProfileFrame ignored = main.getProfiler().profile("ore:" + id)) {
|
|
||||||
int amount = orePair.getRight().getAmount().get(random);
|
|
||||||
for(int i = 0; i < amount; i++) {
|
|
||||||
Vector3 location = new Vector3(random.nextInt(16) + 16 * finalCx, orePair.getRight().getHeight().get
|
|
||||||
(random), random.nextInt(16) + 16 * finalCz);
|
|
||||||
orePair.getLeft().generate(location, chunk, random);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020-2021 Polyhedral Development
|
|
||||||
*
|
|
||||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
|
||||||
* reference the LICENSE file in this module's root directory.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.addons.structure;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import net.jafama.FastMath;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.config.WorldConfig;
|
|
||||||
import com.dfsek.terra.api.profiler.ProfileFrame;
|
|
||||||
import com.dfsek.terra.api.structure.configured.ConfiguredStructure;
|
|
||||||
import com.dfsek.terra.api.util.Rotation;
|
|
||||||
import com.dfsek.terra.api.util.PopulationUtil;
|
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
|
||||||
|
|
||||||
|
|
||||||
public class StructurePopulator implements GenerationStage, Chunkified {
|
|
||||||
private final Platform platform;
|
|
||||||
|
|
||||||
public StructurePopulator(Platform platform) {
|
|
||||||
this.platform = platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("try")
|
|
||||||
@Override
|
|
||||||
public void populate(@NotNull World world, @NotNull Chunk chunk) {
|
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("structure")) {
|
|
||||||
if(world.getConfig().disableStructures()) return;
|
|
||||||
|
|
||||||
int cx = (chunk.getX() << 4);
|
|
||||||
int cz = (chunk.getZ() << 4);
|
|
||||||
BiomeProvider provider = world.getBiomeProvider();
|
|
||||||
WorldConfig config = world.getConfig();
|
|
||||||
for(ConfiguredStructure conf : config.getRegistry(TerraStructure.class).entries()) {
|
|
||||||
Vector3 spawn = conf.getSpawn().getNearestSpawn(cx + 8, cz + 8, world.getSeed());
|
|
||||||
|
|
||||||
if(!provider.getBiome(spawn, world.getSeed()).getContext().get(BiomeStructures.class).getStructures().contains(conf)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Random random = new Random(PopulationUtil.getCarverChunkSeed(FastMath.floorDiv(spawn.getBlockX(), 16),
|
|
||||||
FastMath.floorDiv(spawn.getBlockZ(), 16), world.getSeed()));
|
|
||||||
conf.getStructure().get(random).generate(spawn.setY(conf.getSpawnStart().get(random)), world, chunk, random,
|
|
||||||
Rotation.fromDegrees(90 * random.nextInt(4)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,14 +13,15 @@ import com.dfsek.terra.api.block.state.BlockState;
|
|||||||
import com.dfsek.terra.api.structure.feature.BinaryColumn;
|
import com.dfsek.terra.api.structure.feature.BinaryColumn;
|
||||||
import com.dfsek.terra.api.world.access.Column;
|
import com.dfsek.terra.api.world.access.Column;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.access.World;
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
|
|
||||||
public class ColumnImpl implements Column {
|
public class ColumnImpl<T extends WorldAccess> implements Column<T> {
|
||||||
private final int x;
|
private final int x;
|
||||||
private final int z;
|
private final int z;
|
||||||
private final World world;
|
private final T world;
|
||||||
|
|
||||||
public ColumnImpl(int x, int z, World world) {
|
public ColumnImpl(int x, int z, T world) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.z = z;
|
this.z = z;
|
||||||
this.world = world;
|
this.world = world;
|
||||||
@ -42,7 +43,7 @@ public class ColumnImpl implements Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public World getWorld() {
|
public T getWorld() {
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,10 +13,11 @@ import com.dfsek.terra.api.profiler.ProfileFrame;
|
|||||||
import com.dfsek.terra.api.util.Rotation;
|
import com.dfsek.terra.api.util.Rotation;
|
||||||
import com.dfsek.terra.api.util.PopulationUtil;
|
import com.dfsek.terra.api.util.PopulationUtil;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.chunk.generation.ProtoWorld;
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
|
||||||
public class FeatureGenerationStage implements GenerationStage {
|
public class FeatureGenerationStage implements GenerationStage {
|
||||||
private final Platform platform;
|
private final Platform platform;
|
||||||
@ -27,23 +28,23 @@ public class FeatureGenerationStage implements GenerationStage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("try")
|
@SuppressWarnings("try")
|
||||||
public void populate(World world, Chunk chunk) {
|
public void populate(ProtoWorld world) {
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("feature")) {
|
try(ProfileFrame ignore = platform.getProfiler().profile("feature")) {
|
||||||
int cx = chunk.getX() << 4;
|
int cx = world.centerChunkX() << 4;
|
||||||
int cz = chunk.getZ() << 4;
|
int cz = world.centerChunkZ() << 4;
|
||||||
long seed = world.getSeed();
|
long seed = world.getSeed();
|
||||||
for(int x = 0; x < 16; x++) {
|
for(int x = 0; x < 16; x++) {
|
||||||
for(int z = 0; z < 16; z++) {
|
for(int z = 0; z < 16; z++) {
|
||||||
int tx = cx + x;
|
int tx = cx + x;
|
||||||
int tz = cz + z;
|
int tz = cz + z;
|
||||||
ColumnImpl column = new ColumnImpl(tx, tz, world);
|
ColumnImpl<ProtoWorld> column = new ColumnImpl<>(tx, tz, world);
|
||||||
world.getBiomeProvider().getBiome(tx, tz, seed).getContext().get(BiomeFeatures.class).getFeatures().forEach(feature -> {
|
world.getBiomeProvider().getBiome(tx, tz, seed).getContext().get(BiomeFeatures.class).getFeatures().forEach(feature -> {
|
||||||
if(feature.getDistributor().matches(tx, tz, seed)) {
|
if(feature.getDistributor().matches(tx, tz, seed)) {
|
||||||
feature.getLocator()
|
feature.getLocator()
|
||||||
.getSuitableCoordinates(column)
|
.getSuitableCoordinates(column)
|
||||||
.forEach(y ->
|
.forEach(y ->
|
||||||
feature.getStructure(world, tx, y, tz)
|
feature.getStructure(world, tx, y, tz)
|
||||||
.generate(new Vector3(tx, y, tz), world, PopulationUtil.getRandom(chunk),
|
.generate(new Vector3(tx, y, tz), world, new Random(PopulationUtil.getCarverChunkSeed(world.centerChunkX(), world.centerChunkZ(), seed)),
|
||||||
Rotation.NONE)
|
Rotation.NONE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package com.dfsek.terra.addons.generation.structure;
|
package com.dfsek.terra.addons.generation.structure;
|
||||||
|
|
||||||
import com.dfsek.terra.api.Platform;
|
import com.dfsek.terra.api.Platform;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.chunk.generation.ProtoWorld;
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
import com.dfsek.terra.api.world.chunk.generation.stage.GenerationStage;
|
||||||
|
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ public class StructureGenerationStage implements GenerationStage {
|
|||||||
public StructureGenerationStage(Platform platform) { this.platform = platform; }
|
public StructureGenerationStage(Platform platform) { this.platform = platform; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void populate(World world, Chunk chunk) {
|
public void populate(ProtoWorld world) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.sponge;
|
package com.dfsek.terra.addons.sponge;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import net.jafama.FastMath;
|
import net.jafama.FastMath;
|
||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
@ -20,7 +22,6 @@ import com.dfsek.terra.api.util.Rotation;
|
|||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.util.vector.integer.Vector2Int;
|
import com.dfsek.terra.api.util.vector.integer.Vector2Int;
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
import com.dfsek.terra.api.world.chunk.Chunk;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
|
||||||
|
|
||||||
public class SpongeStructure implements Structure {
|
public class SpongeStructure implements Structure {
|
||||||
@ -37,7 +38,7 @@ public class SpongeStructure implements Structure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generate(Vector3 location, World world, Chunk chunk, Random random, Rotation rotation) {
|
public boolean generate(Vector3 location, WorldAccess world, Chunk chunk, Random random, Rotation rotation) {
|
||||||
int bX = location.getBlockX();
|
int bX = location.getBlockX();
|
||||||
int bY = location.getBlockY();
|
int bY = location.getBlockY();
|
||||||
int bZ = location.getBlockZ();
|
int bZ = location.getBlockZ();
|
||||||
@ -60,7 +61,7 @@ public class SpongeStructure implements Structure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generate(Buffer buffer, World world, Random random, Rotation rotation, int recursions) {
|
public boolean generate(Buffer buffer, WorldAccess world, Random random, Rotation rotation, int recursions) {
|
||||||
for(int x = 0; x < blocks.length; x++) {
|
for(int x = 0; x < blocks.length; x++) {
|
||||||
for(int z = 0; z < blocks[x].length; z++) {
|
for(int z = 0; z < blocks[x].length; z++) {
|
||||||
Vector2Int r = Vector2Int.of(x, z).rotate(rotation);
|
Vector2Int r = Vector2Int.of(x, z).rotate(rotation);
|
||||||
@ -77,7 +78,7 @@ public class SpongeStructure implements Structure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean generate(Vector3 location, World world, Random random, Rotation rotation) {
|
public boolean generate(Vector3 location, WorldAccess world, Random random, Rotation rotation) {
|
||||||
int bX = location.getBlockX();
|
int bX = location.getBlockX();
|
||||||
int bY = location.getBlockY();
|
int bY = location.getBlockY();
|
||||||
int bZ = location.getBlockZ();
|
int bZ = location.getBlockZ();
|
||||||
|
@ -13,7 +13,7 @@ import com.dfsek.terra.api.entity.EntityType;
|
|||||||
import com.dfsek.terra.api.event.events.world.generation.EntitySpawnEvent;
|
import com.dfsek.terra.api.event.events.world.generation.EntitySpawnEvent;
|
||||||
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
|
|
||||||
public class BufferedEntity implements BufferedItem {
|
public class BufferedEntity implements BufferedItem {
|
||||||
@ -27,7 +27,7 @@ public class BufferedEntity implements BufferedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paste(Vector3 origin, World world) {
|
public void paste(Vector3 origin, WorldAccess world) {
|
||||||
Entity entity = world.spawnEntity(origin.clone().add(0.5, 0, 0.5), type);
|
Entity entity = world.spawnEntity(origin.clone().add(0.5, 0, 0.5), type);
|
||||||
platform.getEventManager().callEvent(new EntitySpawnEvent(entity.world().getConfig().getPack(), entity));
|
platform.getEventManager().callEvent(new EntitySpawnEvent(entity.world().getConfig().getPack(), entity));
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ import com.dfsek.terra.api.event.events.world.generation.LootPopulateEvent;
|
|||||||
import com.dfsek.terra.api.structure.LootTable;
|
import com.dfsek.terra.api.structure.LootTable;
|
||||||
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -37,7 +38,7 @@ public class BufferedLootApplication implements BufferedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paste(Vector3 origin, World world) {
|
public void paste(Vector3 origin, WorldAccess world) {
|
||||||
try {
|
try {
|
||||||
BlockEntity data = world.getBlockState(origin);
|
BlockEntity data = world.getBlockState(origin);
|
||||||
if(!(data instanceof Container container)) {
|
if(!(data instanceof Container container)) {
|
||||||
|
@ -10,7 +10,7 @@ package com.dfsek.terra.addons.terrascript.buffer.items;
|
|||||||
import com.dfsek.terra.api.block.state.BlockState;
|
import com.dfsek.terra.api.block.state.BlockState;
|
||||||
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
|
|
||||||
public class BufferedPulledBlock implements BufferedItem {
|
public class BufferedPulledBlock implements BufferedItem {
|
||||||
@ -21,7 +21,7 @@ public class BufferedPulledBlock implements BufferedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paste(Vector3 origin, World world) {
|
public void paste(Vector3 origin, WorldAccess world) {
|
||||||
Vector3 mutable = origin.clone();
|
Vector3 mutable = origin.clone();
|
||||||
while(mutable.getY() > world.getMinHeight()) {
|
while(mutable.getY() > world.getMinHeight()) {
|
||||||
if(!world.getBlockData(mutable).isAir()) {
|
if(!world.getBlockData(mutable).isAir()) {
|
||||||
|
@ -10,7 +10,8 @@ package com.dfsek.terra.addons.terrascript.buffer.items;
|
|||||||
import com.dfsek.terra.api.block.entity.BlockEntity;
|
import com.dfsek.terra.api.block.entity.BlockEntity;
|
||||||
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -26,7 +27,7 @@ public class BufferedStateManipulator implements BufferedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paste(Vector3 origin, World world) {
|
public void paste(Vector3 origin, WorldAccess world) {
|
||||||
try {
|
try {
|
||||||
BlockEntity state = world.getBlockState(origin);
|
BlockEntity state = world.getBlockState(origin);
|
||||||
state.applyState(data);
|
state.applyState(data);
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.terrascript.script;
|
package com.dfsek.terra.addons.terrascript.script;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import net.jafama.FastMath;
|
import net.jafama.FastMath;
|
||||||
@ -136,7 +138,7 @@ public class StructureScript implements Structure {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("try")
|
@SuppressWarnings("try")
|
||||||
public boolean generate(Vector3 location, World world, Chunk chunk, Random random, Rotation rotation) {
|
public boolean generate(Vector3 location, WorldAccess world, Chunk chunk, Random random, Rotation rotation) {
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_chunk:" + id)) {
|
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_chunk:" + id)) {
|
||||||
StructureBuffer buffer = computeBuffer(location, world, random, rotation);
|
StructureBuffer buffer = computeBuffer(location, world, random, rotation);
|
||||||
buffer.paste(location, chunk);
|
buffer.paste(location, chunk);
|
||||||
@ -146,7 +148,7 @@ public class StructureScript implements Structure {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("try")
|
@SuppressWarnings("try")
|
||||||
public boolean generate(Buffer buffer, World world, Random random, Rotation rotation, int recursions) {
|
public boolean generate(Buffer buffer, WorldAccess world, Random random, Rotation rotation, int recursions) {
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_recursive:" + id)) {
|
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_recursive:" + id)) {
|
||||||
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, world, recursions));
|
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, world, recursions));
|
||||||
}
|
}
|
||||||
@ -154,7 +156,7 @@ public class StructureScript implements Structure {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("try")
|
@SuppressWarnings("try")
|
||||||
public boolean generate(Vector3 location, World world, Random random, Rotation rotation) {
|
public boolean generate(Vector3 location, WorldAccess world, Random random, Rotation rotation) {
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_direct:" + id)) {
|
try(ProfileFrame ignore = platform.getProfiler().profile("terrascript_direct:" + id)) {
|
||||||
DirectBuffer buffer = new DirectBuffer(location, world);
|
DirectBuffer buffer = new DirectBuffer(location, world);
|
||||||
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, world, 0));
|
return applyBlock(new TerraImplementationArguments(buffer, rotation, random, world, 0));
|
||||||
@ -169,7 +171,7 @@ public class StructureScript implements Structure {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private StructureBuffer computeBuffer(Vector3 location, World world, Random random, Rotation rotation) {
|
private StructureBuffer computeBuffer(Vector3 location, WorldAccess world, Random random, Rotation rotation) {
|
||||||
try {
|
try {
|
||||||
return cache.get(location, () -> {
|
return cache.get(location, () -> {
|
||||||
StructureBuffer buf = new StructureBuffer(location);
|
StructureBuffer buf = new StructureBuffer(location);
|
||||||
|
@ -13,17 +13,18 @@ import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
|||||||
import com.dfsek.terra.api.structure.buffer.Buffer;
|
import com.dfsek.terra.api.structure.buffer.Buffer;
|
||||||
import com.dfsek.terra.api.util.Rotation;
|
import com.dfsek.terra.api.util.Rotation;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.access.World;
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
|
|
||||||
public class TerraImplementationArguments implements ImplementationArguments {
|
public class TerraImplementationArguments implements ImplementationArguments {
|
||||||
private final Buffer buffer;
|
private final Buffer buffer;
|
||||||
private final Rotation rotation;
|
private final Rotation rotation;
|
||||||
private final Random random;
|
private final Random random;
|
||||||
private final World world;
|
private final WorldAccess world;
|
||||||
private final int recursions;
|
private final int recursions;
|
||||||
private boolean waterlog = false;
|
private boolean waterlog = false;
|
||||||
|
|
||||||
public TerraImplementationArguments(Buffer buffer, Rotation rotation, Random random, World world, int recursions) {
|
public TerraImplementationArguments(Buffer buffer, Rotation rotation, Random random, WorldAccess world, int recursions) {
|
||||||
this.buffer = buffer;
|
this.buffer = buffer;
|
||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
this.random = random;
|
this.random = random;
|
||||||
@ -55,7 +56,7 @@ public class TerraImplementationArguments implements ImplementationArguments {
|
|||||||
this.waterlog = waterlog;
|
this.waterlog = waterlog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public World getWorld() {
|
public WorldAccess getWorld() {
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.addons.terrascript.script.functions;
|
package com.dfsek.terra.addons.terrascript.script.functions;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import net.jafama.FastMath;
|
import net.jafama.FastMath;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -68,7 +70,7 @@ public class CheckFunction implements Function<String> {
|
|||||||
return ReturnType.STRING;
|
return ReturnType.STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String apply(Vector3 vector, World world) {
|
private String apply(Vector3 vector, WorldAccess world) {
|
||||||
int y = vector.getBlockY();
|
int y = vector.getBlockY();
|
||||||
if(y >= world.getMaxHeight() || y < 0) return "AIR";
|
if(y >= world.getMaxHeight() || y < 0) return "AIR";
|
||||||
SamplerCache cache = world.getConfig().getSamplerCache();
|
SamplerCache cache = world.getConfig().getSamplerCache();
|
||||||
|
@ -13,14 +13,14 @@ import com.dfsek.terra.api.structure.buffer.Buffer;
|
|||||||
import com.dfsek.terra.api.util.Rotation;
|
import com.dfsek.terra.api.util.Rotation;
|
||||||
import com.dfsek.terra.api.util.StringIdentifiable;
|
import com.dfsek.terra.api.util.StringIdentifiable;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
import com.dfsek.terra.api.world.chunk.Chunk;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
|
||||||
|
|
||||||
public interface Structure extends StringIdentifiable {
|
public interface Structure extends StringIdentifiable {
|
||||||
boolean generate(Vector3 location, World world, Chunk chunk, Random random, Rotation rotation);
|
boolean generate(Vector3 location, WorldAccess world, Chunk chunk, Random random, Rotation rotation);
|
||||||
|
|
||||||
boolean generate(Buffer buffer, World world, Random random, Rotation rotation, int recursions);
|
boolean generate(Buffer buffer, WorldAccess world, Random random, Rotation rotation, int recursions);
|
||||||
|
|
||||||
boolean generate(Vector3 location, World world, Random random, Rotation rotation);
|
boolean generate(Vector3 location, WorldAccess world, Random random, Rotation rotation);
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,13 @@
|
|||||||
package com.dfsek.terra.api.structure.buffer;
|
package com.dfsek.terra.api.structure.buffer;
|
||||||
|
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus.Experimental;
|
import org.jetbrains.annotations.ApiStatus.Experimental;
|
||||||
|
|
||||||
|
|
||||||
@Experimental
|
@Experimental
|
||||||
public interface BufferedItem {
|
public interface BufferedItem {
|
||||||
void paste(Vector3 origin, World world);
|
void paste(Vector3 origin, WorldAccess world);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import java.util.Map;
|
|||||||
import com.dfsek.terra.api.structure.buffer.Buffer;
|
import com.dfsek.terra.api.structure.buffer.Buffer;
|
||||||
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
import com.dfsek.terra.api.world.chunk.Chunk;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.access.World;
|
||||||
|
|
||||||
@ -25,10 +26,10 @@ import org.jetbrains.annotations.ApiStatus.Experimental;
|
|||||||
@Experimental
|
@Experimental
|
||||||
public class DirectBuffer implements Buffer {
|
public class DirectBuffer implements Buffer {
|
||||||
private final Vector3 origin;
|
private final Vector3 origin;
|
||||||
private final World target;
|
private final WorldAccess target;
|
||||||
private final Map<Vector3, String> marks = new LinkedHashMap<>();
|
private final Map<Vector3, String> marks = new LinkedHashMap<>();
|
||||||
|
|
||||||
public DirectBuffer(Vector3 origin, World target) {
|
public DirectBuffer(Vector3 origin, WorldAccess target) {
|
||||||
this.origin = origin;
|
this.origin = origin;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.api.structure.buffer.items;
|
package com.dfsek.terra.api.structure.buffer.items;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus.Experimental;
|
import org.jetbrains.annotations.ApiStatus.Experimental;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@ -16,7 +18,7 @@ import com.dfsek.terra.api.block.state.BlockState;
|
|||||||
import com.dfsek.terra.api.block.state.properties.base.Properties;
|
import com.dfsek.terra.api.block.state.properties.base.Properties;
|
||||||
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
|
||||||
@Experimental
|
@Experimental
|
||||||
public class BufferedBlock implements BufferedItem {
|
public class BufferedBlock implements BufferedItem {
|
||||||
@ -35,7 +37,7 @@ public class BufferedBlock implements BufferedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paste(Vector3 origin, World world) {
|
public void paste(Vector3 origin, WorldAccess world) {
|
||||||
try {
|
try {
|
||||||
BlockState current = world.getBlockData(origin);
|
BlockState current = world.getBlockData(origin);
|
||||||
if(overwrite || current.isAir()) {
|
if(overwrite || current.isAir()) {
|
||||||
|
@ -12,7 +12,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
import com.dfsek.terra.api.structure.buffer.BufferedItem;
|
||||||
import com.dfsek.terra.api.util.vector.Vector3;
|
import com.dfsek.terra.api.util.vector.Vector3;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
import org.jetbrains.annotations.ApiStatus.Experimental;
|
import org.jetbrains.annotations.ApiStatus.Experimental;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ public class Cell implements BufferedItem {
|
|||||||
private String mark;
|
private String mark;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void paste(Vector3 origin, World world) {
|
public void paste(Vector3 origin, WorldAccess world) {
|
||||||
items.forEach(item -> item.paste(origin.clone(), world));
|
items.forEach(item -> item.paste(origin.clone(), world));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,10 +9,11 @@ package com.dfsek.terra.api.structure.feature;
|
|||||||
|
|
||||||
import com.dfsek.terra.api.structure.Structure;
|
import com.dfsek.terra.api.structure.Structure;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
import com.dfsek.terra.api.world.access.World;
|
||||||
|
import com.dfsek.terra.api.world.access.WorldAccess;
|
||||||
|
|
||||||
|
|
||||||
public interface Feature {
|
public interface Feature {
|
||||||
Structure getStructure(World world, int x, int y, int z);
|
Structure getStructure(WorldAccess world, int x, int y, int z);
|
||||||
|
|
||||||
Distributor getDistributor();
|
Distributor getDistributor();
|
||||||
|
|
||||||
|
@ -19,5 +19,5 @@ public interface Locator {
|
|||||||
return column -> this.getSuitableCoordinates(column).or(that.getSuitableCoordinates(column));
|
return column -> this.getSuitableCoordinates(column).or(that.getSuitableCoordinates(column));
|
||||||
}
|
}
|
||||||
|
|
||||||
BinaryColumn getSuitableCoordinates(Column column);
|
BinaryColumn getSuitableCoordinates(Column<?> column);
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,14 @@ import com.dfsek.terra.api.structure.feature.BinaryColumn;
|
|||||||
/**
|
/**
|
||||||
* A single vertical column of a world.
|
* A single vertical column of a world.
|
||||||
*/
|
*/
|
||||||
public interface Column {
|
public interface Column<T extends WorldAccess> {
|
||||||
int getX();
|
int getX();
|
||||||
|
|
||||||
int getZ();
|
int getZ();
|
||||||
|
|
||||||
BlockState getBlock(int y);
|
BlockState getBlock(int y);
|
||||||
|
|
||||||
World getWorld();
|
T getWorld();
|
||||||
|
|
||||||
int getMinY();
|
int getMinY();
|
||||||
|
|
||||||
|
@ -7,10 +7,9 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.api.world.chunk.generation.stage;
|
package com.dfsek.terra.api.world.chunk.generation.stage;
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
import com.dfsek.terra.api.world.chunk.generation.ProtoWorld;
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
|
|
||||||
|
|
||||||
public interface GenerationStage {
|
public interface GenerationStage {
|
||||||
void populate(World world, Chunk chunk);
|
void populate(ProtoWorld world);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import org.bukkit.Bukkit;
|
|||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.generator.BiomeProvider;
|
import org.bukkit.generator.BiomeProvider;
|
||||||
import org.bukkit.generator.BlockPopulator;
|
import org.bukkit.generator.BlockPopulator;
|
||||||
|
import org.bukkit.generator.LimitedRegion;
|
||||||
import org.bukkit.generator.WorldInfo;
|
import org.bukkit.generator.WorldInfo;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@ -32,6 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.dfsek.terra.api.config.WorldConfig;
|
import com.dfsek.terra.api.config.WorldConfig;
|
||||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
||||||
@ -66,7 +68,12 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
|
public @NotNull List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
|
||||||
return Collections.singletonList(new BukkitPopulatorWrapper(delegate));
|
return delegate.getGenerationStages().stream().map(generationStage -> new BlockPopulator() {
|
||||||
|
@Override
|
||||||
|
public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull LimitedRegion limitedRegion) {
|
||||||
|
generationStage.populate(new BukkitProtoWorld(limitedRegion));
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,54 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Terra.
|
|
||||||
*
|
|
||||||
* Terra 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.
|
|
||||||
*
|
|
||||||
* Terra 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 Terra. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.bukkit.generator;
|
|
||||||
|
|
||||||
import org.bukkit.Chunk;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.generator.BlockPopulator;
|
|
||||||
import org.bukkit.generator.LimitedRegion;
|
|
||||||
import org.bukkit.generator.WorldInfo;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified;
|
|
||||||
import com.dfsek.terra.bukkit.world.BukkitAdapter;
|
|
||||||
|
|
||||||
|
|
||||||
public class BukkitPopulatorWrapper extends BlockPopulator {
|
|
||||||
private final ChunkGenerator delegate;
|
|
||||||
|
|
||||||
public BukkitPopulatorWrapper(ChunkGenerator delegate) {
|
|
||||||
this.delegate = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void populate(@NotNull World world, @NotNull Random random, @NotNull Chunk source) {
|
|
||||||
delegate.getGenerationStages().forEach(populator -> {
|
|
||||||
if(populator instanceof Chunkified) {
|
|
||||||
populator.populate(BukkitAdapter.adapt(world), BukkitAdapter.adapt(source));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull LimitedRegion limitedRegion) {
|
|
||||||
super.populate(worldInfo, random, x, z, limitedRegion);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Terra.
|
|
||||||
*
|
|
||||||
* Terra 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.
|
|
||||||
*
|
|
||||||
* Terra 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 Terra. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.bukkit.population;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
|
||||||
import com.dfsek.terra.bukkit.world.BukkitWorld;
|
|
||||||
|
|
||||||
|
|
||||||
public class ChunkCoordinate implements Serializable {
|
|
||||||
public static final long serialVersionUID = 7102462856296750285L;
|
|
||||||
private final int x;
|
|
||||||
private final int z;
|
|
||||||
private final UUID worldID;
|
|
||||||
|
|
||||||
public ChunkCoordinate(int x, int z, UUID worldID) {
|
|
||||||
this.x = x;
|
|
||||||
this.z = z;
|
|
||||||
this.worldID = worldID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ChunkCoordinate(Chunk c) {
|
|
||||||
this.x = c.getX();
|
|
||||||
this.z = c.getZ();
|
|
||||||
this.worldID = ((BukkitWorld) c.getWorld()).getUID();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UUID getWorldID() {
|
|
||||||
return worldID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getX() {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getZ() {
|
|
||||||
return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return x * 31 + z;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if(!(obj instanceof ChunkCoordinate other)) return false;
|
|
||||||
return other.getX() == x && other.getZ() == z;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Terra.
|
|
||||||
*
|
|
||||||
* Terra 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.
|
|
||||||
*
|
|
||||||
* Terra 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 Terra. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.bukkit.population;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
|
||||||
|
|
||||||
import org.bukkit.generator.BlockPopulator;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import com.dfsek.terra.api.Platform;
|
|
||||||
import com.dfsek.terra.api.profiler.ProfileFrame;
|
|
||||||
import com.dfsek.terra.api.world.access.World;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
|
|
||||||
import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified;
|
|
||||||
import com.dfsek.terra.bukkit.PlatformImpl;
|
|
||||||
import com.dfsek.terra.bukkit.world.BukkitAdapter;
|
|
||||||
import com.dfsek.terra.bukkit.world.BukkitWorld;
|
|
||||||
import com.dfsek.terra.util.FastRandom;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cursed management class for the horrors of Bukkit population
|
|
||||||
*/
|
|
||||||
public class PopulationManager extends BlockPopulator {
|
|
||||||
private final ChunkGenerator generator;
|
|
||||||
private final HashSet<ChunkCoordinate> needsPop = new HashSet<>();
|
|
||||||
private final Platform platform;
|
|
||||||
|
|
||||||
public PopulationManager(ChunkGenerator generator, Platform platform) {
|
|
||||||
this.generator = generator;
|
|
||||||
this.platform = platform;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File getDataFolder(World w) {
|
|
||||||
File f = new File(((BukkitWorld) w).getWorldFolder(), "gaea");
|
|
||||||
f.mkdirs();
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public synchronized void saveBlocks(World w) throws IOException {
|
|
||||||
File f = new File(getDataFolder(w), "chunks.bin");
|
|
||||||
f.createNewFile();
|
|
||||||
SerializationUtil.toFile((HashSet<ChunkCoordinate>) needsPop.clone(), f);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public synchronized void loadBlocks(World w) throws IOException, ClassNotFoundException {
|
|
||||||
File f = new File(getDataFolder(w), "chunks.bin");
|
|
||||||
needsPop.addAll((HashSet<ChunkCoordinate>) SerializationUtil.fromFile(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synchronize to prevent chunks from being queued for population multiple times.
|
|
||||||
public synchronized void checkNeighbors(int x, int z, World world) {
|
|
||||||
BukkitWorld w = (BukkitWorld) world;
|
|
||||||
ChunkCoordinate c = new ChunkCoordinate(x, z, (w).getUID());
|
|
||||||
if(w.isChunkGenerated(x + 1, z)
|
|
||||||
&& w.isChunkGenerated(x - 1, z)
|
|
||||||
&& w.isChunkGenerated(x, z + 1)
|
|
||||||
&& w.isChunkGenerated(x, z - 1) && needsPop.contains(c)) {
|
|
||||||
Random random = new FastRandom(w.getSeed());
|
|
||||||
long xRand = (random.nextLong() / 2L << 1L) + 1L;
|
|
||||||
long zRand = (random.nextLong() / 2L << 1L) + 1L;
|
|
||||||
random.setSeed((long) x * xRand + (long) z * zRand ^ w.getSeed());
|
|
||||||
Chunk currentChunk = w.getChunkAt(x, z);
|
|
||||||
generator.getGenerationStages().forEach(populator -> {
|
|
||||||
if(!(populator instanceof Chunkified)) {
|
|
||||||
populator.populate(w, currentChunk);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
needsPop.remove(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("try")
|
|
||||||
public void populate(org.bukkit.@NotNull World world, @NotNull Random random, org.bukkit.@NotNull Chunk source) {
|
|
||||||
try(ProfileFrame ignore = platform.getProfiler().profile("popman")) {
|
|
||||||
Chunk chunk = BukkitAdapter.adapt(source);
|
|
||||||
needsPop.add(new ChunkCoordinate(chunk));
|
|
||||||
int x = chunk.getX();
|
|
||||||
int z = chunk.getZ();
|
|
||||||
if(((PlatformImpl) platform).getPlugin().isEnabled()) {
|
|
||||||
for(int xi = -1; xi <= 1; xi++) {
|
|
||||||
for(int zi = -1; zi <= 1; zi++) {
|
|
||||||
if(xi == 0 && zi == 0) continue;
|
|
||||||
if(world.isChunkGenerated(xi + x, zi + z)) checkNeighbors(xi + x, zi + z, BukkitAdapter.adapt(world));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Terra.
|
|
||||||
*
|
|
||||||
* Terra 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.
|
|
||||||
*
|
|
||||||
* Terra 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 Terra. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.dfsek.terra.bukkit.population;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.ObjectStreamClass;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
|
|
||||||
public final class SerializationUtil {
|
|
||||||
public static Object fromFile(File f) throws IOException, ClassNotFoundException {
|
|
||||||
ObjectInputStream ois = new MovedObjectInputStream(new FileInputStream(f), "com.dfsek.terra.api.world.generation.population",
|
|
||||||
"com.dfsek.terra.bukkit.population"); // Backwards compat with old Gaea location
|
|
||||||
Object o = ois.readObject();
|
|
||||||
ois.close();
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void toFile(Serializable o, File f) throws IOException {
|
|
||||||
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f));
|
|
||||||
oos.writeObject(o);
|
|
||||||
oos.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class MovedObjectInputStream extends ObjectInputStream {
|
|
||||||
private final String oldNameSpace;
|
|
||||||
private final String newNameSpace;
|
|
||||||
|
|
||||||
public MovedObjectInputStream(InputStream in, String oldNameSpace, String newNameSpace) throws IOException {
|
|
||||||
super(in);
|
|
||||||
this.oldNameSpace = oldNameSpace;
|
|
||||||
this.newNameSpace = newNameSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
|
|
||||||
if(desc.getName().contains(oldNameSpace)) {
|
|
||||||
String newClassName = desc.getName().replace(oldNameSpace, newNameSpace);
|
|
||||||
return Class.forName(newClassName);
|
|
||||||
}
|
|
||||||
return super.resolveClass(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
|
|
||||||
ObjectStreamClass result = super.readClassDescriptor();
|
|
||||||
try {
|
|
||||||
if(result.getName().contains(oldNameSpace)) {
|
|
||||||
String newClassName = result.getName().replace(oldNameSpace, newNameSpace);
|
|
||||||
Class<?> localClass = Class.forName(newClassName);
|
|
||||||
|
|
||||||
Field nameField = ObjectStreamClass.class.getDeclaredField("name");
|
|
||||||
nameField.setAccessible(true);
|
|
||||||
nameField.set(result, newClassName);
|
|
||||||
|
|
||||||
ObjectStreamClass localClassDescriptor = ObjectStreamClass.lookup(localClass);
|
|
||||||
Field suidField = ObjectStreamClass.class.getDeclaredField("suid");
|
|
||||||
suidField.setAccessible(true);
|
|
||||||
suidField.set(result, localClassDescriptor.getSerialVersionUID());
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
throw new IOException("Exception when trying to replace namespace", e);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -194,10 +194,10 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
|
|||||||
public CompletableFuture<Chunk> populateNoise(Executor executor, Blender arg, StructureAccessor structureAccessor, Chunk chunk) {
|
public CompletableFuture<Chunk> populateNoise(Executor executor, Blender arg, StructureAccessor structureAccessor, Chunk chunk) {
|
||||||
return CompletableFuture.supplyAsync(() -> {
|
return CompletableFuture.supplyAsync(() -> {
|
||||||
World world = (World) ((StructureAccessorAccessor) structureAccessor).getWorld();
|
World world = (World) ((StructureAccessorAccessor) structureAccessor).getWorld();
|
||||||
delegate.generateChunkData((ProtoChunk) chunk, (ProtoWorld) world, chunk.getPos().z, chunk.getPos().x);
|
delegate.generateChunkData((ProtoChunk) chunk, world, chunk.getPos().z, chunk.getPos().x);
|
||||||
delegate.getGenerationStages().forEach(populator -> {
|
delegate.getGenerationStages().forEach(populator -> {
|
||||||
if(populator instanceof Chunkified) {
|
if(populator instanceof Chunkified) {
|
||||||
populator.populate(world, (com.dfsek.terra.api.world.chunk.Chunk) world);
|
populator.populate((ProtoWorld) world);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return chunk;
|
return chunk;
|
||||||
@ -208,7 +208,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C
|
|||||||
public void generateFeatures(StructureWorldAccess world, Chunk chunk, StructureAccessor structureAccessor) {
|
public void generateFeatures(StructureWorldAccess world, Chunk chunk, StructureAccessor structureAccessor) {
|
||||||
delegate.getGenerationStages().forEach(populator -> {
|
delegate.getGenerationStages().forEach(populator -> {
|
||||||
if(!(populator instanceof Chunkified)) {
|
if(!(populator instanceof Chunkified)) {
|
||||||
populator.populate((World) world, (com.dfsek.terra.api.world.chunk.Chunk) world);
|
populator.populate((ProtoWorld) world);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if(pack.vanillaFlora()) {
|
if(pack.vanillaFlora()) {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
package com.dfsek.terra.fabric.mixin.implementations.world;
|
package com.dfsek.terra.fabric.mixin.implementations.world;
|
||||||
|
|
||||||
import com.dfsek.terra.api.world.chunk.Chunk;
|
import com.dfsek.terra.api.world.chunk.generation.ProtoWorld;
|
||||||
|
|
||||||
import net.minecraft.block.FluidBlock;
|
import net.minecraft.block.FluidBlock;
|
||||||
import net.minecraft.fluid.Fluid;
|
import net.minecraft.fluid.Fluid;
|
||||||
@ -26,6 +26,7 @@ import net.minecraft.util.math.BlockPos;
|
|||||||
import net.minecraft.world.ChunkRegion;
|
import net.minecraft.world.ChunkRegion;
|
||||||
import net.minecraft.world.ServerWorldAccess;
|
import net.minecraft.world.ServerWorldAccess;
|
||||||
import net.minecraft.world.WorldAccess;
|
import net.minecraft.world.WorldAccess;
|
||||||
|
import net.minecraft.world.chunk.Chunk;
|
||||||
import net.minecraft.world.chunk.ChunkStatus;
|
import net.minecraft.world.chunk.ChunkStatus;
|
||||||
import net.minecraft.world.tick.OrderedTick;
|
import net.minecraft.world.tick.OrderedTick;
|
||||||
import net.minecraft.world.tick.QueryableTickScheduler;
|
import net.minecraft.world.tick.QueryableTickScheduler;
|
||||||
@ -57,7 +58,7 @@ import com.dfsek.terra.fabric.util.FabricUtil;
|
|||||||
|
|
||||||
|
|
||||||
@Mixin(ChunkRegion.class)
|
@Mixin(ChunkRegion.class)
|
||||||
@Implements(@Interface(iface = World.class, prefix = "terraWorld$", remap = Interface.Remap.NONE))
|
@Implements(@Interface(iface = ProtoWorld.class, prefix = "terraWorld$", remap = Interface.Remap.NONE))
|
||||||
public abstract class ChunkRegionMixin {
|
public abstract class ChunkRegionMixin {
|
||||||
private WorldConfig config;
|
private WorldConfig config;
|
||||||
|
|
||||||
@ -72,6 +73,10 @@ public abstract class ChunkRegionMixin {
|
|||||||
@Shadow
|
@Shadow
|
||||||
public abstract QueryableTickScheduler<Fluid> getFluidTickScheduler();
|
public abstract QueryableTickScheduler<Fluid> getFluidTickScheduler();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private Chunk centerPos;
|
||||||
|
|
||||||
@Inject(at = @At("RETURN"),
|
@Inject(at = @At("RETURN"),
|
||||||
method = "<init>(Lnet/minecraft/server/world/ServerWorld;Ljava/util/List;Lnet/minecraft/world/chunk/ChunkStatus;I)V")
|
method = "<init>(Lnet/minecraft/server/world/ServerWorld;Ljava/util/List;Lnet/minecraft/world/chunk/ChunkStatus;I)V")
|
||||||
public void injectConstructor(ServerWorld world, List<net.minecraft.world.chunk.Chunk> list, ChunkStatus chunkStatus, int i,
|
public void injectConstructor(ServerWorld world, List<net.minecraft.world.chunk.Chunk> list, ChunkStatus chunkStatus, int i,
|
||||||
@ -107,10 +112,6 @@ public abstract class ChunkRegionMixin {
|
|||||||
return (((ChunkRegion) (Object) this).getBottomY()) + ((ChunkRegion) (Object) this).getHeight();
|
return (((ChunkRegion) (Object) this).getBottomY()) + ((ChunkRegion) (Object) this).getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Chunk terraWorld$getChunkAt(int x, int z) {
|
|
||||||
return (Chunk) ((ChunkRegion) (Object) this).getChunk(x, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Intrinsic(displace = true)
|
@Intrinsic(displace = true)
|
||||||
public BlockState terraWorld$getBlockData(int x, int y, int z) {
|
public BlockState terraWorld$getBlockData(int x, int y, int z) {
|
||||||
BlockPos pos = new BlockPos(x, y, z);
|
BlockPos pos = new BlockPos(x, y, z);
|
||||||
@ -137,6 +138,18 @@ public abstract class ChunkRegionMixin {
|
|||||||
.getBiomeSource()).getProvider();
|
.getBiomeSource()).getProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int terra$getCenterChunkX() {
|
||||||
|
return centerPos.getPos().x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int terra$getCenterChunkZ() {
|
||||||
|
return centerPos.getPos().z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public World terra$getWorld() {
|
||||||
|
return (World) world;
|
||||||
|
}
|
||||||
|
|
||||||
public WorldConfig terraWorld$getConfig() {
|
public WorldConfig terraWorld$getConfig() {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user