282 lines
5.1 KiB
Markdown
282 lines
5.1 KiB
Markdown
---
|
|
title: Prop Placement
|
|
type: docs
|
|
weight: 10
|
|
---
|
|
|
|
Prop placement handles the generation of vegetation, decorations, and small objects on terrain surfaces.
|
|
|
|
**Package:** `com.hypixel.hytale.builtin.hytalegenerator.props`
|
|
|
|
## Prop System
|
|
|
|
Props are small features placed after terrain generation:
|
|
|
|
```java
|
|
public interface PropPlacer {
|
|
// Place props in chunk
|
|
void place(GenerationContainer container, int chunkX, int chunkZ);
|
|
}
|
|
|
|
public class PropContext {
|
|
private int x, y, z;
|
|
private Biome biome;
|
|
private BlockType surfaceBlock;
|
|
private float slope;
|
|
private boolean nearWater;
|
|
}
|
|
```
|
|
|
|
## Prop Definition
|
|
|
|
```yaml
|
|
# props/oak_tree.yaml
|
|
Type: Prop
|
|
Id: oak_tree
|
|
Prefab: prefabs/trees/oak_medium
|
|
Density: 0.02
|
|
Placement:
|
|
SurfaceTypes: [grass_block, dirt]
|
|
MinSlope: 0
|
|
MaxSlope: 30
|
|
MinSpacing: 3
|
|
Requirements:
|
|
ClearanceAbove: 10
|
|
ClearanceRadius: 2
|
|
Variants:
|
|
- prefabs/trees/oak_small
|
|
- prefabs/trees/oak_medium
|
|
- prefabs/trees/oak_large
|
|
VariantWeights: [0.3, 0.5, 0.2]
|
|
```
|
|
|
|
## Position Providers
|
|
|
|
Determine where props can be placed:
|
|
|
|
### RandomPositionProvider
|
|
|
|
Random surface positions:
|
|
|
|
```yaml
|
|
Type: RandomPosition
|
|
Density: 0.1
|
|
GridSize: 4 # One attempt per 4x4 area
|
|
```
|
|
|
|
### GridPositionProvider
|
|
|
|
Regular grid with jitter:
|
|
|
|
```yaml
|
|
Type: GridPosition
|
|
Spacing: 8
|
|
Jitter: 3
|
|
```
|
|
|
|
### NoisePositionProvider
|
|
|
|
Noise-based clustering:
|
|
|
|
```yaml
|
|
Type: NoisePosition
|
|
NoiseScale: 0.05
|
|
Threshold: 0.3
|
|
Density: 0.5
|
|
```
|
|
|
|
## Placement Rules
|
|
|
|
```java
|
|
public class PlacementRules {
|
|
private Set<BlockType> validSurfaces;
|
|
private float minSlope;
|
|
private float maxSlope;
|
|
private int minSpacing;
|
|
private int clearanceAbove;
|
|
|
|
public boolean canPlace(PropContext ctx) {
|
|
// Check surface type
|
|
if (!validSurfaces.contains(ctx.surfaceBlock)) {
|
|
return false;
|
|
}
|
|
|
|
// Check slope
|
|
if (ctx.slope < minSlope || ctx.slope > maxSlope) {
|
|
return false;
|
|
}
|
|
|
|
// Check spacing from other props
|
|
if (!hasMinSpacing(ctx)) {
|
|
return false;
|
|
}
|
|
|
|
// Check clearance
|
|
if (!hasClearance(ctx)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Vegetation Props
|
|
|
|
### TreePlacer
|
|
|
|
Places trees with biome variation:
|
|
|
|
```yaml
|
|
Type: TreePlacer
|
|
Biomes:
|
|
forest:
|
|
Density: 0.3
|
|
Types: [oak, birch, maple]
|
|
plains:
|
|
Density: 0.02
|
|
Types: [oak]
|
|
jungle:
|
|
Density: 0.5
|
|
Types: [jungle_tree, palm]
|
|
```
|
|
|
|
### GrassPlacer
|
|
|
|
Places grass and flowers:
|
|
|
|
```yaml
|
|
Type: GrassPlacer
|
|
Density: 0.8
|
|
Variants:
|
|
- Block: tall_grass
|
|
Weight: 0.7
|
|
- Block: fern
|
|
Weight: 0.2
|
|
- Block: flower_red
|
|
Weight: 0.05
|
|
- Block: flower_yellow
|
|
Weight: 0.05
|
|
```
|
|
|
|
### BushPlacer
|
|
|
|
Places bushes and shrubs:
|
|
|
|
```yaml
|
|
Type: BushPlacer
|
|
Density: 0.1
|
|
Prefabs: [bush_small, bush_medium]
|
|
NearTreesOnly: true
|
|
TreeDistance: 5
|
|
```
|
|
|
|
## Object Props
|
|
|
|
### RockPlacer
|
|
|
|
Places rocks and boulders:
|
|
|
|
```yaml
|
|
Type: RockPlacer
|
|
Density: 0.05
|
|
Sizes:
|
|
- Prefab: rock_small
|
|
Weight: 0.6
|
|
- Prefab: rock_medium
|
|
Weight: 0.3
|
|
- Prefab: rock_large
|
|
Weight: 0.1
|
|
BiomeModifiers:
|
|
mountains: 2.0
|
|
plains: 0.5
|
|
```
|
|
|
|
### DebrisPlacer
|
|
|
|
Places fallen logs, branches:
|
|
|
|
```yaml
|
|
Type: DebrisPlacer
|
|
Density: 0.03
|
|
Items:
|
|
- fallen_log
|
|
- branch
|
|
- leaf_pile
|
|
ForestOnly: true
|
|
```
|
|
|
|
## Biome Integration
|
|
|
|
```java
|
|
public class BiomePropPlacer implements PropPlacer {
|
|
private Map<String, List<PropConfig>> biomeProps;
|
|
|
|
public void place(GenerationContainer container, int chunkX, int chunkZ) {
|
|
for (int x = 0; x < 16; x++) {
|
|
for (int z = 0; z < 16; z++) {
|
|
int worldX = chunkX * 16 + x;
|
|
int worldZ = chunkZ * 16 + z;
|
|
|
|
Biome biome = container.getBiome(worldX, worldZ);
|
|
List<PropConfig> props = biomeProps.get(biome.getId());
|
|
|
|
for (PropConfig prop : props) {
|
|
if (shouldPlace(prop, worldX, worldZ)) {
|
|
placeProp(container, prop, worldX, worldZ);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Configuration
|
|
|
|
```yaml
|
|
# props/config.yaml
|
|
PropPlacement:
|
|
Enabled: true
|
|
DensityMultiplier: 1.0
|
|
Props:
|
|
- Type: TreePlacer
|
|
Priority: 1
|
|
- Type: BushPlacer
|
|
Priority: 2
|
|
- Type: GrassPlacer
|
|
Priority: 3
|
|
- Type: RockPlacer
|
|
Priority: 4
|
|
```
|
|
|
|
## Custom Prop Placer
|
|
|
|
```java
|
|
public class MyPropPlacer implements PropPlacer {
|
|
@Override
|
|
public void place(GenerationContainer container, int chunkX, int chunkZ) {
|
|
for (int x = 0; x < 16; x++) {
|
|
for (int z = 0; z < 16; z++) {
|
|
if (random.nextFloat() < 0.1f) {
|
|
int surfaceY = container.getHeight(x, z);
|
|
// Place custom prop
|
|
placeMyProp(container, x, surfaceY + 1, z);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
{{< callout type="info" >}}
|
|
**Prop Placement Guidelines:**
|
|
- Use appropriate density for biome feel
|
|
- Ensure props don't overlap
|
|
- Add variety with multiple variants
|
|
- Consider performance with high density
|
|
- Test visual distribution across terrain
|
|
{{< /callout >}}
|