127 lines
3.9 KiB
Go
127 lines
3.9 KiB
Go
package world
|
|
|
|
import "regionio/internal/worldgen"
|
|
|
|
const vegetationStage = 9
|
|
|
|
func placeVanillaTrees(c *Chunk, seed int64, cx, cz int32, biomes *[16][16]string, surfTop *[16][16]int) {
|
|
set, err := worldgen.LoadFeatureSet()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
random, decorationSeed := worldgen.DecorationRandom(seed, int(cx), int(cz))
|
|
seen := make(map[string]bool)
|
|
for bx := 0; bx < 16; bx += 4 {
|
|
for bz := 0; bz < 16; bz += 4 {
|
|
stages := set.Biomes[biomes[bx][bz]].Features
|
|
if len(stages) <= vegetationStage {
|
|
continue
|
|
}
|
|
for featureIndex, name := range stages[vegetationStage] {
|
|
if seen[name] {
|
|
continue
|
|
}
|
|
seen[name] = true
|
|
placed, ok := set.Placed[name]
|
|
if !ok || !treeFeatureType(set.Configured[placed.Feature].Type) {
|
|
continue
|
|
}
|
|
plan, err := set.Placement(name)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
random.SetFeatureSeed(decorationSeed, featureIndex, vegetationStage)
|
|
count := plan.Count.Sample(random)
|
|
for attempt := 0; attempt < count; attempt++ {
|
|
x, z := int(random.NextIntN(16)), int(random.NextIntN(16))
|
|
y := MinY + surfTop[x][z] + 1
|
|
placeTreeReference(c, set, random, placed.Feature, x, y, z)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func treeFeatureType(kind string) bool {
|
|
return kind == "minecraft:tree" || kind == "minecraft:random_selector"
|
|
}
|
|
|
|
func placeTreeReference(c *Chunk, set *worldgen.FeatureSet, random worldgen.RandomSource, name string, x, y, z int) bool {
|
|
configured, ok := set.Configured[name]
|
|
if !ok {
|
|
if placed, exists := set.Placed[name]; exists {
|
|
return placeTreeReference(c, set, random, placed.Feature, x, y, z)
|
|
}
|
|
return false
|
|
}
|
|
switch configured.Type {
|
|
case "minecraft:random_selector":
|
|
selector, err := set.RandomSelector(name)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
for _, entry := range selector.Features {
|
|
if random.NextFloat() < entry.Chance {
|
|
return placeTreeReference(c, set, random, entry.Feature.Name, x, y, z)
|
|
}
|
|
}
|
|
return placeTreeReference(c, set, random, selector.Default.Name, x, y, z)
|
|
case "minecraft:tree":
|
|
config, err := set.Tree(name)
|
|
if err != nil || config.TrunkPlacer.Type != "minecraft:straight_trunk_placer" || config.FoliagePlacer.Type != "minecraft:blob_foliage_placer" {
|
|
return false
|
|
}
|
|
return placeStraightBlobTree(c, random, x, y, z, config)
|
|
}
|
|
return false
|
|
}
|
|
|
|
func placeStraightBlobTree(c *Chunk, random worldgen.RandomSource, x, y, z int, config worldgen.TreeFeatureConfig) bool {
|
|
if x < 2 || x >= 14 || z < 2 || z >= 14 || y <= MinY || y+12 >= MinY+WorldHeight {
|
|
return false
|
|
}
|
|
floor := c.GetBlock(x, y-1, z)
|
|
if floor != StateGrass && floor != StateDirt && floor != StateCoarseDirt && floor != StatePodzol {
|
|
return false
|
|
}
|
|
height := config.TrunkPlacer.BaseHeight
|
|
if config.TrunkPlacer.HeightRandA > 0 {
|
|
height += int(random.NextIntN(int32(config.TrunkPlacer.HeightRandA + 1)))
|
|
}
|
|
if config.TrunkPlacer.HeightRandB > 0 {
|
|
height += int(random.NextIntN(int32(config.TrunkPlacer.HeightRandB + 1)))
|
|
}
|
|
for dy := 0; dy <= height+config.FoliagePlacer.Height; dy++ {
|
|
if c.GetBlock(x, y+dy, z) != StateAir {
|
|
return false
|
|
}
|
|
}
|
|
logState, okLog := nameToStateID(config.TrunkProvider.State.Name, config.TrunkProvider.State.Properties)
|
|
leafState, okLeaf := nameToStateID(config.FoliageProvider.State.Name, config.FoliageProvider.State.Properties)
|
|
if !okLog || !okLeaf {
|
|
return false
|
|
}
|
|
c.SetBlock(x, y-1, z, StateDirt)
|
|
for dy := 0; dy < height; dy++ {
|
|
c.SetBlock(x, y+dy, z, logState)
|
|
}
|
|
centerY := y + height - 1 + config.FoliagePlacer.Offset
|
|
for layer := 0; layer < config.FoliagePlacer.Height; layer++ {
|
|
radius := config.FoliagePlacer.Radius
|
|
if layer == config.FoliagePlacer.Height-1 {
|
|
radius--
|
|
}
|
|
ly := centerY - layer
|
|
for dx := -radius; dx <= radius; dx++ {
|
|
for dz := -radius; dz <= radius; dz++ {
|
|
if abs(dx) == radius && abs(dz) == radius && random.NextIntN(2) == 0 {
|
|
continue
|
|
}
|
|
if c.GetBlock(x+dx, ly, z+dz) == StateAir {
|
|
c.SetBlock(x+dx, ly, z+dz, leafState)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
}
|