Archives
Trending
Support
Login
clear text
XML
Django
JavaScript
MATLAB
C
C++
C#
Python
SQL
Shell
Bash
Markdown
YAML
JSON
HTML
CSS
PHP
Java
Ruby
Go
Rust
Swift
Kotlin
Arduino
TypeScript
Perl
Autohotkey
Lua
SQF
R
Scala
Haskell
Groovy
Dart
Clojure
VB.NET
Objective-C
PowerShell
Bash
CoffeeScript
Verilog
package com.mysticsbiomes.common.levelgen.feature.tree; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.mojang.serialization.Codec; import com.mysticsbiomes.common.levelgen.feature.config.NewMysticTreeConfiguration; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.tags.BlockTags; import net.minecraft.util.RandomSource; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelSimulatedReader; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.LeavesBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.levelgen.feature.Feature; import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; import net.minecraft.world.level.levelgen.feature.treedecorators.TreeDecorator; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.phys.shapes.BitSetDiscreteVoxelShape; import net.minecraft.world.phys.shapes.DiscreteVoxelShape; import java.util.*; import java.util.function.BiConsumer; public abstract class NewMysticTreeFeature extends Feature
{ public NewMysticTreeFeature(Codec
codec) { super(codec); } @Override public boolean place(FeaturePlaceContext
context) { final WorldGenLevel level = context.level(); RandomSource random = context.random(); BlockPos initialPos = context.origin(); NewMysticTreeConfiguration config = context.config(); Set
trunkPositions = Sets.newHashSet(); Set
branchPositions = Sets.newHashSet(); final Set
foliagePositions = Sets.newHashSet(); Set
decoratorPositions = Sets.newHashSet(); BiConsumer
trunkSetter = setter(level, trunkPositions); BiConsumer
branchSetter = setter(level, branchPositions); BiConsumer
foliageSetter = setter(level, foliagePositions); BiConsumer
decoratorSetter = setter(level, decoratorPositions); boolean flag = this.doPlace(level, random, initialPos, trunkSetter, branchSetter, foliageSetter, config); if (flag && (!branchPositions.isEmpty() || !foliagePositions.isEmpty())) { if (!config.decorators.isEmpty()) { config.decorators.forEach((decorator) -> decorator.place(new TreeDecorator.Context(level, decoratorSetter, random, branchPositions, foliagePositions, trunkPositions))); } return BoundingBox.encapsulatingPositions(Iterables.concat(trunkPositions, branchPositions, foliagePositions, decoratorPositions)).map((box) -> { StructureTemplate.updateShapeAtEdge(level, 3, updateLeaves(level, box, branchPositions, decoratorPositions, trunkPositions), box.minX(), box.minY(), box.minZ()); return true; }).orElse(false); } else { return false; } } private static BiConsumer
setter(LevelAccessor level, Set
set) { return (pos, state) -> { set.add(pos.immutable()); level.setBlock(pos, state, 19); }; } public boolean doPlace(WorldGenLevel level, RandomSource random, BlockPos initialPos, BiConsumer
trunkSetter, BiConsumer
branchSetter, BiConsumer
foliageSetter, NewMysticTreeConfiguration config) { int trunkHeight = config.trunkShape.getTrunkHeight(random); int minBuildY = Math.min(initialPos.getY(), initialPos.getY()); int maxBuildY = Math.max(initialPos.getY(), initialPos.getY()) + trunkHeight + 1; if (minBuildY >= level.getMinBuildHeight() + 1 && maxBuildY <= level.getMaxBuildHeight()) { for (int currentY = 0; currentY <= trunkHeight; currentY++) { config.trunkShape.placeLog(level, random, initialPos.above(currentY), Direction.Axis.Y, trunkSetter, config); } int foliageRadius = config.foliageShape.radius.sample(random); int foliageHeight = config.foliageShape.height.sample(random); this.placeFoliage(level, random, initialPos.above(trunkHeight), config, foliageSetter, foliageRadius, foliageHeight); List
list = new ArrayList<>(); for (int count = 0; count < config.branchShape.branchCount.sample(random); count++) { Direction branchDirection = Direction.Plane.HORIZONTAL.getRandomDirection(random); list.add(branchDirection); for (Direction directions : list) { if (branchDirection != directions) { int branchYStart = trunkHeight / 2 - config.branchShape.branchYStart.sample(random); this.generateBranch(level, random, initialPos.above(branchYStart), branchDirection, branchSetter, foliageSetter, config); } } } return true; } else { return false; } } private int getMaxFreeTreeHeight(LevelSimulatedReader level, RandomSource random, BlockPos initialPos, int height, NewMysticTreeConfiguration config) { BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); for (int y = 0; y <= height + 1; y++) { int radius = config.foliageShape.foliageRadius(random); for (int xOffset = -radius; xOffset <= radius; xOffset++) { for (int zOffset = -radius; zOffset <= radius; zOffset++) { mutablePos.setWithOffset(initialPos, xOffset, y, zOffset); boolean flag = !config.trunkShape.isFree(level, mutablePos); if (flag) { return y - 2; } } } } return height; } private static DiscreteVoxelShape updateLeaves(LevelAccessor level, BoundingBox box, Set
logs, Set
leaves, Set
persistentLeaves) { DiscreteVoxelShape shape = new BitSetDiscreteVoxelShape(box.getXSpan(), box.getYSpan(), box.getZSpan()); List
> list = Lists.newArrayList(); for (int i = 0; i < 7; i++) { list.add(Sets.newHashSet()); } for (BlockPos pos : Lists.newArrayList(Sets.union(leaves, persistentLeaves))) { if (box.isInside(pos)) { shape.fill(pos.getX() - box.minX(), pos.getY() - box.minY(), pos.getZ() - box.minZ()); } } BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); int currentDistance = 0; list.getFirst().addAll(logs); while (true) { while (currentDistance >= 7 || !list.get(currentDistance).isEmpty()) { if (currentDistance >= 7) return shape; Iterator
iterator = list.get(currentDistance).iterator(); BlockPos currentPos = iterator.next(); iterator.remove(); if (box.isInside(currentPos)) { if (currentDistance != 0) { BlockState state = level.getBlockState(currentPos); level.setBlock(currentPos, state.setValue(BlockStateProperties.DISTANCE, 1), 19); } shape.fill(currentPos.getX() - box.minX(), currentPos.getY() - box.minY(), currentPos.getZ() - box.minZ()); for (Direction direction : Direction.values()) { mutablePos.setWithOffset(currentPos, direction); if (box.isInside(mutablePos)) { int dx = mutablePos.getX() - box.minX(); int dy = mutablePos.getY() - box.minY(); int dz = mutablePos.getZ() - box.minZ(); if (!shape.isFull(dx, dy, dz)) { OptionalInt distance = LeavesBlock.getOptionalDistanceAt(level.getBlockState(mutablePos)); if (distance.isPresent()) { int nextDistance = Math.min(distance.getAsInt(), currentDistance + 1); if (nextDistance < 7) { list.get(nextDistance).add(mutablePos.immutable()); currentDistance = Math.min(currentDistance, nextDistance); } } } } } } } ++currentDistance; } } public static boolean validTreePos(LevelSimulatedReader level, BlockPos pos) { return level.isStateAtPosition(pos, state -> state.isAir() || state.is(BlockTags.REPLACEABLE_BY_TREES)); } public static boolean isAirOrLeaves(LevelSimulatedReader level, BlockPos pos) { return level.isStateAtPosition(pos, state -> state.isAir() || state.is(BlockTags.LEAVES)); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// protected void generateBranch(LevelAccessor level, RandomSource random, BlockPos startPos, Direction branchDirection, BiConsumer
branchSetter, BiConsumer
foliageSetter, NewMysticTreeConfiguration config) { BlockPos.MutableBlockPos mutablePos = startPos.mutable(); int branchLength = config.branchShape.branchLength.sample(random); int extendAmount = config.branchShape.extendAmount.sample(random); if (extendAmount > 0) { for (int i = 0; i < extendAmount; i++) { mutablePos.move(branchDirection); config.trunkShape.placeLog(level, random, mutablePos, branchDirection.getAxis(), branchSetter, config); } } int steps = 0; while (steps <= branchLength) { int forwardInterval = 1 + Math.round((float) steps / branchLength * (config.branchShape.forwardInterval + 1)); int upwardInterval = 1 + Math.round((float) steps / branchLength * (config.branchShape.upwardInterval + 1)); for (int i = 0; i < forwardInterval && steps < branchLength; i++, steps++) { mutablePos.move(branchDirection); config.trunkShape.placeLog(level, random, mutablePos, branchDirection.getAxis(), branchSetter, config); } for (int i = 0; i < upwardInterval && steps < branchLength; i++, steps++) { mutablePos.move(Direction.UP); config.trunkShape.placeLog(level, random, mutablePos, Direction.Axis.Y, branchSetter, config); } if (steps == branchLength) { this.placeFoliage(level, random, mutablePos, config, foliageSetter, config.foliageShape.radius.sample(random), config.foliageShape.height.sample(random)); return; } } } public abstract void placeFoliage(LevelAccessor level, RandomSource random, BlockPos pos, NewMysticTreeConfiguration config, BiConsumer
foliageSetter, int foliageRadius, int foliageHeight); }
Mark as private (unlisted)
for 30 minutes
for 6 hours
for 1 day
for 1 week
for 1 month
for 1 year
everlasting (like CCCP)