Добавить детерминированное размещение dungeon prefab в voxel-мире через stamp/carve в данных чанков. #6
@@ -36,6 +36,8 @@ MonoBehaviour:
|
||||
- {fileID: 11400000, guid: 6d0dbe510ed048440a3925ef40aeeb5b, type: 2}
|
||||
biomeNoiseScale: 0.02
|
||||
biomeSize: 6
|
||||
placementCollections:
|
||||
- {fileID: 11400000, guid: b91d23f483c774f4dbb1a77660881d87, type: 2}
|
||||
maxAsyncChunkJobs: 2
|
||||
maxChunkBuildsPerFrame: 1
|
||||
maxChunkMeshBuildsPerFrame: 1
|
||||
|
||||
@@ -19,8 +19,9 @@ MonoBehaviour:
|
||||
- id: EntranceCrypt
|
||||
prefab: {fileID: 155468, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
weight: 10
|
||||
spawnChancePercent: 100
|
||||
placementMode: 1
|
||||
footprint: {x: 0, y: 0}
|
||||
footprint: {x: 2, y: 2}
|
||||
clearance: 4
|
||||
flattenPadding: 4
|
||||
flattenSearchRadius: 4
|
||||
@@ -28,8 +29,9 @@ MonoBehaviour:
|
||||
- id: GlowingOrb
|
||||
prefab: {fileID: 190932, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
weight: 0
|
||||
spawnChancePercent: 100
|
||||
placementMode: 0
|
||||
footprint: {x: 0, y: 0}
|
||||
footprint: {x: 2, y: 2}
|
||||
clearance: 4
|
||||
flattenPadding: 4
|
||||
flattenSearchRadius: 4
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
internal readonly struct VoxelWorldResolvedSettings
|
||||
{
|
||||
private static readonly IReadOnlyList<VoxelBiomeProfile> EmptyBiomes = System.Array.Empty<VoxelBiomeProfile>();
|
||||
private static readonly IReadOnlyList<WorldPrefabCollection> EmptyPlacementCollections = System.Array.Empty<WorldPrefabCollection>();
|
||||
private static readonly IReadOnlyList<WorldPrefabCollectionRuntime> EmptyPlacementCollections = System.Array.Empty<WorldPrefabCollectionRuntime>();
|
||||
|
||||
public static readonly VoxelWorldResolvedSettings Default = Resolve(null);
|
||||
|
||||
@@ -79,7 +79,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
IReadOnlyList<VoxelBiomeProfile> biomeProfiles,
|
||||
float biomeNoiseScale,
|
||||
float biomeSize,
|
||||
IReadOnlyList<WorldPrefabCollection> placementCollections,
|
||||
IReadOnlyList<WorldPrefabCollectionRuntime> placementCollections,
|
||||
int maxAsyncChunkJobs,
|
||||
int maxChunkBuildsPerFrame,
|
||||
int maxChunkMeshBuildsPerFrame,
|
||||
@@ -140,7 +140,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
public IReadOnlyList<VoxelBiomeProfile> BiomeProfiles { get; }
|
||||
public float BiomeNoiseScale { get; }
|
||||
public float BiomeSize { get; }
|
||||
public IReadOnlyList<WorldPrefabCollection> PlacementCollections { get; }
|
||||
public IReadOnlyList<WorldPrefabCollectionRuntime> PlacementCollections { get; }
|
||||
public int MaxAsyncChunkJobs { get; }
|
||||
public int MaxChunkBuildsPerFrame { get; }
|
||||
public int MaxChunkMeshBuildsPerFrame { get; }
|
||||
@@ -154,9 +154,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
IReadOnlyList<VoxelBiomeProfile> biomes = config != null && config.biomeProfiles != null
|
||||
? config.biomeProfiles
|
||||
: EmptyBiomes;
|
||||
IReadOnlyList<WorldPrefabCollection> placements = config != null && config.placementCollections != null
|
||||
? config.placementCollections
|
||||
: EmptyPlacementCollections;
|
||||
IReadOnlyList<WorldPrefabCollectionRuntime> placements = ResolvePlacementCollections(config);
|
||||
|
||||
return new VoxelWorldResolvedSettings(
|
||||
Mathf.Max(8, config != null ? config.chunkSize : 16),
|
||||
@@ -189,5 +187,58 @@ namespace InfiniteWorld.VoxelWorld
|
||||
Mathf.Max(1, config != null ? config.renderRegionSizeInChunks : 4),
|
||||
Mathf.Max(1, config != null ? config.maxRegionBuildsPerFrame : 1));
|
||||
}
|
||||
|
||||
private static IReadOnlyList<WorldPrefabCollectionRuntime> ResolvePlacementCollections(VoxelWorldConfig config)
|
||||
{
|
||||
if (config == null || config.placementCollections == null || config.placementCollections.Count == 0)
|
||||
{
|
||||
return EmptyPlacementCollections;
|
||||
}
|
||||
|
||||
List<WorldPrefabCollectionRuntime> result = new List<WorldPrefabCollectionRuntime>(config.placementCollections.Count);
|
||||
for (int collectionIndex = 0; collectionIndex < config.placementCollections.Count; collectionIndex++)
|
||||
{
|
||||
WorldPrefabCollection collection = config.placementCollections[collectionIndex];
|
||||
if (collection == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
List<WorldPrefabEntryRuntime> entries = new List<WorldPrefabEntryRuntime>();
|
||||
if (collection.entries != null)
|
||||
{
|
||||
for (int entryIndex = 0; entryIndex < collection.entries.Count; entryIndex++)
|
||||
{
|
||||
WorldPrefabEntry entry = collection.entries[entryIndex];
|
||||
if (entry == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
entries.Add(new WorldPrefabEntryRuntime(
|
||||
entryIndex,
|
||||
entry.id,
|
||||
entry.weight,
|
||||
entry.spawnChancePercent,
|
||||
entry.placementMode,
|
||||
entry.footprint,
|
||||
entry.clearance,
|
||||
entry.flattenPadding,
|
||||
entry.flattenSearchRadius,
|
||||
entry.allowRotations,
|
||||
entry.prefab != null));
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new WorldPrefabCollectionRuntime(
|
||||
collectionIndex,
|
||||
Mathf.Max(0, collection.maxPlacementsPerChunk),
|
||||
Mathf.Max(1, collection.attemptsPerPlacement),
|
||||
Mathf.Max(0, collection.chunkEdgePadding),
|
||||
entries));
|
||||
}
|
||||
|
||||
return result.Count > 0 ? result : EmptyPlacementCollections;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@ namespace InfiniteWorld.VoxelWorld
|
||||
public sealed partial class VoxelWorldGenerator
|
||||
{
|
||||
private readonly Dictionary<Vector2Int, WorldChunkPlacementPlan> chunkPlacementPlans = new Dictionary<Vector2Int, WorldChunkPlacementPlan>();
|
||||
private IReadOnlyList<WorldPrefabCollection> placementCollections => settings.PlacementCollections;
|
||||
|
||||
public IReadOnlyList<WorldPrefabCollection> PlacementCollections => placementCollections;
|
||||
private readonly object placementPlanLock = new object();
|
||||
private IReadOnlyList<WorldPrefabCollectionRuntime> placementCollections => settings.PlacementCollections;
|
||||
|
||||
public WorldChunkPlacementPlan GetChunkPlacementPlan(Vector2Int chunkCoord)
|
||||
{
|
||||
@@ -32,14 +31,26 @@ namespace InfiniteWorld.VoxelWorld
|
||||
|
||||
private WorldChunkPlacementPlan GetOrCreateChunkPlacementPlan(Vector2Int chunkCoord)
|
||||
{
|
||||
if (chunkPlacementPlans.TryGetValue(chunkCoord, out WorldChunkPlacementPlan plan))
|
||||
lock (placementPlanLock)
|
||||
{
|
||||
return plan;
|
||||
if (chunkPlacementPlans.TryGetValue(chunkCoord, out WorldChunkPlacementPlan cachedPlan))
|
||||
{
|
||||
return cachedPlan;
|
||||
}
|
||||
}
|
||||
|
||||
plan = WorldSpawnPlanner.PlanChunk(seed, chunkCoord, chunkSize, placementCollections, GetBaseHeightAtWorldCell);
|
||||
chunkPlacementPlans[chunkCoord] = plan;
|
||||
return plan;
|
||||
WorldChunkPlacementPlan plan = WorldSpawnPlanner.PlanChunk(seed, chunkCoord, chunkSize, placementCollections, GetBaseHeightAtWorldCell);
|
||||
|
||||
lock (placementPlanLock)
|
||||
{
|
||||
if (chunkPlacementPlans.TryGetValue(chunkCoord, out WorldChunkPlacementPlan cachedPlan))
|
||||
{
|
||||
return cachedPlan;
|
||||
}
|
||||
|
||||
chunkPlacementPlans[chunkCoord] = plan;
|
||||
return plan;
|
||||
}
|
||||
}
|
||||
|
||||
private int GetSampledFinalHeightAtWorldCell(Vector2Int worldCell)
|
||||
@@ -72,7 +83,10 @@ namespace InfiniteWorld.VoxelWorld
|
||||
|
||||
private void CleanupPlacementPlans()
|
||||
{
|
||||
chunkPlacementPlans.Clear();
|
||||
lock (placementPlanLock)
|
||||
{
|
||||
chunkPlacementPlans.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,10 @@ namespace InfiniteWorld.VoxelWorld
|
||||
Vector2Int regionCoord = ChunkToRegion(coord);
|
||||
MarkRegionDirty(coord);
|
||||
chunks.Remove(coord);
|
||||
chunkPlacementPlans.Remove(coord);
|
||||
lock (placementPlanLock)
|
||||
{
|
||||
chunkPlacementPlans.Remove(coord);
|
||||
}
|
||||
runtime.Dispose();
|
||||
TryDisposeRegionIfEmpty(regionCoord);
|
||||
QueueNeighborRefresh(coord);
|
||||
|
||||
@@ -58,6 +58,54 @@ namespace InfiniteWorld.VoxelWorld
|
||||
public bool allowRotations = true;
|
||||
}
|
||||
|
||||
internal sealed class WorldPrefabCollectionRuntime
|
||||
{
|
||||
public WorldPrefabCollectionRuntime(int sourceIndex, int maxPlacementsPerChunk, int attemptsPerPlacement, int chunkEdgePadding, IReadOnlyList<WorldPrefabEntryRuntime> entries)
|
||||
{
|
||||
SourceIndex = sourceIndex;
|
||||
MaxPlacementsPerChunk = maxPlacementsPerChunk;
|
||||
AttemptsPerPlacement = attemptsPerPlacement;
|
||||
ChunkEdgePadding = chunkEdgePadding;
|
||||
Entries = entries ?? Array.Empty<WorldPrefabEntryRuntime>();
|
||||
}
|
||||
|
||||
public int SourceIndex { get; }
|
||||
public int MaxPlacementsPerChunk { get; }
|
||||
public int AttemptsPerPlacement { get; }
|
||||
public int ChunkEdgePadding { get; }
|
||||
public IReadOnlyList<WorldPrefabEntryRuntime> Entries { get; }
|
||||
}
|
||||
|
||||
internal sealed class WorldPrefabEntryRuntime
|
||||
{
|
||||
public WorldPrefabEntryRuntime(int sourceIndex, string id, float weight, float spawnChancePercent, WorldPlacementMode placementMode, Vector2Int footprint, int clearance, int flattenPadding, int flattenSearchRadius, bool allowRotations, bool hasPrefab)
|
||||
{
|
||||
SourceIndex = sourceIndex;
|
||||
Id = string.IsNullOrWhiteSpace(id) ? $"entry_{sourceIndex}" : id;
|
||||
Weight = Mathf.Max(0f, weight);
|
||||
SpawnChancePercent = Mathf.Clamp(spawnChancePercent, 0f, 100f);
|
||||
PlacementMode = placementMode;
|
||||
Footprint = new Vector2Int(Mathf.Max(1, footprint.x), Mathf.Max(1, footprint.y));
|
||||
Clearance = Mathf.Max(0, clearance);
|
||||
FlattenPadding = Mathf.Max(0, flattenPadding);
|
||||
FlattenSearchRadius = Mathf.Max(1, flattenSearchRadius);
|
||||
AllowRotations = allowRotations;
|
||||
HasPrefab = hasPrefab;
|
||||
}
|
||||
|
||||
public int SourceIndex { get; }
|
||||
public string Id { get; }
|
||||
public float Weight { get; }
|
||||
public float SpawnChancePercent { get; }
|
||||
public WorldPlacementMode PlacementMode { get; }
|
||||
public Vector2Int Footprint { get; }
|
||||
public int Clearance { get; }
|
||||
public int FlattenPadding { get; }
|
||||
public int FlattenSearchRadius { get; }
|
||||
public bool AllowRotations { get; }
|
||||
public bool HasPrefab { get; }
|
||||
}
|
||||
|
||||
public sealed class WorldTerrainPatch
|
||||
{
|
||||
private readonly List<Vector2Int> flattenedCells;
|
||||
@@ -72,14 +120,14 @@ namespace InfiniteWorld.VoxelWorld
|
||||
|
||||
public readonly struct WorldSpawnPoint
|
||||
{
|
||||
public WorldSpawnPoint(long spawnId, Vector2Int chunkCoord, int spawnOrdinalInChunk, int collectionIndex, int entryIndex, WorldPrefabEntry entry, Vector3 position, Quaternion rotation)
|
||||
public WorldSpawnPoint(long spawnId, Vector2Int chunkCoord, int spawnOrdinalInChunk, int collectionIndex, int entryIndex, string entryId, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
SpawnId = spawnId;
|
||||
ChunkCoord = chunkCoord;
|
||||
SpawnOrdinalInChunk = spawnOrdinalInChunk;
|
||||
CollectionIndex = collectionIndex;
|
||||
EntryIndex = entryIndex;
|
||||
Entry = entry;
|
||||
EntryId = entryId;
|
||||
Position = position;
|
||||
Rotation = rotation;
|
||||
}
|
||||
@@ -89,7 +137,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
public int SpawnOrdinalInChunk { get; }
|
||||
public int CollectionIndex { get; }
|
||||
public int EntryIndex { get; }
|
||||
public WorldPrefabEntry Entry { get; }
|
||||
public string EntryId { get; }
|
||||
public Vector3 Position { get; }
|
||||
public Quaternion Rotation { get; }
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
int worldSeed,
|
||||
Vector2Int chunkCoord,
|
||||
int chunkSize,
|
||||
IReadOnlyList<WorldPrefabCollection> collections,
|
||||
IReadOnlyList<WorldPrefabCollectionRuntime> collections,
|
||||
System.Func<Vector2Int, int> getBaseHeight)
|
||||
{
|
||||
if (collections == null || collections.Count == 0)
|
||||
@@ -25,15 +25,15 @@ namespace InfiniteWorld.VoxelWorld
|
||||
|
||||
for (int collectionIndex = 0; collectionIndex < collections.Count; collectionIndex++)
|
||||
{
|
||||
WorldPrefabCollection collection = collections[collectionIndex];
|
||||
if (collection == null || collection.entries == null || collection.entries.Count == 0 || collection.maxPlacementsPerChunk <= 0)
|
||||
WorldPrefabCollectionRuntime collection = collections[collectionIndex];
|
||||
if (collection == null || collection.Entries == null || collection.Entries.Count == 0 || collection.MaxPlacementsPerChunk <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int placementIndex = 0; placementIndex < collection.maxPlacementsPerChunk; placementIndex++)
|
||||
for (int placementIndex = 0; placementIndex < collection.MaxPlacementsPerChunk; placementIndex++)
|
||||
{
|
||||
if (!TryPickEntry(collection, worldSeed, chunkCoord, collectionIndex, placementIndex, out int entryIndex, out WorldPrefabEntry entry))
|
||||
if (!TryPickEntry(collection, worldSeed, chunkCoord, collectionIndex, placementIndex, out int entryIndex, out WorldPrefabEntryRuntime entry))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -71,18 +71,18 @@ namespace InfiniteWorld.VoxelWorld
|
||||
return new WorldChunkPlacementPlan(spawnPoints, terrainPatches, flattenedCells.Count > 0 ? flattenedCells : null);
|
||||
}
|
||||
|
||||
private static bool TryPickEntry(WorldPrefabCollection collection, int worldSeed, Vector2Int chunkCoord, int collectionIndex, int placementIndex, out int entryIndex, out WorldPrefabEntry entry)
|
||||
private static bool TryPickEntry(WorldPrefabCollectionRuntime collection, int worldSeed, Vector2Int chunkCoord, int collectionIndex, int placementIndex, out int entryIndex, out WorldPrefabEntryRuntime entry)
|
||||
{
|
||||
float totalWeight = 0f;
|
||||
for (int i = 0; i < collection.entries.Count; i++)
|
||||
for (int i = 0; i < collection.Entries.Count; i++)
|
||||
{
|
||||
WorldPrefabEntry candidate = collection.entries[i];
|
||||
if (candidate == null || candidate.prefab == null || candidate.weight <= 0f)
|
||||
WorldPrefabEntryRuntime candidate = collection.Entries[i];
|
||||
if (candidate == null || !candidate.HasPrefab || candidate.Weight <= 0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
totalWeight += candidate.weight;
|
||||
totalWeight += candidate.Weight;
|
||||
}
|
||||
|
||||
if (totalWeight <= 0f)
|
||||
@@ -94,15 +94,15 @@ namespace InfiniteWorld.VoxelWorld
|
||||
|
||||
float pick = WorldSeedUtility.Value01(WorldSeedUtility.Hash(worldSeed, chunkCoord.x, chunkCoord.y, collectionIndex, placementIndex, 1)) * totalWeight;
|
||||
float accumulated = 0f;
|
||||
for (int i = 0; i < collection.entries.Count; i++)
|
||||
for (int i = 0; i < collection.Entries.Count; i++)
|
||||
{
|
||||
WorldPrefabEntry candidate = collection.entries[i];
|
||||
if (candidate == null || candidate.prefab == null || candidate.weight <= 0f)
|
||||
WorldPrefabEntryRuntime candidate = collection.Entries[i];
|
||||
if (candidate == null || !candidate.HasPrefab || candidate.Weight <= 0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
accumulated += candidate.weight;
|
||||
accumulated += candidate.Weight;
|
||||
if (pick <= accumulated)
|
||||
{
|
||||
entryIndex = i;
|
||||
@@ -111,10 +111,10 @@ namespace InfiniteWorld.VoxelWorld
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = collection.entries.Count - 1; i >= 0; i--)
|
||||
for (int i = collection.Entries.Count - 1; i >= 0; i--)
|
||||
{
|
||||
WorldPrefabEntry candidate = collection.entries[i];
|
||||
if (candidate == null || candidate.prefab == null || candidate.weight <= 0f)
|
||||
WorldPrefabEntryRuntime candidate = collection.Entries[i];
|
||||
if (candidate == null || !candidate.HasPrefab || candidate.Weight <= 0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -129,36 +129,36 @@ namespace InfiniteWorld.VoxelWorld
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool PassesSpawnChance(WorldPrefabEntry entry, int worldSeed, Vector2Int chunkCoord, int collectionIndex, int placementIndex)
|
||||
private static bool PassesSpawnChance(WorldPrefabEntryRuntime entry, int worldSeed, Vector2Int chunkCoord, int collectionIndex, int placementIndex)
|
||||
{
|
||||
if (entry == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.spawnChancePercent <= 0f)
|
||||
if (entry.SpawnChancePercent <= 0f)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.spawnChancePercent >= 100f)
|
||||
if (entry.SpawnChancePercent >= 100f)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
float roll = WorldSeedUtility.Value01(WorldSeedUtility.Hash(worldSeed, chunkCoord.x, chunkCoord.y, collectionIndex, placementIndex, 11)) * 100f;
|
||||
return roll <= entry.spawnChancePercent;
|
||||
return roll <= entry.SpawnChancePercent;
|
||||
}
|
||||
|
||||
private static bool TryPlanPlacement(
|
||||
int worldSeed,
|
||||
Vector2Int chunkCoord,
|
||||
int chunkSize,
|
||||
WorldPrefabCollection collection,
|
||||
WorldPrefabCollectionRuntime collection,
|
||||
int collectionIndex,
|
||||
int placementIndex,
|
||||
int entryIndex,
|
||||
WorldPrefabEntry entry,
|
||||
WorldPrefabEntryRuntime entry,
|
||||
int spawnOrdinal,
|
||||
HashSet<Vector2Int> occupiedCells,
|
||||
HashSet<Vector2Int> flattenedCells,
|
||||
@@ -172,20 +172,20 @@ namespace InfiniteWorld.VoxelWorld
|
||||
patch = null;
|
||||
|
||||
Vector2Int chunkOrigin = new Vector2Int(chunkCoord.x * chunkSize, chunkCoord.y * chunkSize);
|
||||
int attempts = Mathf.Max(1, collection.attemptsPerPlacement);
|
||||
int attempts = Mathf.Max(1, collection.AttemptsPerPlacement);
|
||||
for (int attempt = 0; attempt < attempts; attempt++)
|
||||
{
|
||||
int rotationSteps = entry.allowRotations ? WorldSeedUtility.Range(WorldSeedUtility.Hash(worldSeed, chunkCoord.x, chunkCoord.y, collectionIndex, placementIndex, attempt, 2), 0, 4) : 0;
|
||||
Vector2Int footprint = GetFootprint(entry.footprint, rotationSteps);
|
||||
int rotationSteps = entry.AllowRotations ? WorldSeedUtility.Range(WorldSeedUtility.Hash(worldSeed, chunkCoord.x, chunkCoord.y, collectionIndex, placementIndex, attempt, 2), 0, 4) : 0;
|
||||
Vector2Int footprint = GetFootprint(entry.Footprint, rotationSteps);
|
||||
if (footprint.x <= 0 || footprint.y <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int localMinX = collection.chunkEdgePadding;
|
||||
int localMinZ = collection.chunkEdgePadding;
|
||||
int localMaxX = chunkSize - collection.chunkEdgePadding - footprint.x;
|
||||
int localMaxZ = chunkSize - collection.chunkEdgePadding - footprint.y;
|
||||
int localMinX = collection.ChunkEdgePadding;
|
||||
int localMinZ = collection.ChunkEdgePadding;
|
||||
int localMaxX = chunkSize - collection.ChunkEdgePadding - footprint.x;
|
||||
int localMaxZ = chunkSize - collection.ChunkEdgePadding - footprint.y;
|
||||
if (localMaxX < localMinX || localMaxZ < localMinZ)
|
||||
{
|
||||
continue;
|
||||
@@ -194,14 +194,14 @@ namespace InfiniteWorld.VoxelWorld
|
||||
int localX = WorldSeedUtility.Range(WorldSeedUtility.Hash(worldSeed, chunkCoord.x, chunkCoord.y, collectionIndex, placementIndex, attempt, 3), localMinX, localMaxX + 1);
|
||||
int localZ = WorldSeedUtility.Range(WorldSeedUtility.Hash(worldSeed, chunkCoord.x, chunkCoord.y, collectionIndex, placementIndex, attempt, 4), localMinZ, localMaxZ + 1);
|
||||
RectInt footprintRect = new RectInt(localX, localZ, footprint.x, footprint.y);
|
||||
RectInt reservedRect = ExpandRect(footprintRect, Mathf.Max(0, entry.clearance), chunkSize);
|
||||
RectInt reservedRect = ExpandRect(footprintRect, Mathf.Max(0, entry.Clearance), chunkSize);
|
||||
|
||||
if (IntersectsOccupied(chunkOrigin, reservedRect, occupiedCells))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.placementMode == WorldPlacementMode.GroundOnly)
|
||||
if (entry.PlacementMode == WorldPlacementMode.GroundOnly)
|
||||
{
|
||||
if (!IsGroundArea(chunkOrigin, reservedRect, flattenedCells, getBaseHeight))
|
||||
{
|
||||
@@ -227,7 +227,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
long spawnId = WorldSeedUtility.ToStableId(
|
||||
WorldSeedUtility.Hash(worldSeed, chunkCoord.x, chunkCoord.y, collectionIndex),
|
||||
WorldSeedUtility.Hash(entryIndex, placementIndex, spawnOrdinal, footprintRect.x, footprintRect.y));
|
||||
spawnPoint = new WorldSpawnPoint(spawnId, chunkCoord, spawnOrdinal, collectionIndex, entryIndex, entry, position, Quaternion.Euler(0f, rotationY, 0f));
|
||||
spawnPoint = new WorldSpawnPoint(spawnId, chunkCoord, spawnOrdinal, collectionIndex, entryIndex, entry.Id, position, Quaternion.Euler(0f, rotationY, 0f));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -239,14 +239,14 @@ namespace InfiniteWorld.VoxelWorld
|
||||
int chunkSize,
|
||||
RectInt footprintRect,
|
||||
RectInt reservedRect,
|
||||
WorldPrefabEntry entry,
|
||||
WorldPrefabEntryRuntime entry,
|
||||
HashSet<Vector2Int> occupiedCells,
|
||||
HashSet<Vector2Int> flattenedCells,
|
||||
System.Func<Vector2Int, int> getBaseHeight,
|
||||
out WorldTerrainPatch patch,
|
||||
out List<Vector2Int> reservedCells)
|
||||
{
|
||||
int flattenPadding = Mathf.Max(entry.clearance, entry.flattenPadding);
|
||||
int flattenPadding = Mathf.Max(entry.Clearance, entry.FlattenPadding);
|
||||
RectInt flattenRect = ExpandRect(footprintRect, flattenPadding, chunkSize);
|
||||
List<Vector2Int> flattened = CollectCells(chunkOrigin, flattenRect);
|
||||
if (IntersectsOccupied(flattened, occupiedCells))
|
||||
@@ -256,7 +256,7 @@ namespace InfiniteWorld.VoxelWorld
|
||||
return false;
|
||||
}
|
||||
|
||||
List<Vector2Int> corridor = TryBuildAccessCorridor(chunkOrigin, chunkSize, flattenRect, Mathf.Max(1, entry.flattenSearchRadius), occupiedCells, flattenedCells, getBaseHeight);
|
||||
List<Vector2Int> corridor = TryBuildAccessCorridor(chunkOrigin, chunkSize, flattenRect, Mathf.Max(1, entry.FlattenSearchRadius), occupiedCells, flattenedCells, getBaseHeight);
|
||||
if (corridor == null)
|
||||
{
|
||||
patch = null;
|
||||
|
||||
@@ -277,63 +277,6 @@ Transform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1001 &1015513039
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 155468, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: SM_Env_Entrance_Crypt_01
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 3.1642048
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0.00000032572393
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 2.031263
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 492300, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: ea0c7071e67bf1c43940a8ab3ea121f8, type: 3}
|
||||
--- !u!1001 &1165873058
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -395,79 +338,6 @@ PrefabInstance:
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 0b650fca685f2eb41a86538aa883e4c1, type: 3}
|
||||
--- !u!1001 &1382386155
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
serializedVersion: 2
|
||||
m_Modification:
|
||||
serializedVersion: 3
|
||||
m_TransformParent: {fileID: 0}
|
||||
m_Modifications:
|
||||
- target: {fileID: 190932, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_Name
|
||||
value: SM_Env_GlowingOrb_04
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalScale.x
|
||||
value: 14.01
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalScale.y
|
||||
value: 14.01
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalScale.z
|
||||
value: 14.01
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalPosition.x
|
||||
value: 11.45
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalPosition.y
|
||||
value: 0.27
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalPosition.z
|
||||
value: 4.4
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalRotation.w
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalRotation.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalRotation.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalRotation.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 495720, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
propertyPath: m_ConstrainProportionsScale
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
m_AddedComponents: []
|
||||
m_SourcePrefab: {fileID: 100100000, guid: 20e0bf298681fcd4693097c822277593, type: 3}
|
||||
--- !u!1001 &6493552143235564167
|
||||
PrefabInstance:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -528,6 +398,10 @@ PrefabInstance:
|
||||
propertyPath: placementCollections.Array.size
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 2927522923773808063, guid: 91b5caa5457131b4f8c542529f4ad7c3, type: 3}
|
||||
propertyPath: 'placementCollections.Array.data[0]'
|
||||
value:
|
||||
objectReference: {fileID: 11400000, guid: b91d23f483c774f4dbb1a77660881d87, type: 2}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
@@ -541,5 +415,3 @@ SceneRoots:
|
||||
- {fileID: 6493552143235564167}
|
||||
- {fileID: 1165873058}
|
||||
- {fileID: 171707223}
|
||||
- {fileID: 1015513039}
|
||||
- {fileID: 1382386155}
|
||||
|
||||
Reference in New Issue
Block a user