Skip to content

Commit

Permalink
feat: introduce BiomeData
Browse files Browse the repository at this point in the history
  • Loading branch information
smartcmd committed Dec 21, 2024
1 parent 0a3ea3f commit 3db41db
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 54 deletions.
61 changes: 61 additions & 0 deletions api/src/main/java/org/allaymc/api/world/Dimension.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import org.allaymc.api.math.position.Position3i;
import org.allaymc.api.math.position.Position3ic;
import org.allaymc.api.utils.Utils;
import org.allaymc.api.world.biome.BiomeId;
import org.allaymc.api.world.biome.BiomeType;
import org.allaymc.api.world.service.*;
import org.apache.commons.lang3.function.TriFunction;
import org.cloudburstmc.math.vector.Vector3f;
Expand Down Expand Up @@ -1024,4 +1026,63 @@ default boolean canPosSeeSky(Vector3ic pos) {
default boolean canPosSeeSky(int x, int y, int z) {
return getHeight(x, z) <= y;
}

/**
* Get the biome at the specified pos.
*
* @param pos the pos.
*
* @return biome the biome.
*/
default BiomeType getBiome(Vector3ic pos) {
return getBiome(pos.x(), pos.y(), pos.z());
}

/**
* Get the biome at the specified pos.
*
* @param x the x coordinate of the pos.
* @param y the y coordinate of the pos.
* @param z the z coordinate of the pos.
*
* @return the biome at the specified pos.
*/
default BiomeType getBiome(int x, int y, int z) {
if (y < this.getDimensionInfo().minHeight() || y > getDimensionInfo().maxHeight())
return BiomeId.PLAINS;

var chunk = getChunkService().getChunkByDimensionPos(x, z);
if (chunk == null) {
chunk = getChunkService().getOrLoadChunkSync(x >> 4, z >> 4);
}

return chunk.getBiome(x & 15, y, z & 15);
}

/**
* Set the biome at the specified pos.
*
* @param pos the pos.
* @param biome the biome to set.
*/
default void setBiome(Vector3ic pos, BiomeType biome) {
setBiome(pos.x(), pos.y(), pos.z(), biome);
}

/**
* Set the biome at the specified pos.
*
* @param x the x coordinate of the pos.
* @param y the y coordinate of the pos.
* @param z the z coordinate of the pos.
* @param biome the biome to set.
*/
default void setBiome(int x, int y, int z, BiomeType biome) {
var chunk = getChunkService().getChunkByDimensionPos(x, z);
if (chunk == null) {
chunk = getChunkService().getOrLoadChunkSync(x >> 4, z >> 4);
}

chunk.setBiome(x & 15, y, z & 15, biome);
}
}
29 changes: 0 additions & 29 deletions api/src/main/java/org/allaymc/api/world/biome/BiomeData.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static void generate() {
.build()
)
.addField(FieldSpec
.builder(ClassNames.BIOME_ARRAY, "MAP1", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
.builder(ClassNames.BIOME_ID_ARRAY, "MAP1", Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
.build())
.addField(FieldSpec
.builder(ParameterizedTypeName.get(ClassNames.HASH_MAP, ClassNames.API_IDENTIFIER, ClassNames.BIOME_TYPE), "MAP2", Modifier.PRIVATE, Modifier.FINAL, Modifier.STATIC)
Expand Down
3 changes: 2 additions & 1 deletion codegen/src/main/java/org/allaymc/codegen/ClassNames.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ public interface ClassNames {
ClassName MATERIAL_TYPE = ClassName.get("org.allaymc.api.block.material", "MaterialType");

ClassName BIOME_TYPE = ClassName.get("org.allaymc.api.world.biome", "BiomeType");
ClassName BIOME_ARRAY = ClassName.get("org.allaymc.api.world.biome", "BiomeId[]");
ClassName BIOME_ID = ClassName.get("org.allaymc.api.world.biome", "BiomeId");
ClassName BIOME_ID_ARRAY = ClassName.get("org.allaymc.api.world.biome", "BiomeId[]");

ClassName ENTITY = ClassName.get("org.allaymc.api.entity", "Entity");
ClassName ENTITY_IMPL = ClassName.get("org.allaymc.server.entity.impl", "EntityImpl");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.allaymc.api.utils.Utils;
import org.allaymc.api.world.Weather;
import org.allaymc.api.world.gamerule.GameRule;
import org.allaymc.server.world.biome.BiomeData;
import org.joml.Vector3i;

import java.util.Set;
Expand Down Expand Up @@ -124,16 +125,18 @@ public void onScheduledUpdate(BlockStateWithPos blockStateWithPos) {
}
}

// TODO: decrease the value of base if the rainfall values are high
var base = 0;
trySpreadFireOn(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.EAST), 300 + base, age);
trySpreadFireOn(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.WEST), 300 + base, age);
trySpreadFireOn(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.DOWN), 250 + base, age);
trySpreadFireOn(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.UP), 250 + base, age);
trySpreadFireOn(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.SOUTH), 300 + base, age);
trySpreadFireOn(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.NORTH), 300 + base, age);
burnBlockAround(blockStateWithPos, age);
spreadFire(blockStateWithPos);
}

private void burnBlockAround(BlockStateWithPos blockStateWithPos, Integer age) {
// TODO: INCREASED_FIRE_BURNOUT
for (var face : BlockFace.getHorizontalBlockFaces()) {
burnBlock(blockStateWithPos, blockStateWithPos.offsetPos(face), 300, age);
}

trySpreadFire(blockStateWithPos);
burnBlock(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.UP), 250, age);
burnBlock(blockStateWithPos, blockStateWithPos.offsetPos(BlockFace.DOWN), 250, age);
}

protected boolean tryConvertToSoulFire(BlockStateWithPos blockStateWithPos) {
Expand All @@ -149,7 +152,7 @@ protected boolean tryConvertToSoulFire(BlockStateWithPos blockStateWithPos) {
return false;
}

protected void trySpreadFire(BlockStateWithPos source) {
protected void spreadFire(BlockStateWithPos source) {
var random = ThreadLocalRandom.current();
var pos = source.pos();
var x = pos.x();
Expand All @@ -176,10 +179,12 @@ protected void trySpreadFire(BlockStateWithPos source) {
if (ly > y + 1) {
k += (ly - (y + 1)) * 100;
}
// TODO: decrease the value of t if the rainfall values are high
var t = (flameOdds + 40 + dimension.getWorld().getWorldData().getDifficulty().ordinal() * 7) / (age + 30);
var maxChance = (flameOdds + 40 + dimension.getWorld().getWorldData().getDifficulty().ordinal() * 7) / (age + 30);
if (BiomeData.getBiomeData(dimension.getBiome(lx, ly, lz)).isHumid()) {
maxChance /= 2;
}

if (t > 0 && random.nextInt(k) <= t) {
if (maxChance > 0 && random.nextInt(k) <= maxChance) {
var newAge = Math.min(age + (random.nextInt(5) >> 2), 15);
var localBlockStateWithPos = new BlockStateWithPos(localBlockState, new Position3i(lx, ly, lz, dimension), 0);
var event = new BlockIgniteEvent(localBlockStateWithPos, source, null, BlockIgniteEvent.BlockIgniteCause.SPREAD);
Expand All @@ -194,7 +199,7 @@ protected void trySpreadFire(BlockStateWithPos source) {
}
}

protected void trySpreadFireOn(BlockStateWithPos source, BlockStateWithPos target, int bound, int sourceFireAge) {
protected void burnBlock(BlockStateWithPos source, BlockStateWithPos target, int bound, int sourceFireAge) {
var targetBlockState = target.blockState();
var dimension = source.dimension();
var random = ThreadLocalRandom.current();
Expand Down Expand Up @@ -261,12 +266,9 @@ protected static int getMaxFlameOddsOfNeighborsEncouragingFire(BlockStateWithPos
return 0;
} else {
int flameOdds = 0;
flameOdds = Math.max(flameOdds, blockStateWithPos.offsetPos(BlockFace.EAST).blockState().getBlockStateData().flameOdds());
flameOdds = Math.max(flameOdds, blockStateWithPos.offsetPos(BlockFace.WEST).blockState().getBlockStateData().flameOdds());
flameOdds = Math.max(flameOdds, blockStateWithPos.offsetPos(BlockFace.DOWN).blockState().getBlockStateData().flameOdds());
flameOdds = Math.max(flameOdds, blockStateWithPos.offsetPos(BlockFace.UP).blockState().getBlockStateData().flameOdds());
flameOdds = Math.max(flameOdds, blockStateWithPos.offsetPos(BlockFace.SOUTH).blockState().getBlockStateData().flameOdds());
flameOdds = Math.max(flameOdds, blockStateWithPos.offsetPos(BlockFace.NORTH).blockState().getBlockStateData().flameOdds());
for (var face : BlockFace.values()) {
flameOdds = Math.max(flameOdds, blockStateWithPos.offsetPos(face).blockState().getBlockStateData().flameOdds());
}
return flameOdds;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ protected void onLoad(Map<String, PluginDescriptor> descriptors, Map<String, Plu
pluginContainer = loader.loadPlugin();
pluginContainer.plugin().onLoad();
} catch (Throwable t) {
log.error(I18n.get().tr(TrKeys.A_PLUGIN_LOAD_ERROR, descriptor.getName(), t.getMessage()), t);
log.error(I18n.get().tr(TrKeys.A_PLUGIN_LOAD_ERROR, descriptor.getName(), t.getMessage() != null ? t.getMessage() : ""), t);
continue;
}

Expand All @@ -134,7 +134,7 @@ protected void checkCircularDependencies(Map<String, ? extends PluginDescriptor>
try {
dag.setBefore(name, descriptor.getName());//set ref
} catch (DAGCycleException e) {
log.error(I18n.get().tr(TrKeys.A_PLUGIN_DEPENDENCY_CIRCULAR, descriptor.getName(), e.getMessage()));
log.error(I18n.get().tr(TrKeys.A_PLUGIN_DEPENDENCY_CIRCULAR, descriptor.getName(), e.getMessage() != null ? e.getMessage() : ""));
dag.remove(descriptor.getName());
}
}
Expand Down Expand Up @@ -170,7 +170,7 @@ public void enablePlugins() {
var plugin = pluginContainer.plugin();
plugin.onEnable();
} catch (Throwable t) {
log.error(I18n.get().tr(TrKeys.A_PLUGIN_ENABLE_ERROR, pluginContainer.descriptor().getName(), t.getMessage()), t);
log.error(I18n.get().tr(TrKeys.A_PLUGIN_ENABLE_ERROR, pluginContainer.descriptor().getName(), t.getMessage() != null ? t.getMessage() : ""), t);
continue;
}

Expand Down
78 changes: 78 additions & 0 deletions server/src/main/java/org/allaymc/server/world/biome/BiomeData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.allaymc.server.world.biome;

import org.allaymc.api.annotation.MinecraftVersionSensitive;
import org.allaymc.api.utils.Identifier;
import org.allaymc.api.utils.Utils;
import org.allaymc.api.world.biome.BiomeId;
import org.allaymc.api.world.biome.BiomeType;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.nbt.NbtUtils;

import java.util.EnumMap;
import java.util.List;

/**
* BiomeData represents the data of a biome.
*/
@MinecraftVersionSensitive
public record BiomeData(
float ash,
float blue_spores,
float depth,
float downfall,
float height,
boolean rain,
float red_spores,
List<String> tags,
float temperature,
float waterColorA,
float waterColorB,
float waterColorG,
float waterColorR,
float white_ash
) {
private static final EnumMap<BiomeId, BiomeData> BIOME_DATA = new EnumMap(BiomeId.class);

static {
try (var stream = Utils.getResource("biome_definitions.nbt")) {
var tag = (NbtMap) NbtUtils.createNetworkReader(stream).readTag();
tag.forEach((key, value) -> {
BIOME_DATA.put((BiomeId) BiomeId.fromIdentifier(new Identifier("minecraft", key)), fromNBT((NbtMap) value));
});
} catch (Exception e) {
throw new AssertionError("Failed to load biome_definitions.nbt", e);
}
}

public boolean isHumid() {
return downfall >= 0.85;
}

public static BiomeData getBiomeData(BiomeId biomeId) {
return BIOME_DATA.get(biomeId);
}

public static BiomeData getBiomeData(BiomeType biomeType) {
return getBiomeData((BiomeId) biomeType);
}

private static BiomeData fromNBT(NbtMap nbt) {
return new BiomeData(
nbt.getFloat("ash"),
nbt.getFloat("blue_spores"),
nbt.getFloat("depth"),
nbt.getFloat("downfall"),
nbt.getFloat("height"),
nbt.getBoolean("rain"),
nbt.getFloat("red_spores"),
nbt.getList("tags", NbtType.STRING),
nbt.getFloat("temperature"),
nbt.getFloat("waterColorA"),
nbt.getFloat("waterColorB"),
nbt.getFloat("waterColorG"),
nbt.getFloat("waterColorR"),
nbt.getFloat("white_ash")
);
}
}

0 comments on commit 3db41db

Please sign in to comment.