[Add] Base Logic
This commit is contained in:
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace InfiniteWorld.VoxelWorld
|
||||
{
|
||||
public enum WorldPlacementMode : byte
|
||||
{
|
||||
GroundOnly,
|
||||
FlattenTerrain
|
||||
}
|
||||
|
||||
[CreateAssetMenu(menuName = "Infinite World/World Prefab Collection", fileName = "WorldPrefabCollection")]
|
||||
public sealed class WorldPrefabCollection : ScriptableObject
|
||||
{
|
||||
[Tooltip("Maximum number of spawn points this collection may contribute to a single chunk.")]
|
||||
[Min(0)] public int maxPlacementsPerChunk = 2;
|
||||
[Tooltip("How many deterministic candidate positions are tested for each spawn slot before it is skipped.")]
|
||||
[Min(1)] public int attemptsPerPlacement = 8;
|
||||
[Tooltip("How many cells near the chunk border are reserved so large prefabs do not clip outside the chunk.")]
|
||||
[Min(0)] public int chunkEdgePadding = 1;
|
||||
public List<WorldPrefabEntry> entries = new List<WorldPrefabEntry>();
|
||||
|
||||
public IReadOnlyList<WorldPrefabEntry> Entries => entries;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class WorldPrefabEntry
|
||||
{
|
||||
[Tooltip("Stable logical identifier for this entry. Use it later for save data, analytics, or seeded config generation.")]
|
||||
public string id = "entry";
|
||||
|
||||
[Tooltip("Prefab that will be instantiated when this entry wins placement generation.")]
|
||||
public GameObject prefab;
|
||||
|
||||
[Tooltip("Relative weight inside the collection. Higher values make this entry more likely to be selected compared to others.")]
|
||||
[Min(0f)] public float weight = 1f;
|
||||
|
||||
[Tooltip("Percent chance from 0 to 100 that the selected entry will actually spawn in its slot after being chosen by weight.")]
|
||||
[Range(0f, 100f)] public float spawnChancePercent = 100f;
|
||||
|
||||
[Tooltip("GroundOnly requires an already flat area. FlattenTerrain carves the area to ground level and ensures an approach path.")]
|
||||
public WorldPlacementMode placementMode;
|
||||
|
||||
[Tooltip("Required placement size in world cells. Rotations may swap X and Y if enabled.")]
|
||||
public Vector2Int footprint = Vector2Int.one;
|
||||
|
||||
[Tooltip("Extra reserved cells around the footprint so other generated placements do not overlap too closely.")]
|
||||
[Min(0)] public int clearance;
|
||||
|
||||
[Tooltip("Extra cells around the footprint that will also be flattened when using FlattenTerrain.")]
|
||||
[Min(0)] public int flattenPadding = 1;
|
||||
|
||||
[Tooltip("Maximum search radius in cells for finding existing ground and cutting an access corridor to the flattened area.")]
|
||||
[Min(1)] public int flattenSearchRadius = 6;
|
||||
|
||||
[Tooltip("Allows deterministic 90-degree rotations so the same prefab can fit in more layout variations.")]
|
||||
public bool allowRotations = true;
|
||||
}
|
||||
|
||||
public sealed class WorldTerrainPatch
|
||||
{
|
||||
private readonly List<Vector2Int> flattenedCells;
|
||||
|
||||
public WorldTerrainPatch(IReadOnlyList<Vector2Int> cells)
|
||||
{
|
||||
flattenedCells = cells != null ? new List<Vector2Int>(cells) : new List<Vector2Int>();
|
||||
}
|
||||
|
||||
public IReadOnlyList<Vector2Int> FlattenedCells => flattenedCells;
|
||||
}
|
||||
|
||||
public readonly struct WorldSpawnPoint
|
||||
{
|
||||
public WorldSpawnPoint(long spawnId, Vector2Int chunkCoord, int spawnOrdinalInChunk, int collectionIndex, int entryIndex, WorldPrefabEntry entry, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
SpawnId = spawnId;
|
||||
ChunkCoord = chunkCoord;
|
||||
SpawnOrdinalInChunk = spawnOrdinalInChunk;
|
||||
CollectionIndex = collectionIndex;
|
||||
EntryIndex = entryIndex;
|
||||
Entry = entry;
|
||||
Position = position;
|
||||
Rotation = rotation;
|
||||
}
|
||||
|
||||
public long SpawnId { get; }
|
||||
public Vector2Int ChunkCoord { get; }
|
||||
public int SpawnOrdinalInChunk { get; }
|
||||
public int CollectionIndex { get; }
|
||||
public int EntryIndex { get; }
|
||||
public WorldPrefabEntry Entry { get; }
|
||||
public Vector3 Position { get; }
|
||||
public Quaternion Rotation { get; }
|
||||
}
|
||||
|
||||
public sealed class WorldChunkPlacementPlan
|
||||
{
|
||||
private static readonly IReadOnlyList<WorldSpawnPoint> EmptySpawnPoints = Array.Empty<WorldSpawnPoint>();
|
||||
private static readonly IReadOnlyList<WorldTerrainPatch> EmptyTerrainPatches = Array.Empty<WorldTerrainPatch>();
|
||||
|
||||
private readonly IReadOnlyList<WorldSpawnPoint> spawnPoints;
|
||||
private readonly IReadOnlyList<WorldTerrainPatch> terrainPatches;
|
||||
private readonly HashSet<Vector2Int> flattenedCells;
|
||||
|
||||
public static WorldChunkPlacementPlan Empty { get; } = new WorldChunkPlacementPlan(EmptySpawnPoints, EmptyTerrainPatches, null);
|
||||
|
||||
public WorldChunkPlacementPlan(IReadOnlyList<WorldSpawnPoint> spawnPoints, IReadOnlyList<WorldTerrainPatch> terrainPatches, HashSet<Vector2Int> flattenedCells)
|
||||
{
|
||||
this.spawnPoints = spawnPoints ?? EmptySpawnPoints;
|
||||
this.terrainPatches = terrainPatches ?? EmptyTerrainPatches;
|
||||
this.flattenedCells = flattenedCells;
|
||||
}
|
||||
|
||||
public IReadOnlyList<WorldSpawnPoint> SpawnPoints => spawnPoints;
|
||||
public IReadOnlyList<WorldTerrainPatch> TerrainPatches => terrainPatches;
|
||||
public bool HasFlattening => flattenedCells != null && flattenedCells.Count > 0;
|
||||
|
||||
public int GetFinalHeight(Vector2Int worldCell, int baseHeight)
|
||||
{
|
||||
return flattenedCells != null && flattenedCells.Contains(worldCell) ? 0 : baseHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user