127 lines
4.6 KiB
C#
127 lines
4.6 KiB
C#
using System.Collections.Generic;
|
|
using Cysharp.Threading.Tasks;
|
|
using Unity.Mathematics;
|
|
using Random = Unity.Mathematics.Random;
|
|
|
|
namespace DanieleMarotta.RiversongCodeShowcase
|
|
{
|
|
public class StoneResourcesGeneratorOperation : IWorldGeneratorOperation
|
|
{
|
|
[InjectService]
|
|
private GameConfig _config;
|
|
|
|
[InjectService]
|
|
private ITileSpace _tileSpace;
|
|
|
|
public async UniTask Execute(World world)
|
|
{
|
|
return; // Temporarily disabled
|
|
|
|
var blockMap = world.BlockMap;
|
|
var resourcesState = world.RawResources;
|
|
|
|
var config = _config.WorldGen.Stone;
|
|
var stoneDefinition = await config.StoneDefinition.LoadAssetAsync<ResourceNodeDefinition>();
|
|
|
|
var random = new Random((uint)world.Seed);
|
|
var count = random.NextInt(config.Count.x, config.Count.y + 1);
|
|
|
|
var candidates = new List<(int2, int2, Directions)>();
|
|
foreach (var tile in TileRange.From(1, world.Size - 2))
|
|
if (ValidateCandidate(world, tile, out var side, out var orientation))
|
|
candidates.Add((tile, side, orientation));
|
|
|
|
var current = new List<int2>(count);
|
|
while (candidates.Count > 0 && current.Count < count)
|
|
{
|
|
var i = random.NextInt(candidates.Count);
|
|
var (tile, side, orientation) = candidates[i];
|
|
candidates[i] = candidates[^1];
|
|
candidates.RemoveAt(candidates.Count - 1);
|
|
|
|
if (TooCloseToOtherResources(tile, current, config.Spacing)) continue;
|
|
|
|
current.Add(tile);
|
|
|
|
var position = _tileSpace.TileToWorld(tile);
|
|
resourcesState.AddResourceNode(
|
|
new ResourceNode
|
|
{
|
|
Id = 1 + resourcesState.Count,
|
|
DefinitionId = stoneDefinition.RuntimeId,
|
|
Position = position,
|
|
Tile = tile,
|
|
Orientation = orientation,
|
|
Elevation = _config.GeneralSettings.BaseElevation
|
|
});
|
|
|
|
blockMap.AddReason(tile, BlockReason.RawResource);
|
|
blockMap.AddReason(tile + side, BlockReason.RawResource);
|
|
blockMap.AddReason(tile - side, BlockReason.RawResource);
|
|
}
|
|
}
|
|
|
|
private bool ValidateCandidate(World world, int2 tile, out int2 side, out Directions orientation)
|
|
{
|
|
side = default;
|
|
orientation = default;
|
|
return world.Heightmap.GetValue(tile) == _config.GeneralSettings.BaseElevation &&
|
|
!world.BlockMap.IsBlocked(tile) &&
|
|
NextToCliff(world, tile, out side, out orientation);
|
|
}
|
|
|
|
private bool NextToCliff(World world, int2 tile, out int2 side, out Directions orientation)
|
|
{
|
|
side = new int2(0, 1);
|
|
|
|
if (NextToCliff(world, tile, new int2(1, 0), side))
|
|
{
|
|
orientation = Directions.East;
|
|
return true;
|
|
}
|
|
|
|
if (NextToCliff(world, tile, new int2(-1, 0), side))
|
|
{
|
|
orientation = Directions.West;
|
|
return true;
|
|
}
|
|
|
|
side = new int2(1, 0);
|
|
|
|
if (NextToCliff(world, tile, new int2(0, 1), side))
|
|
{
|
|
orientation = Directions.North;
|
|
return true;
|
|
}
|
|
|
|
if (NextToCliff(world, tile, new int2(0, -1), side))
|
|
{
|
|
orientation = Directions.South;
|
|
return true;
|
|
}
|
|
|
|
orientation = default;
|
|
return false;
|
|
}
|
|
|
|
private bool NextToCliff(World world, int2 bottomTile, int2 direction, int2 side)
|
|
{
|
|
var topTile = bottomTile + direction;
|
|
var baseElevation = _config.GeneralSettings.BaseElevation;
|
|
|
|
return world.Heightmap.GetValue(bottomTile + side) == baseElevation &&
|
|
world.Heightmap.GetValue(bottomTile - side) == baseElevation &&
|
|
world.Heightmap.GetValue(topTile) > baseElevation &&
|
|
world.Heightmap.GetValue(topTile + side) > baseElevation &&
|
|
world.Heightmap.GetValue(topTile - side) > baseElevation;
|
|
}
|
|
|
|
private static bool TooCloseToOtherResources(int2 tile, List<int2> alreadyPlaced, int spacing)
|
|
{
|
|
foreach (var other in alreadyPlaced)
|
|
if (TileMath.StepCount(tile, other) < spacing)
|
|
return true;
|
|
return false;
|
|
}
|
|
}
|
|
} |