Make procgen use weighted variants (#24669)

This commit is contained in:
Nemanja
2024-01-28 21:41:59 -05:00
committed by GitHub
parent bd100344a2
commit 2a6705818b
11 changed files with 68 additions and 64 deletions

View File

@@ -6,6 +6,7 @@ using Content.Server.Procedural;
using Content.Server.Salvage; using Content.Server.Salvage;
using Content.Shared.CCVar; using Content.Shared.CCVar;
using Content.Shared.Dataset; using Content.Shared.Dataset;
using Content.Shared.Maps;
using Content.Shared.Movement.Components; using Content.Shared.Movement.Components;
using Content.Shared.Parallax.Biomes; using Content.Shared.Parallax.Biomes;
using Content.Shared.Physics; using Content.Shared.Physics;
@@ -41,6 +42,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem
[Dependency] private readonly MetaDataSystem _metadata = default!; [Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly RestrictedRangeSystem _restricted = default!; [Dependency] private readonly RestrictedRangeSystem _restricted = default!;
[Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly TileSystem _tile = default!;
[ValidatePrototypeId<DatasetPrototype>] [ValidatePrototypeId<DatasetPrototype>]
private const string PlanetNames = "names_borer"; private const string PlanetNames = "names_borer";
@@ -132,7 +134,7 @@ public sealed class GatewayGeneratorSystem : EntitySystem
{ {
for (var y = -2; y <= 2; y++) for (var y = -2; y <= 2; y++)
{ {
tiles.Add((new Vector2i(x, y) + origin, new Tile(tileDef.TileId, variant: random.NextByte(tileDef.Variants)))); tiles.Add((new Vector2i(x, y) + origin, new Tile(tileDef.TileId, variant: _tile.PickVariant((ContentTileDefinition) tileDef, random))));
} }
} }

View File

@@ -84,7 +84,7 @@ public sealed partial class DungeonJob
foundNoise = true; foundNoise = true;
noiseFill = true; noiseFill = true;
var tileDef = _tileDefManager[layer.Tile]; var tileDef = _tileDefManager[layer.Tile];
var variant = rand.NextByte(tileDef.Variants); var variant = _tile.PickVariant((ContentTileDefinition) tileDef, rand);
tiles.Add((node, new Tile(tileDef.TileId, variant: variant))); tiles.Add((node, new Tile(tileDef.TileId, variant: variant)));
roomTiles.Add(node); roomTiles.Add(node);

View File

@@ -3,6 +3,7 @@ using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using Content.Server.NodeContainer; using Content.Server.NodeContainer;
using Content.Shared.Doors.Components; using Content.Shared.Doors.Components;
using Content.Shared.Maps;
using Content.Shared.Physics; using Content.Shared.Physics;
using Content.Shared.Procedural; using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration; using Content.Shared.Procedural.PostGeneration;
@@ -191,7 +192,7 @@ public sealed partial class DungeonJob
if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
tiles.Add((neighbor, _tileDefManager.GetVariantTile(tileDef, random))); tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
} }
foreach (var index in dungeon.CorridorExteriorTiles) foreach (var index in dungeon.CorridorExteriorTiles)
@@ -202,7 +203,7 @@ public sealed partial class DungeonJob
if (!_anchorable.TileFree(grid, index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) if (!_anchorable.TileFree(grid, index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask))
continue; continue;
tiles.Add((index, _tileDefManager.GetVariantTile(tileDef, random))); tiles.Add((index, _tile.GetVariantTile((ContentTileDefinition)tileDef, random)));
} }
grid.SetTiles(tiles); grid.SetTiles(tiles);
@@ -478,7 +479,7 @@ public sealed partial class DungeonJob
isValid = true; isValid = true;
// Entrance wew // Entrance wew
grid.SetTile(tile, _tileDefManager.GetVariantTile(tileDef, random)); grid.SetTile(tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
ClearDoor(dungeon, grid, tile); ClearDoor(dungeon, grid, tile);
var gridCoords = grid.GridTileToLocal(tile); var gridCoords = grid.GridTileToLocal(tile);
// Need to offset the spawn to avoid spawning in the room. // Need to offset the spawn to avoid spawning in the room.
@@ -496,7 +497,7 @@ public sealed partial class DungeonJob
continue; continue;
} }
grid.SetTile(nearTile.GridIndices, _tileDefManager.GetVariantTile(tileDef, random)); grid.SetTile(nearTile.GridIndices, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));;
} }
break; break;
@@ -589,7 +590,7 @@ public sealed partial class DungeonJob
{ {
var neighbor = tile + dirVec * j; var neighbor = tile + dirVec * j;
tiles.Add((neighbor, _tileDefManager.GetVariantTile(tileDef, random))); tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
index++; index++;
takenTiles.Add(neighbor); takenTiles.Add(neighbor);
} }
@@ -690,7 +691,7 @@ public sealed partial class DungeonJob
{ {
var tile = validTiles[j]; var tile = validTiles[j];
var gridPos = grid.GridTileToLocal(tile); var gridPos = grid.GridTileToLocal(tile);
grid.SetTile(tile, _tileDefManager.GetVariantTile(tileDef, random)); grid.SetTile(tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
_entManager.SpawnEntities(gridPos, gen.Entities); _entManager.SpawnEntities(gridPos, gen.Entities);
} }
@@ -721,7 +722,7 @@ public sealed partial class DungeonJob
{ {
foreach (var entrance in room.Entrances) foreach (var entrance in room.Entrances)
{ {
setTiles.Add((entrance, _tileDefManager.GetVariantTile(tileDef, random))); setTiles.Add((entrance, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
} }
} }
@@ -857,7 +858,7 @@ public sealed partial class DungeonJob
foreach (var tile in corridorTiles) foreach (var tile in corridorTiles)
{ {
setTiles.Add((tile, _tileDefManager.GetVariantTile(tileDef, random))); setTiles.Add((tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
} }
grid.SetTiles(setTiles); grid.SetTiles(setTiles);
@@ -902,7 +903,7 @@ public sealed partial class DungeonJob
if (!dungeon.RoomExteriorTiles.Contains(neighbor)) if (!dungeon.RoomExteriorTiles.Contains(neighbor))
continue; continue;
tiles.Add((neighbor, _tileDefManager.GetVariantTile(tileDef, random))); tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)));
spawnPositions.Add(neighbor); spawnPositions.Add(neighbor);
} }
} }
@@ -1013,7 +1014,7 @@ public sealed partial class DungeonJob
for (var x = -width + 1; x < width; x++) for (var x = -width + 1; x < width; x++)
{ {
var weh = tile + neighborDir.ToIntVec() * x; var weh = tile + neighborDir.ToIntVec() * x;
grid.SetTile(weh, _tileDefManager.GetVariantTile(tileDef, random)); grid.SetTile(weh, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
var coords = grid.GridTileToLocal(weh); var coords = grid.GridTileToLocal(weh);
_entManager.SpawnEntities(coords, gen.Entities); _entManager.SpawnEntities(coords, gen.Entities);
@@ -1131,7 +1132,7 @@ public sealed partial class DungeonJob
continue; continue;
width--; width--;
grid.SetTile(node, _tileDefManager.GetVariantTile(tileDef, random)); grid.SetTile(node, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
if (gen.EdgeEntities != null && nodeDistances.Count - i <= 2) if (gen.EdgeEntities != null && nodeDistances.Count - i <= 2)
{ {
@@ -1217,7 +1218,7 @@ public sealed partial class DungeonJob
if (!random.Prob(gen.Prob) || !checkedTiles.Add(neighbor)) if (!random.Prob(gen.Prob) || !checkedTiles.Add(neighbor))
continue; continue;
grid.SetTile(neighbor, _tileDefManager.GetVariantTile(tileDef, random)); grid.SetTile(neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));
var gridPos = grid.GridTileToLocal(neighbor); var gridPos = grid.GridTileToLocal(neighbor);
var protoNames = EntitySpawnCollection.GetSpawns(gen.Spawns, random); var protoNames = EntitySpawnCollection.GetSpawns(gen.Spawns, random);

View File

@@ -4,6 +4,7 @@ using Content.Server.Construction;
using Robust.Shared.CPUJob.JobQueues; using Robust.Shared.CPUJob.JobQueues;
using Content.Server.Decals; using Content.Server.Decals;
using Content.Shared.Construction.EntitySystems; using Content.Shared.Construction.EntitySystems;
using Content.Shared.Maps;
using Content.Shared.Procedural; using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonGenerators; using Content.Shared.Procedural.DungeonGenerators;
using Content.Shared.Procedural.PostGeneration; using Content.Shared.Procedural.PostGeneration;
@@ -27,6 +28,7 @@ public sealed partial class DungeonJob : Job<Dungeon>
private readonly DecalSystem _decals; private readonly DecalSystem _decals;
private readonly DungeonSystem _dungeon; private readonly DungeonSystem _dungeon;
private readonly EntityLookupSystem _lookup; private readonly EntityLookupSystem _lookup;
private readonly TileSystem _tile;
private readonly SharedMapSystem _maps; private readonly SharedMapSystem _maps;
private readonly SharedTransformSystem _transform; private readonly SharedTransformSystem _transform;
private EntityQuery<TagComponent> _tagQuery; private EntityQuery<TagComponent> _tagQuery;
@@ -51,6 +53,7 @@ public sealed partial class DungeonJob : Job<Dungeon>
DecalSystem decals, DecalSystem decals,
DungeonSystem dungeon, DungeonSystem dungeon,
EntityLookupSystem lookup, EntityLookupSystem lookup,
TileSystem tile,
SharedTransformSystem transform, SharedTransformSystem transform,
DungeonConfigPrototype gen, DungeonConfigPrototype gen,
MapGridComponent grid, MapGridComponent grid,
@@ -69,6 +72,7 @@ public sealed partial class DungeonJob : Job<Dungeon>
_decals = decals; _decals = decals;
_dungeon = dungeon; _dungeon = dungeon;
_lookup = lookup; _lookup = lookup;
_tile = tile;
_maps = _entManager.System<SharedMapSystem>(); _maps = _entManager.System<SharedMapSystem>();
_transform = transform; _transform = transform;
_tagQuery = _entManager.GetEntityQuery<TagComponent>(); _tagQuery = _entManager.GetEntityQuery<TagComponent>();

View File

@@ -1,5 +1,6 @@
using System.Numerics; using System.Numerics;
using Content.Shared.Decals; using Content.Shared.Decals;
using Content.Shared.Maps;
using Content.Shared.Procedural; using Content.Shared.Procedural;
using Content.Shared.Random.Helpers; using Content.Shared.Random.Helpers;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
@@ -230,7 +231,7 @@ public sealed partial class DungeonSystem
// but place 1 nanometre off grid and fail the add. // but place 1 nanometre off grid and fail the add.
if (!_maps.TryGetTileRef(gridUid, grid, tilePos, out var tileRef) || tileRef.Tile.IsEmpty) if (!_maps.TryGetTileRef(gridUid, grid, tilePos, out var tileRef) || tileRef.Tile.IsEmpty)
{ {
_maps.SetTile(gridUid, grid, tilePos, _tileDefManager.GetVariantTile(FallbackTileId, _random)); _maps.SetTile(gridUid, grid, tilePos, _tile.GetVariantTile((ContentTileDefinition) _tileDefManager[FallbackTileId], _random.GetRandom()));
} }
var result = _decals.TryAddDecal( var result = _decals.TryAddDecal(

View File

@@ -31,6 +31,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
[Dependency] private readonly AnchorableSystem _anchorable = default!; [Dependency] private readonly AnchorableSystem _anchorable = default!;
[Dependency] private readonly DecalSystem _decals = default!; [Dependency] private readonly DecalSystem _decals = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
@@ -198,6 +199,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
_decals, _decals,
this, this,
_lookup, _lookup,
_tile,
_transform, _transform,
gen, gen,
grid, grid,
@@ -229,6 +231,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
_decals, _decals,
this, this,
_lookup, _lookup,
_tile,
_transform, _transform,
gen, gen,
grid, grid,

View File

@@ -67,7 +67,7 @@ namespace Content.Shared.Maps
/// <summary> /// <summary>
/// This controls what variants the `variantize` command is allowed to use. /// This controls what variants the `variantize` command is allowed to use.
/// </summary> /// </summary>
[DataField("placementVariants")] public float[] PlacementVariants { get; set; } = new [] { 1f }; [DataField("placementVariants")] public float[] PlacementVariants { get; set; } = { 1f };
[DataField("thermalConductivity")] public float ThermalConductivity = 0.04f; [DataField("thermalConductivity")] public float ThermalConductivity = 0.04f;

View File

@@ -25,12 +25,29 @@ public sealed class TileSystem : EntitySystem
/// Returns a weighted pick of a tile variant. /// Returns a weighted pick of a tile variant.
/// </summary> /// </summary>
public byte PickVariant(ContentTileDefinition tile) public byte PickVariant(ContentTileDefinition tile)
{
return PickVariant(tile, _robustRandom.GetRandom());
}
/// <summary>
/// Returns a weighted pick of a tile variant.
/// </summary>
public byte PickVariant(ContentTileDefinition tile, int seed)
{
var rand = new System.Random(seed);
return PickVariant(tile, rand);
}
/// <summary>
/// Returns a weighted pick of a tile variant.
/// </summary>
public byte PickVariant(ContentTileDefinition tile, System.Random random)
{ {
var variants = tile.PlacementVariants; var variants = tile.PlacementVariants;
var sum = variants.Sum(); var sum = variants.Sum();
var accumulated = 0f; var accumulated = 0f;
var rand = _robustRandom.NextFloat() * sum; var rand = random.NextFloat() * sum;
for (byte i = 0; i < variants.Length; ++i) for (byte i = 0; i < variants.Length; ++i)
{ {
@@ -44,6 +61,23 @@ public sealed class TileSystem : EntitySystem
throw new InvalidOperationException($"Invalid weighted variantize tile pick for {tile.ID}!"); throw new InvalidOperationException($"Invalid weighted variantize tile pick for {tile.ID}!");
} }
/// <summary>
/// Returns a tile with a weighted random variant.
/// </summary>
public Tile GetVariantTile(ContentTileDefinition tile, System.Random random)
{
return new Tile(tile.TileId, variant: PickVariant(tile, random));
}
/// <summary>
/// Returns a tile with a weighted random variant.
/// </summary>
public Tile GetVariantTile(ContentTileDefinition tile, int seed)
{
var rand = new System.Random(seed);
return new Tile(tile.TileId, variant: PickVariant(tile, rand));
}
public bool PryTile(Vector2i indices, EntityUid gridId) public bool PryTile(Vector2i indices, EntityUid gridId)
{ {
var grid = Comp<MapGridComponent>(gridId); var grid = Comp<MapGridComponent>(gridId);

View File

@@ -16,6 +16,7 @@ public abstract class SharedBiomeSystem : EntitySystem
[Dependency] protected readonly IPrototypeManager ProtoManager = default!; [Dependency] protected readonly IPrototypeManager ProtoManager = default!;
[Dependency] private readonly ISerializationManager _serManager = default!; [Dependency] private readonly ISerializationManager _serManager = default!;
[Dependency] protected readonly ITileDefinitionManager TileDefManager = default!; [Dependency] protected readonly ITileDefinitionManager TileDefManager = default!;
[Dependency] private readonly TileSystem _tile = default!;
protected const byte ChunkSize = 8; protected const byte ChunkSize = 8;
@@ -158,13 +159,8 @@ public abstract class SharedBiomeSystem : EntitySystem
// Pick a variant tile if they're available as well // Pick a variant tile if they're available as well
if (variantCount > 1) if (variantCount > 1)
{ {
var variantValue = (noise.GetNoise(indices.X * 8, indices.Y * 8, variantCount) + 1f) / 2f; var variantValue = (noise.GetNoise(indices.X * 8, indices.Y * 8, variantCount) + 1f) * 100;
variant = (byte) Pick(variantCount, variantValue); variant = _tile.PickVariant(tileDef, (int) variantValue);
if (variants != null)
{
variant = variants[variant];
}
} }
tile = new Tile(tileDef.TileId, 0, variant); tile = new Tile(tileDef.TileId, 0, variant);

View File

@@ -35,6 +35,7 @@ public sealed class FloorTileSystem : EntitySystem
[Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedStackSystem _stackSystem = default!; [Dependency] private readonly SharedStackSystem _stackSystem = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly TileSystem _tile = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!;
private static readonly Vector2 CheckRange = new(1f, 1f); private static readonly Vector2 CheckRange = new(1f, 1f);
@@ -175,8 +176,8 @@ public sealed class FloorTileSystem : EntitySystem
{ {
_adminLogger.Add(LogType.Tile, LogImpact.Low, $"{ToPrettyString(user):actor} placed tile {_tileDefinitionManager[tileId].Name} at {ToPrettyString(gridUid)} {location}"); _adminLogger.Add(LogType.Tile, LogImpact.Low, $"{ToPrettyString(user):actor} placed tile {_tileDefinitionManager[tileId].Name} at {ToPrettyString(gridUid)} {location}");
// TODO: Proper predicted RNG. var random = new System.Random((int) _timing.CurTick.Value);
var variant = (byte) (_timing.CurTick.Value % ((ContentTileDefinition) _tileDefinitionManager[tileId]).Variants); var variant = _tile.PickVariant((ContentTileDefinition) _tileDefinitionManager[tileId], random);
mapGrid.SetTile(location.Offset(new Vector2(offset, offset)), new Tile(tileId, 0, variant)); mapGrid.SetTile(location.Offset(new Vector2(offset, offset)), new Tile(tileId, 0, variant));
_audio.PlayPredicted(placeSound, location, user); _audio.PlayPredicted(placeSound, location, user);

View File

@@ -70,15 +70,6 @@
# Fill layer # Fill layer
- !type:BiomeTileLayer - !type:BiomeTileLayer
threshold: -1 threshold: -1
variants:
- 0
tile: FloorAsteroidSand
- !type:BiomeTileLayer
threshold: 0.80
noise:
seed: 1
noiseType: OpenSimplex2
frequency: 2
tile: FloorAsteroidSand tile: FloorAsteroidSand
# Grass # Grass
@@ -307,8 +298,6 @@
# Fill basalt # Fill basalt
- !type:BiomeTileLayer - !type:BiomeTileLayer
threshold: -1 threshold: -1
variants:
- 0
tile: FloorBasalt tile: FloorBasalt
# Snow # Snow
@@ -530,15 +519,6 @@
# Fill chromite # Fill chromite
- !type:BiomeTileLayer - !type:BiomeTileLayer
threshold: -1 threshold: -1
variants:
- 0
tile: FloorChromite
- !type:BiomeTileLayer
threshold: 0.25
noise:
seed: 1
noiseType: OpenSimplex2
frequency: 2
tile: FloorChromite tile: FloorChromite
# Caves # Caves
@@ -593,15 +573,6 @@
- !type:BiomeTileLayer - !type:BiomeTileLayer
threshold: -1.0 threshold: -1.0
tile: FloorAsteroidSand tile: FloorAsteroidSand
variants:
- 0
- !type:BiomeTileLayer
threshold: 0.5
noise:
seed: 1
noiseType: OpenSimplex2
frequency: 2
tile: FloorAsteroidSand
# Asteroid # Asteroid
- type: biomeTemplate - type: biomeTemplate
@@ -653,12 +624,3 @@
- !type:BiomeTileLayer - !type:BiomeTileLayer
threshold: -1.0 threshold: -1.0
tile: FloorAsteroidSand tile: FloorAsteroidSand
variants:
- 0
- !type:BiomeTileLayer
threshold: 0.5
noise:
seed: 1
noiseType: OpenSimplex2
frequency: 2
tile: FloorAsteroidSand