From 3db41db5511eae60b316109c19d00d9070d08897 Mon Sep 17 00:00:00 2001 From: daoge_cmd <3523206925@qq.com> Date: Sat, 21 Dec 2024 20:56:02 +0800 Subject: [PATCH] feat: introduce BiomeData --- .../java/org/allaymc/api/world/Dimension.java | 61 +++++++++++++++ .../allaymc/api/world/biome/BiomeData.java | 29 ------- .../org/allaymc/codegen/BiomeIdEnumGen.java | 2 +- .../java/org/allaymc/codegen/ClassNames.java | 3 +- .../component/BlockFireBaseComponentImpl.java | 42 +++++----- .../server/plugin/AllayPluginManager.java | 6 +- .../allaymc/server/world/biome/BiomeData.java | 78 +++++++++++++++++++ 7 files changed, 167 insertions(+), 54 deletions(-) delete mode 100644 api/src/main/java/org/allaymc/api/world/biome/BiomeData.java create mode 100644 server/src/main/java/org/allaymc/server/world/biome/BiomeData.java diff --git a/api/src/main/java/org/allaymc/api/world/Dimension.java b/api/src/main/java/org/allaymc/api/world/Dimension.java index 3ca58ce3dc..fb2bfd0c77 100644 --- a/api/src/main/java/org/allaymc/api/world/Dimension.java +++ b/api/src/main/java/org/allaymc/api/world/Dimension.java @@ -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; @@ -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); + } } diff --git a/api/src/main/java/org/allaymc/api/world/biome/BiomeData.java b/api/src/main/java/org/allaymc/api/world/biome/BiomeData.java deleted file mode 100644 index 0a28c91579..0000000000 --- a/api/src/main/java/org/allaymc/api/world/biome/BiomeData.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.allaymc.api.world.biome; - -import org.cloudburstmc.nbt.NbtList; -import org.cloudburstmc.nbt.annotation.NBT; - -/** - * This record is used for custom biome - * Which is not implemented - */ -@NBT -public record BiomeData( - float ash, - float blue_spores, - float depth, - float downfall, - float height, - String name_hash, - byte rain, - float red_spores, - NbtList tags, - float temperature, - float waterColorA, - float waterColorB, - float waterColorG, - float waterColorR, - float waterTransparency, - float white_ash -) { -} diff --git a/codegen/src/main/java/org/allaymc/codegen/BiomeIdEnumGen.java b/codegen/src/main/java/org/allaymc/codegen/BiomeIdEnumGen.java index a29c199eda..489a1ebbe3 100644 --- a/codegen/src/main/java/org/allaymc/codegen/BiomeIdEnumGen.java +++ b/codegen/src/main/java/org/allaymc/codegen/BiomeIdEnumGen.java @@ -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) diff --git a/codegen/src/main/java/org/allaymc/codegen/ClassNames.java b/codegen/src/main/java/org/allaymc/codegen/ClassNames.java index 862048441d..b6117b6d91 100644 --- a/codegen/src/main/java/org/allaymc/codegen/ClassNames.java +++ b/codegen/src/main/java/org/allaymc/codegen/ClassNames.java @@ -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"); diff --git a/server/src/main/java/org/allaymc/server/block/component/BlockFireBaseComponentImpl.java b/server/src/main/java/org/allaymc/server/block/component/BlockFireBaseComponentImpl.java index d5c0862902..4e8e1bb029 100644 --- a/server/src/main/java/org/allaymc/server/block/component/BlockFireBaseComponentImpl.java +++ b/server/src/main/java/org/allaymc/server/block/component/BlockFireBaseComponentImpl.java @@ -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; @@ -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) { @@ -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(); @@ -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); @@ -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(); @@ -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; } } diff --git a/server/src/main/java/org/allaymc/server/plugin/AllayPluginManager.java b/server/src/main/java/org/allaymc/server/plugin/AllayPluginManager.java index f49fe6a4cf..bef4907c17 100644 --- a/server/src/main/java/org/allaymc/server/plugin/AllayPluginManager.java +++ b/server/src/main/java/org/allaymc/server/plugin/AllayPluginManager.java @@ -115,7 +115,7 @@ protected void onLoad(Map descriptors, Map 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()); } } @@ -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; } diff --git a/server/src/main/java/org/allaymc/server/world/biome/BiomeData.java b/server/src/main/java/org/allaymc/server/world/biome/BiomeData.java new file mode 100644 index 0000000000..fa373024a8 --- /dev/null +++ b/server/src/main/java/org/allaymc/server/world/biome/BiomeData.java @@ -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 tags, + float temperature, + float waterColorA, + float waterColorB, + float waterColorG, + float waterColorR, + float white_ash +) { + private static final EnumMap 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") + ); + } +}