Skip to content

Commit

Permalink
Add support for Bedrock flat world generator options
Browse files Browse the repository at this point in the history
  • Loading branch information
wode490390 committed Feb 26, 2024
1 parent ec624ba commit 157ccd6
Show file tree
Hide file tree
Showing 17 changed files with 439 additions and 189 deletions.
24 changes: 10 additions & 14 deletions src/main/java/cn/nukkit/level/Level.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
Expand Down Expand Up @@ -299,10 +298,7 @@ public Generator initialValue() {
try {
Generator generator = generatorClass.getConstructor(Map.class).newInstance(provider.getGeneratorOptions());
NukkitRandom rand = new NukkitRandom(getSeed());
// if (Server.getInstance().isPrimaryThread()) {
// generator.init(Level.this, rand);
// }
generator.init(new PopChunkManager(getSeed(), getHeightRange()), rand);
generator.init(new PopChunkManager(getSeed(), getHeightRange()), rand, provider.getWorldGeneratorOptions());
return generator;
} catch (Throwable e) {
Server.getInstance().getLogger().logException(e);
Expand Down Expand Up @@ -4094,14 +4090,14 @@ public Position getSafeSpawn(Vector3 spawn) {
}

if (spawn != null) {
Vector3 v = spawn.floor();
FullChunk chunk = this.getChunk((int) v.x >> 4, (int) v.z >> 4, false);
int x = (int) v.x & 0x0f;
int z = (int) v.z & 0x0f;
BlockVector3 v = spawn.asBlockVector3();
FullChunk chunk = this.getChunk(v.getChunkX(), v.getChunkZ(), false);
int x = v.x & 0x0f;
int z = v.z & 0x0f;
if (chunk != null && chunk.isGenerated()) {
int y = (int) Math.max(Math.min(heightRange.getMaxY() - 1 - 1, v.y), heightRange.getMinY() + 1);
boolean wasAir = chunk.getBlockId(0, x, y - 1, z) == Block.AIR;
for (; y > 0; --y) {
int y = Mth.clamp(Math.min(chunk.getHighestBlockAt(x, z), v.y), heightRange.getMinY() + 1, heightRange.getMaxY() - 1);
boolean wasAir = chunk.getBlockId(0, x, y + 1, z) == Block.AIR;
for (; y > heightRange.getMinY(); --y) {
int b = chunk.getFullBlock(0, x, y, z);
Block block = Block.fromFullId(b);
if (this.isFullBlock(block)) {
Expand All @@ -4114,14 +4110,14 @@ public Position getSafeSpawn(Vector3 spawn) {
}
}

for (; y >= heightRange.getMinY() && y < heightRange.getMaxY() - 1; y++) {
for (; y >= heightRange.getMinY() && y <= heightRange.getMaxY(); y++) {
int b = chunk.getFullBlock(0, x, y + 1, z);
Block block = Block.fromFullId(b);
if (!this.isFullBlock(block)) {
b = chunk.getFullBlock(0, x, y, z);
block = Block.fromFullId(b);
if (!this.isFullBlock(block)) {
return new Position(spawn.x, y == (int) spawn.y ? spawn.y : y, spawn.z, this);
return new Position(spawn.x, y, spawn.z, this);
}
} else {
++y;
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/cn/nukkit/level/biome/Biome.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ public boolean canSnow() {
return false;
}

public static int getIdByName(String name) {
return nameToId.getInt(name);
}

@Nullable
public static String getNameById(int id) {
return idToName[id];
Expand Down
18 changes: 13 additions & 5 deletions src/main/java/cn/nukkit/level/format/FullChunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ default boolean setBlock(int layer, int x, int y, int z, int blockId) {

void setBlockLight(int x, int y, int z, int level);

int getHighestBlockAt(int x, int z);
default int getHighestBlockAt(int x, int z) {
return getHighestBlockAt(x, z, true);
}

int getHighestBlockAt(int x, int z, boolean cache);

Expand Down Expand Up @@ -148,15 +150,21 @@ default void fillBiome(int biomeId) {

boolean isLoaded();

boolean load() throws IOException;
default boolean load() throws IOException {
return load(true);
}

boolean load(boolean generate) throws IOException;

boolean unload() throws Exception;
default boolean unload() {
return unload(true);
}

boolean unload(boolean save) throws Exception;
default boolean unload(boolean save) {
return unload(save, true);
}

boolean unload(boolean save, boolean safe) throws Exception;
boolean unload(boolean save, boolean safe);

void initChunk();

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/cn/nukkit/level/format/LevelProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import cn.nukkit.level.format.LevelProviderManager.LevelProviderHandle;
import cn.nukkit.level.format.generic.BaseFullChunk;
import cn.nukkit.level.generator.Generator;
import cn.nukkit.level.generator.GeneratorOptions;
import cn.nukkit.math.Vector3;
import cn.nukkit.scheduler.AsyncTask;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
Expand Down Expand Up @@ -136,4 +137,6 @@ default void forEachChunks(Function<FullChunk, Boolean> action) {
void setSaveChunksOnClose(boolean save);

HeightRange getHeightRange();

GeneratorOptions getWorldGeneratorOptions();
}
10 changes: 10 additions & 0 deletions src/main/java/cn/nukkit/level/format/anvil/Anvil.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import cn.nukkit.level.format.generic.BaseLevelProvider;
import cn.nukkit.level.format.generic.BaseRegionLoader;
import cn.nukkit.level.format.generic.ChunkRequestTask;
import cn.nukkit.level.generator.FlatGeneratorOptions;
import cn.nukkit.level.generator.GeneratorOptions;
import cn.nukkit.level.generator.Generators;
import cn.nukkit.nbt.NBTIO;
import cn.nukkit.nbt.tag.CompoundTag;
Expand Down Expand Up @@ -37,6 +39,9 @@ public class Anvil extends BaseLevelProvider {
public static final Pattern ANVIL_REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");

static final HeightRange DEFAULT_HEIGHT_RANGE = HeightRange.blockY(0, 256);
private static final GeneratorOptions GENERATOR_OPTIONS = GeneratorOptions.builder()
.flatOptions(FlatGeneratorOptions.LEGACY)
.build();

public Anvil(Level level, String path) throws IOException {
super(level, path);
Expand Down Expand Up @@ -310,4 +315,9 @@ public void forEachChunks(Function<FullChunk, Boolean> action, boolean skipCorru
public HeightRange getHeightRange() {
return DEFAULT_HEIGHT_RANGE;
}

@Override
public GeneratorOptions getWorldGeneratorOptions() {
return GENERATOR_OPTIONS;
}
}
20 changes: 0 additions & 20 deletions src/main/java/cn/nukkit/level/format/generic/BaseFullChunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,6 @@ public void populateSkyLight() {
}
}

@Override
public int getHighestBlockAt(int x, int z) {
return this.getHighestBlockAt(x, z, true);
}

@Override
public int getHighestBlockAt(int x, int z, boolean cache) {
if (cache) {
Expand Down Expand Up @@ -404,26 +399,11 @@ public boolean isLoaded() {
return this.getProvider() != null && this.getProvider().isChunkLoaded(this.getX(), this.getZ());
}

@Override
public boolean load() throws IOException {
return this.load(true);
}

@Override
public boolean load(boolean generate) throws IOException {
return this.getProvider() != null && this.getProvider().getChunk(this.getX(), this.getZ(), true) != null;
}

@Override
public boolean unload() {
return this.unload(true, true);
}

@Override
public boolean unload(boolean save) {
return this.unload(save, true);
}

@Override
public boolean unload(boolean save, boolean safe) {
LevelProvider level = this.getProvider();
Expand Down
30 changes: 29 additions & 1 deletion src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
import cn.nukkit.level.format.anvil.util.NibbleArray;
import cn.nukkit.level.format.generic.BaseFullChunk;
import cn.nukkit.level.format.generic.ChunkRequestTask;
import cn.nukkit.level.generator.FlatGeneratorOptions;
import cn.nukkit.level.generator.Generator;
import cn.nukkit.level.generator.GeneratorOptions;
import cn.nukkit.level.generator.Generators;
import cn.nukkit.level.util.PalettedSubChunkStorage;
import cn.nukkit.math.BlockVector3;
Expand Down Expand Up @@ -88,6 +90,7 @@ public class LevelDB implements LevelProvider {
protected final String path;

protected final CompoundTag levelData;
private GeneratorOptions generatorOptions;

protected volatile boolean closed;
protected final Lock gcLock;
Expand Down Expand Up @@ -260,7 +263,7 @@ public static void updateLevelData(CompoundTag levelData) {
levelData.putByteIfAbsent("isCreatedInEditor", 0);
levelData.putByteIfAbsent("isExportedFromEditor", 0);
levelData.putStringIfAbsent("BiomeOverride", "");
levelData.putStringIfAbsent("FlatWorldLayers", DEFAULT_FLAT_WORLD_LAYERS);
levelData.putStringIfAbsent("FlatWorldLayers", FlatGeneratorOptions.DEFAULT_FLAT_WORLD_LAYERS);
levelData.putCompoundIfAbsent("world_policies", new CompoundTag());
levelData.putCompoundIfAbsent("experiments", new CompoundTag()
.putByte("experiments_ever_used", 0)
Expand Down Expand Up @@ -1256,6 +1259,7 @@ public CompoundTag getLevelData() {
return levelData;
}

@Override
public void updateLevelName(String name) {
if (!this.getName().equals(name)) {
this.levelData.putString("LevelName", name);
Expand Down Expand Up @@ -1428,6 +1432,30 @@ public HeightRange getHeightRange() {
return DEFAULT_HEIGHT_RANGE;
}

@Override
public GeneratorOptions getWorldGeneratorOptions() {
GeneratorOptions options = this.generatorOptions;
if (options == null) {
String biomeOverride = levelData.getString("BiomeOverride");
int biome;
if (biomeOverride.isEmpty()) {
biome = -1;
} else {
biome = Biome.getIdByName(biomeOverride);
if (biome != -1 && !Biome.isValidBiome(biome)) {
biome = -1;
}
}
options = GeneratorOptions.builder()
.flatOptions(FlatGeneratorOptions.load(levelData.getString("FlatWorldLayers", FlatGeneratorOptions.DEFAULT_FLAT_WORLD_LAYERS)))
.bonusChest(levelData.getBoolean("bonusChestEnabled"))
.biomeOverride(biome)
.build();
this.generatorOptions = options;
}
return options;
}

class AutoCompactionTask extends AsyncTask<Void> {
@Override
public void onRun() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ public final class LevelDbConstants {
new IntTag("", 0), // revision
new IntTag("", 0))); // beta

public static final String DEFAULT_FLAT_WORLD_LAYERS = "{\"biome_id\":1,\"block_layers\":[{\"block_name\":\"minecraft:bedrock\",\"count\":1},{\"block_name\":\"minecraft:dirt\",\"count\":2},{\"block_name\":\"minecraft:grass\",\"count\":1}],\"encoding_version\":6,\"structure_options\":null,\"world_version\":\"version.post_1_18\"}";

private LevelDbConstants() {
throw new IllegalStateException();
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/cn/nukkit/level/format/mcregion/McRegion.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import cn.nukkit.level.format.generic.BaseFullChunk;
import cn.nukkit.level.format.generic.BaseLevelProvider;
import cn.nukkit.level.format.generic.BaseRegionLoader;
import cn.nukkit.level.generator.FlatGeneratorOptions;
import cn.nukkit.level.generator.GeneratorOptions;
import cn.nukkit.level.generator.Generators;
import cn.nukkit.nbt.NBTIO;
import cn.nukkit.nbt.tag.CompoundTag;
Expand All @@ -34,6 +36,9 @@ public class McRegion extends BaseLevelProvider {
private static final Pattern REGION_REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mcr$");

static final HeightRange DEFAULT_HEIGHT_RANGE = HeightRange.blockY(0, 128);
private static final GeneratorOptions GENERATOR_OPTIONS = GeneratorOptions.builder()
.flatOptions(FlatGeneratorOptions.LEGACY)
.build();

public McRegion(Level level, String path) throws IOException {
super(level, path);
Expand Down Expand Up @@ -267,4 +272,9 @@ public void forEachChunks(Function<FullChunk, Boolean> action, boolean skipCorru
public HeightRange getHeightRange() {
return DEFAULT_HEIGHT_RANGE;
}

@Override
public GeneratorOptions getWorldGeneratorOptions() {
return GENERATOR_OPTIONS;
}
}
3 changes: 1 addition & 2 deletions src/main/java/cn/nukkit/level/generator/End.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import cn.nukkit.level.Level;
import cn.nukkit.level.biome.BiomeID;
import cn.nukkit.level.format.generic.BaseFullChunk;
import cn.nukkit.level.generator.populator.type.Populator;
import cn.nukkit.math.NukkitRandom;
import cn.nukkit.math.Vector3;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
Expand Down Expand Up @@ -55,7 +54,7 @@ public Vector3 getSpawn() {
}

@Override
public void init(ChunkManager level, NukkitRandom random) {
public void init(ChunkManager level, NukkitRandom random, GeneratorOptions generatorOptions) {
this.level = level;
}

Expand Down
Loading

0 comments on commit 157ccd6

Please sign in to comment.