Replace all uses of System.Random with IRobustRandom, resolve all System.Random warnings. (#32)

* Remove all uses of System.Random

* Use IRobustRandom in BinomialNumberSelector.Get

* Remove remaining ToolRefinableSystem S.Random inst
This commit is contained in:
Whatstone 2026-06-16 19:38:37 -04:00 • committed by GitHub
parent 6e695c404d
commit f339f58945
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
62 changed files with 150 additions and 223 deletions

View file

@ -30,7 +30,8 @@ namespace Content.Benchmarks
[GlobalSetup]
public void Setup()
{
var random = new Random(3005);
var random = new RobustRandom();
random.SetSeed(3005);
_colors = new (Color, Color)[N];
_output = new Color[N];

View file

@ -97,7 +97,8 @@ public class PvsBenchmark
// Repeatedly move players around so that they "explore" the map and see lots of entities.
// This will populate their PVS data with out-of-view entities.
var rng = new Random(42);
var rng = new RobustRandom();
rng.SetSeed(42);
ShufflePlayers(rng, 100);
_pair.Server.PvsTick(_players);
@ -107,7 +108,7 @@ public class PvsBenchmark
_locations = ents.Select(x => _entMan.GetComponent<TransformComponent>(x).Coordinates).ToArray();
}
private void ShufflePlayers(Random rng, int count)
private void ShufflePlayers(IRobustRandom rng, int count)
{
while (count > 0)
{
@ -116,7 +117,7 @@ public class PvsBenchmark
}
}
private void ShufflePlayers(Random rng)
private void ShufflePlayers(IRobustRandom rng)
{
_pair.Server.PvsTick(_players);

View file

@ -40,7 +40,8 @@ public sealed partial class StampCollection : Container
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var random = new Random(PlacementSeed);
var random = new RobustRandom();
random.SetSeed(PlacementSeed);
var r = (finalSize * 0.5f).Length();
var dtheta = -MathHelper.DegreesToRadians(90);
var theta0 = random.Next(0, 3) * dtheta;

View file

@ -408,7 +408,8 @@ namespace Content.Client.Parallax
private void GenPoints(Image<Rgba32> buffer)
{
var o = PointSize - 1;
var random = new Random(Seed);
var random = new RobustRandom();
random.SetSeed(Seed);
var span = buffer.GetPixelSpan();
for (var i = 0; i < PointCount; i++)
@ -435,7 +436,8 @@ namespace Content.Client.Parallax
private void GenPointsMasked(Image<Rgba32> buffer)
{
var o = PointSize - 1;
var random = new Random(Seed);
var random = new RobustRandom();
random.SetSeed(Seed);
var noise = new FastNoiseLite((int)MaskSeed);
noise.SetFractalType(MaskNoiseType);
noise.SetFractalLacunarity(MaskLacunarity);

View file

@ -1081,7 +1081,9 @@ public sealed partial class AdminVerbSystem
// I would do it now but theres a massive rod rewrite, and I don't wanna poke it for this.
// find reasonable spawn location (use gamerule and find rod?) but respect map not on grid etc etc
var offset = new Random(target.Id).NextAngle().RotateVec(new Vector2(distance, 0));
var random = new RobustRandom() as IRobustRandom;
random.SetSeed(target.Id);
var offset = random.NextAngle().RotateVec(new Vector2(distance, 0));
var spawnCoords = _transformSystem.GetMapCoordinates(target).Offset(offset);
var rod = Spawn(proto, spawnCoords);
// Here we abuse the ChasingWalkComp by making it skip targetting logic and dialling its frequency up

View file

@ -99,7 +99,8 @@ public sealed partial class GatewayGeneratorSystem : EntitySystem
const int MaxOffset = 256;
var tiles = new List<(Vector2i Index, Tile Tile)>();
var seed = _random.Next();
var random = new Random(seed);
var random = new RobustRandom();
random.SetSeed(seed);
var mapUid = _maps.CreateMap();
var gatewayName = _salvage.GetFTLName(_protoManager.Index(PlanetNames), seed);

View file

@ -37,7 +37,7 @@ public sealed partial class PathfindingSystem
/// <summary>
/// Gets a spline path from start to end.
/// </summary>
public SplinePathResult GetSplinePath(SplinePathArgs args, Random random)
public SplinePathResult GetSplinePath(SplinePathArgs args, IRobustRandom random)
{
var start = args.Args.Start;
var end = args.Args.End;

View file

@ -8,7 +8,7 @@ public sealed partial class PathfindingSystem
/// <summary>
/// Widens the path by the specified amount.
/// </summary>
public HashSet<Vector2i> GetWiden(WidenArgs args, Random random)
public HashSet<Vector2i> GetWiden(WidenArgs args, IRobustRandom random)
{
var tiles = new HashSet<Vector2i>(args.Path.Count * 2);
var variance = (args.MaxWiden - args.MinWiden) / 2f + args.MinWiden;

View file

@ -484,7 +484,8 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
// inadvertantly spawn too many near the edges.
var layerProto = ProtoManager.Index<BiomeMarkerLayerPrototype>(layer);
var markerSeed = seed + chunk.X * ChunkSize + chunk.Y + localIdx;
var rand = new Random(markerSeed);
var rand = new RobustRandom();
rand.SetSeed(markerSeed);
var buffer = (int)(layerProto.Radius / 2f);
var bounds = new Box2i(chunk + buffer, chunk + layerProto.Size - buffer);
var count = (int)(bounds.Area / (layerProto.Radius * layerProto.Radius));
@ -567,7 +568,7 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
bool forced,
Box2i bounds,
int count,
Random rand,
IRobustRandom rand,
out Dictionary<Vector2i, string?> spawnSet,
out HashSet<EntityUid> existingEnts,
bool emptyTiles = true)
@ -638,7 +639,8 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
// While we have remaining tiles keep iterating
while (groupSize > 0 && remainingTiles.Count > 0)
{
var startNode = rand.PickAndTake(remainingTiles);
var startNode = rand.Pick(remainingTiles);
remainingTiles.Remove(startNode);
frontier.Clear();
frontier.Add(startNode);

View file

@ -1,6 +1,5 @@
using System.Linq;
using System.Threading.Tasks;
using Content.Server.NodeContainer;
using Content.Shared.NodeContainer;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
@ -13,7 +12,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="AutoCablingDunGen"/>
/// </summary>
private async Task PostGen(AutoCablingDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(AutoCablingDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
// There's a lot of ways you could do this.
// For now we'll just connect every LV cable in the dungeon.

View file

@ -1,10 +1,10 @@
using System.Threading.Tasks;
using Content.Server.Parallax;
using Content.Shared.Maps;
using Content.Shared.Parallax.Biomes;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Map;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Procedural.DungeonJob;
@ -14,7 +14,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="BiomeDunGen"/>
/// </summary>
private async Task PostGen(BiomeDunGen dunGen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(BiomeDunGen dunGen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
if (!_prototype.Resolve(dunGen.BiomeTemplate, out var indexedBiome))
return;

View file

@ -6,6 +6,7 @@ using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Random.Helpers;
using Robust.Shared.Map;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Procedural.DungeonJob;
@ -15,7 +16,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="BiomeMarkerLayerDunGen"/>
/// </summary>
private async Task PostGen(BiomeMarkerLayerDunGen dunGen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(BiomeMarkerLayerDunGen dunGen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
// If we're adding biome then disable it and just use for markers.
if (_entManager.EnsureComponent(_gridUid, out BiomeComponent biomeComp))

View file

@ -3,6 +3,7 @@ using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Map;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Procedural.DungeonJob;
@ -12,7 +13,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="BoundaryWallDunGen"/>
/// </summary>
private async Task PostGen(BoundaryWallDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(BoundaryWallDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var tileDef = _tileDefManager[gen.Tile];
var tiles = new List<(Vector2i Index, Tile Tile)>(dungeon.RoomExteriorTiles.Count);

View file

@ -10,7 +10,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="CornerClutterDunGen"/>
/// </summary>
private async Task PostGen(CornerClutterDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(CornerClutterDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var contentsTable = _prototype.Index(gen.Contents);

View file

@ -4,6 +4,7 @@ using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -12,7 +13,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="CorridorDunGen"/>
/// </summary>
private async Task PostGen(CorridorDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(CorridorDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var entrances = new List<Vector2i>(dungeon.Rooms.Count);

View file

@ -1,7 +1,6 @@
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
@ -12,7 +11,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="CorridorClutterDunGen"/>
/// </summary>
private async Task PostGen(CorridorClutterDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(CorridorClutterDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var physicsQuery = _entManager.GetEntityQuery<PhysicsComponent>();
var count = (int) Math.Ceiling(dungeon.CorridorTiles.Count * gen.Chance);

View file

@ -4,6 +4,7 @@ using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Collections;
using Robust.Shared.Physics.Components;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Procedural.DungeonJob;
@ -13,7 +14,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="CorridorDecalSkirtingDunGen"/>
/// </summary>
private async Task PostGen(CorridorDecalSkirtingDunGen decks, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(CorridorDecalSkirtingDunGen decks, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var directions = new ValueList<DirectionFlag>(4);
var pocketDirections = new ValueList<Direction>(4);

View file

@ -5,6 +5,7 @@ using Content.Shared.Procedural;
using Content.Shared.Procedural.Distance;
using Content.Shared.Procedural.DungeonGenerators;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -25,7 +26,7 @@ public sealed partial class DungeonJob
NoiseDistanceDunGen dungen,
HashSet<Vector2i> reservedTiles,
int seed,
Random random)
IRobustRandom random)
{
var tiles = new List<(Vector2i, Tile)>();
var matrix = Matrix3Helpers.CreateTranslation(position);

View file

@ -2,7 +2,6 @@ using System.Numerics;
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonGenerators;
using Content.Shared.Whitelist;
using Robust.Shared.Map;
using Robust.Shared.Random;
using Robust.Shared.Utility;
@ -14,7 +13,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="PrefabDunGen"/>
/// </summary>
private async Task<Dungeon> GeneratePrefabDunGen(Vector2i position, PrefabDunGen prefab, HashSet<Vector2i> reservedTiles, Random random)
private async Task<Dungeon> GeneratePrefabDunGen(Vector2i position, PrefabDunGen prefab, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var preset = prefab.Presets[random.Next(prefab.Presets.Count)];
var gen = _prototype.Index(preset);
@ -297,7 +296,7 @@ public sealed partial class DungeonJob
return dungeon;
}
private void SetDungeonEntrance(Dungeon dungeon, DungeonRoom room, HashSet<Vector2i> reservedTiles, Random random)
private void SetDungeonEntrance(Dungeon dungeon, DungeonRoom room, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
// TODO: Move to dungeonsystem.

View file

@ -1,7 +1,6 @@
using System.Threading.Tasks;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonGenerators;
using Content.Shared.Procedural.PostGeneration;
using Robust.Shared.Map;
using Robust.Shared.Random;
@ -12,7 +11,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="ReplaceTileDunGen"/>
/// </summary>
private async Task GenerateTileReplacementDunGen(ReplaceTileDunGen gen, List<Dungeon> dungeons, HashSet<Vector2i> reservedTiles, Random random)
private async Task GenerateTileReplacementDunGen(ReplaceTileDunGen gen, List<Dungeon> dungeons, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var replacements = new List<(Vector2i Index, Tile Tile)>();

View file

@ -2,7 +2,6 @@ using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -12,7 +11,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="DungeonEntranceDunGen"/>
/// </summary>
private async Task PostGen(DungeonEntranceDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(DungeonEntranceDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var rooms = new List<DungeonRoom>(dungeon.Rooms);
var roomTiles = new List<Vector2i>();

View file

@ -3,11 +3,11 @@ using System.Threading.Tasks;
using Content.Server.Ghost.Roles.Components;
using Content.Server.NPC.Systems;
using Content.Shared.EntityTable;
using Content.Shared.EntityTable.EntitySelectors;
using Content.Shared.Physics;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonLayers;
using Robust.Shared.Collections;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -17,7 +17,7 @@ public sealed partial class DungeonJob
EntityTableDunGen gen,
List<Dungeon> dungeons,
HashSet<Vector2i> reservedTiles,
Random random)
IRobustRandom random)
{
var count = random.Next(gen.MinCount, gen.MaxCount + 1);
var npcs = _entManager.System<NPCSystem>();

View file

@ -2,9 +2,9 @@ using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Collections;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -13,7 +13,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="EntranceFlankDunGen"/>
/// </summary>
private async Task PostGen(EntranceFlankDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(EntranceFlankDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var tiles = new List<(Vector2i Index, Tile)>();
var tileDef = _tileDefManager[gen.Tile];

View file

@ -1,5 +1,4 @@
using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.NPC;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonGenerators;
@ -13,7 +12,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="ExteriorDunGen"/>
/// </summary>
private async Task<List<Dungeon>> GenerateExteriorDungen(Vector2i position, ExteriorDunGen dungen, HashSet<Vector2i> reservedTiles, Random random)
private async Task<List<Dungeon>> GenerateExteriorDungen(Vector2i position, ExteriorDunGen dungen, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
DebugTools.Assert(_grid.ChunkCount > 0);
@ -49,7 +48,9 @@ public sealed partial class DungeonJob
var config = _prototype.Index(dungen.Proto);
var nextSeed = random.Next();
var dungeons = await GetDungeons(dungeonSpawn.Value, config, config.Layers, reservedTiles, nextSeed, new Random(nextSeed));
var newRandom = new RobustRandom();
newRandom.SetSeed(nextSeed);
var dungeons = await GetDungeons(dungeonSpawn.Value, config, config.Layers, reservedTiles, nextSeed, newRandom);
return dungeons;
}

View file

@ -3,9 +3,7 @@ using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -24,7 +22,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="ExternalWindowDunGen"/>
/// </summary>
private async Task PostGen(ExternalWindowDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(ExternalWindowDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
// Iterate every tile with N chance to spawn windows on that wall per cardinal dir.
var chance = 0.25 / 3f;

View file

@ -3,7 +3,6 @@ using Content.Shared.Procedural;
using Content.Shared.Tag;
using Robust.Shared.Collections;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
namespace Content.Server.Procedural.DungeonJob;

View file

@ -1,9 +1,8 @@
using System.Numerics;
using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -12,7 +11,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="InternalWindowDunGen"/>
/// </summary>
private async Task PostGen(InternalWindowDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(InternalWindowDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
// Iterate every room and check if there's a gap beyond it that leads to another room within N tiles
// If so then consider windows

View file

@ -2,8 +2,7 @@ using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Map.Components;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -12,7 +11,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="JunctionDunGen"/>
/// </summary>
private async Task PostGen(JunctionDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(JunctionDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var tileDef = _tileDefManager[gen.Tile];
var contents = _prototype.Index(gen.Contents);

View file

@ -3,7 +3,7 @@ using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Procedural.DungeonJob;
@ -13,7 +13,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="MiddleConnectionDunGen"/>
/// </summary>
private async Task PostGen(MiddleConnectionDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(MiddleConnectionDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
// Grab all of the room bounds
// Then, work out connections between them

View file

@ -1,11 +1,9 @@
using System.Threading.Tasks;
using Content.Server.Ghost.Roles.Components;
using Content.Server.NPC.Components;
using Content.Server.NPC.Systems;
using Content.Shared.Physics;
using Content.Shared.Procedural;
using Content.Shared.Procedural.DungeonLayers;
using Content.Shared.Storage;
using Robust.Shared.Collections;
using Robust.Shared.Random;
@ -19,7 +17,7 @@ public sealed partial class DungeonJob
private async Task PostGen(
MobsDunGen gen,
Dungeon dungeon,
Random random)
IRobustRandom random)
{
var availableRooms = new ValueList<DungeonRoom>();
availableRooms.AddRange(dungeon.Rooms);

View file

@ -19,7 +19,7 @@ public sealed partial class DungeonJob
NoiseDunGen dungen,
HashSet<Vector2i> reservedTiles,
int seed,
Random random)
IRobustRandom random)
{
var tiles = new List<(Vector2i, Tile)>();
var matrix = Matrix3Helpers.CreateTranslation(position);

View file

@ -17,7 +17,7 @@ public sealed partial class DungeonJob
OreDunGen gen,
List<Dungeon> dungeons,
HashSet<Vector2i> reservedTiles,
Random random)
IRobustRandom random)
{
foreach (var dungeon in dungeons)
{

View file

@ -2,8 +2,8 @@ using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Map;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -12,7 +12,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="RoomEntranceDunGen"/>
/// </summary>
private async Task PostGen(RoomEntranceDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(RoomEntranceDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var setTiles = new List<(Vector2i, Tile)>();
var tileDef = _tileDefManager[gen.Tile];

View file

@ -17,7 +17,7 @@ public sealed partial class DungeonJob
SplineDungeonConnectorDunGen gen,
List<Dungeon> dungeons,
HashSet<Vector2i> reservedTiles,
Random random)
IRobustRandom random)
{
// NOOP
if (dungeons.Count <= 1)

View file

@ -2,7 +2,6 @@ using System.Threading.Tasks;
using Content.Shared.Maps;
using Content.Shared.Procedural;
using Content.Shared.Procedural.PostGeneration;
using Content.Shared.Storage;
using Robust.Shared.Random;
namespace Content.Server.Procedural.DungeonJob;
@ -12,7 +11,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="WallMountDunGen"/>
/// </summary>
private async Task PostGen(WallMountDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(WallMountDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var checkedTiles = new HashSet<Vector2i>();
var allExterior = new HashSet<Vector2i>(dungeon.CorridorExteriorTiles);

View file

@ -15,7 +15,7 @@ public sealed partial class DungeonJob
/// <summary>
/// <see cref="WormCorridorDunGen"/>
/// </summary>
private async Task PostGen(WormCorridorDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, Random random)
private async Task PostGen(WormCorridorDunGen gen, Dungeon dungeon, HashSet<Vector2i> reservedTiles, IRobustRandom random)
{
var networks = new List<(Vector2i Start, HashSet<Vector2i> Network)>();

View file

@ -1,8 +1,6 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Content.Server.Decals;
using Content.Server.NPC.Components;
using Content.Server.NPC.HTN;
using Content.Server.NPC.Systems;
using Content.Server.Shuttles.Systems;
@ -22,7 +20,6 @@ using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using IDunGenLayer = Content.Shared.Procedural.IDunGenLayer;
namespace Content.Server.Procedural.DungeonJob;
@ -118,7 +115,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
List<IDunGenLayer> layers,
HashSet<Vector2i> reservedTiles,
int seed,
Random random,
IRobustRandom random,
List<Dungeon>? existing = null)
{
var dungeons = new List<Dungeon>();
@ -133,7 +130,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
for (var i = 0; i < count; i++)
{
position += random.NextPolarVector2(config.MinOffset, config.MaxOffset).Floored();
position += random.NextVector2(config.MinOffset, config.MaxOffset).Floored();
foreach (var layer in layers)
{
@ -163,8 +160,9 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
{
_sawmill.Info($"Generating dungeon {_gen} with seed {_seed} on {_entManager.ToPrettyString(_gridUid)}");
_grid.CanSplit = false;
var random = new Random(_seed);
var position = (_position + random.NextPolarVector2(_gen.MinOffset, _gen.MaxOffset)).Floored();
var random = new RobustRandom() as IRobustRandom;
random.SetSeed(_seed);
var position = (_position + random.NextVector2(_gen.MinOffset, _gen.MaxOffset)).Floored();
// Tiles we can no longer generate on due to being reserved elsewhere.
var reservedTiles = new HashSet<Vector2i>();
@ -203,7 +201,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
IDunGenLayer layer,
HashSet<Vector2i> reservedTiles,
int seed,
Random random)
IRobustRandom random)
{
_sawmill.Debug($"Doing postgen {layer.GetType()} for {_gen} with seed {_seed}");
@ -284,7 +282,7 @@ public sealed partial class DungeonJob : Job<List<Dungeon>>
break;
case PrototypeDunGen prototypo:
var groupConfig = _prototype.Index(prototypo.Proto);
position = (position + random.NextPolarVector2(groupConfig.MinOffset, groupConfig.MaxOffset)).Floored();
position = (position + random.NextVector2(groupConfig.MinOffset, groupConfig.MaxOffset)).Floored();
switch (prototypo.InheritDungeons)
{

View file

@ -1,12 +1,13 @@
using Content.Shared.NPC;
using Robust.Shared.Collections;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Server.Procedural;
public sealed partial class DungeonSystem
{
public List<(Vector2i Start, Vector2i End)> MinimumSpanningTree(List<Vector2i> tiles, System.Random random)
public List<(Vector2i Start, Vector2i End)> MinimumSpanningTree(List<Vector2i> tiles, IRobustRandom random)
{
// Generate connections between all rooms.
var connections = new Dictionary<Vector2i, List<(Vector2i Tile, float Distance)>>(tiles.Count);

View file

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

View file

@ -87,7 +87,8 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
var mapUid = _map.CreateMap(out var mapId, runMapInit: false);
MetaDataComponent? metadata = null;
var grid = _entManager.EnsureComponent<MapGridComponent>(mapUid);
var random = new Random(_missionParams.Seed);
var random = new RobustRandom();
random.SetSeed(_missionParams.Seed);
var destComp = _entManager.AddComponent<FTLDestinationComponent>(mapUid);
destComp.BeaconsOnly = true;
destComp.RequireCoordinateDisk = true;
@ -284,7 +285,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
return true;
}
private async Task SpawnRandomEntry(Entity<MapGridComponent> grid, IBudgetEntry entry, Dungeon dungeon, Random random)
private async Task SpawnRandomEntry(Entity<MapGridComponent> grid, IBudgetEntry entry, Dungeon dungeon, IRobustRandom random)
{
await SuspendIfOutOfTime();

View file

@ -59,14 +59,23 @@ public sealed partial class MeteorSwarmSystem : GameRuleSystem<MeteorSwarmCompon
var center = playableArea.Center;
IRobustRandom random;
if (component.NonDirectional)
{
random = RobustRandom;
}
else
{
random = new RobustRandom();
random.SetSeed(uid.Id);
}
var meteorsToSpawn = component.MeteorsPerWave.Next(RobustRandom);
for (var i = 0; i < meteorsToSpawn; i++)
{
var spawnProto = RobustRandom.Pick(component.Meteors);
var angle = component.NonDirectional
? RobustRandom.NextAngle()
: new Random(uid.Id).NextAngle();
var angle = random.NextAngle();
var offset = angle.RotateVec(new Vector2((maximumDistance - minimumDistance) * RobustRandom.NextFloat() + minimumDistance, 0));

View file

@ -22,11 +22,6 @@ public partial struct MinMax
return random.Next(Min, Max + 1);
}
public readonly int Next(System.Random random)
{
return random.Next(Min, Max + 1);
}
public static implicit operator MinMax((int Min, int Max) tuple)
{
return new MinMax(tuple.Min, tuple.Max);

View file

@ -1,5 +1,5 @@
using System.Linq;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.EntitySelectors;
@ -11,7 +11,7 @@ public sealed partial class AllSelector : EntityTableSelector
[DataField(required: true)]
public List<EntityTableSelector> Children;
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand,
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(IRobustRandom rand,
IEntityManager entMan,
IPrototypeManager proto,
EntityTableContext ctx)

View file

@ -1,5 +1,6 @@
using Content.Shared.EntityTable.ValueSelector;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.EntitySelectors;
@ -16,7 +17,7 @@ public sealed partial class EntSelector : EntityTableSelector
[DataField]
public NumberSelector Amount = new ConstantNumberSelector(1);
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand,
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(IRobustRandom rand,
IEntityManager entMan,
IPrototypeManager proto,
EntityTableContext ctx)

View file

@ -26,7 +26,7 @@ public abstract partial class EntityTableSelector
/// A simple chance that the selector will run.
/// </summary>
[DataField]
public double Prob = 1;
public float Prob = 1;
/// <summary>
/// A list of conditions that must evaluate to 'true' for the selector to apply.
@ -41,7 +41,7 @@ public abstract partial class EntityTableSelector
[DataField]
public bool RequireAll = true;
public IEnumerable<EntProtoId> GetSpawns(System.Random rand,
public IEnumerable<EntProtoId> GetSpawns(IRobustRandom rand,
IEntityManager entMan,
IPrototypeManager proto,
EntityTableContext ctx)
@ -112,7 +112,7 @@ public abstract partial class EntityTableSelector
}
}
protected abstract IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand,
protected abstract IEnumerable<EntProtoId> GetSpawnsImplementation(IRobustRandom rand,
IEntityManager entMan,
IPrototypeManager proto,
EntityTableContext ctx);

View file

@ -1,6 +1,7 @@
using System.Linq;
using Content.Shared.Random.Helpers;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.EntitySelectors;
@ -12,7 +13,7 @@ public sealed partial class GroupSelector : EntityTableSelector
[DataField(required: true)]
public List<EntityTableSelector> Children = new();
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand,
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(IRobustRandom rand,
IEntityManager entMan,
IPrototypeManager proto,
EntityTableContext ctx)

View file

@ -1,4 +1,5 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.EntitySelectors;
@ -11,7 +12,7 @@ public sealed partial class NestedSelector : EntityTableSelector
[DataField(required: true)]
public ProtoId<EntityTablePrototype> TableId;
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand,
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(IRobustRandom rand,
IEntityManager entMan,
IPrototypeManager proto,
EntityTableContext ctx)

View file

@ -1,4 +1,5 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.EntitySelectors;
@ -7,7 +8,7 @@ namespace Content.Shared.EntityTable.EntitySelectors;
/// </summary>
public sealed partial class NoneSelector : EntityTableSelector
{
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(System.Random rand,
protected override IEnumerable<EntProtoId> GetSpawnsImplementation(IRobustRandom rand,
IEntityManager entMan,
IPrototypeManager proto,
EntityTableContext ctx)

View file

@ -11,18 +11,18 @@ public sealed partial class EntityTableSystem : EntitySystem
[Dependency] private IPrototypeManager _prototypeManager = default!;
[Dependency] private IRobustRandom _random = default!;
public IEnumerable<EntProtoId> GetSpawns(EntityTablePrototype entTableProto, System.Random? rand = null, EntityTableContext? ctx = null)
public IEnumerable<EntProtoId> GetSpawns(EntityTablePrototype entTableProto, IRobustRandom? rand = null, EntityTableContext? ctx = null)
{
// convenient
return GetSpawns(entTableProto.Table, rand, ctx);
}
public IEnumerable<EntProtoId> GetSpawns(EntityTableSelector? table, System.Random? rand = null, EntityTableContext? ctx = null)
public IEnumerable<EntProtoId> GetSpawns(EntityTableSelector? table, IRobustRandom? rand = null, EntityTableContext? ctx = null)
{
if (table == null)
return new List<EntProtoId>();
rand ??= _random.GetRandom();
rand ??= _random;
ctx ??= new EntityTableContext();
return table.GetSpawns(rand, EntityManager, _prototypeManager, ctx);
}

View file

@ -22,14 +22,13 @@ public sealed partial class BinomialNumberSelector : NumberSelector
[DataField]
public float Chance = .5f;
public override int Get(System.Random rand)
public override int Get(IRobustRandom rand)
{
var random = IoCManager.Resolve<IRobustRandom>();
int count = 0;
for (int i = 0; i < Trials; i++)
{
if (random.Prob(Chance))
if (rand.Prob(Chance))
count++;
}
return count;

View file

@ -1,3 +1,5 @@
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.ValueSelector;
/// <summary>
@ -13,7 +15,7 @@ public sealed partial class ConstantNumberSelector : NumberSelector
Value = value;
}
public override int Get(System.Random rand)
public override int Get(IRobustRandom rand)
{
return Value;
}

View file

@ -1,5 +1,6 @@
using Content.Shared.EntityTable.EntitySelectors;
using JetBrains.Annotations;
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.ValueSelector;
@ -9,7 +10,7 @@ namespace Content.Shared.EntityTable.ValueSelector;
[ImplicitDataDefinitionForInheritors, UsedImplicitly(ImplicitUseTargetFlags.WithInheritors)]
public abstract partial class NumberSelector
{
public abstract int Get(System.Random rand);
public abstract int Get(IRobustRandom rand);
/// <summary>
/// Odds of occurrence

View file

@ -1,3 +1,5 @@
using Robust.Shared.Random;
namespace Content.Shared.EntityTable.ValueSelector;
/// <summary>
@ -13,7 +15,7 @@ public sealed partial class RangeNumberSelector : NumberSelector
Range = range;
}
public override int Get(System.Random rand)
public override int Get(IRobustRandom rand)
{
// rand.Next() is inclusive on the first number and exclusive on the second number,
// so we add 1 to the second number.

View file

@ -105,7 +105,7 @@ public sealed partial class TileSystem : EntitySystem
/// </summary>
public byte PickVariant(ContentTileDefinition tile)
{
return PickVariant(tile, _robustRandom.GetRandom());
return PickVariant(tile, _robustRandom);
}
/// <summary>
@ -113,14 +113,15 @@ public sealed partial class TileSystem : EntitySystem
/// </summary>
public byte PickVariant(ContentTileDefinition tile, int seed)
{
var rand = new System.Random(seed);
var rand = new RobustRandom();
rand.SetSeed(seed);
return PickVariant(tile, rand);
}
/// <summary>
/// Returns a weighted pick of a tile variant.
/// </summary>
public byte PickVariant(ContentTileDefinition tile, System.Random random)
public byte PickVariant(ContentTileDefinition tile, IRobustRandom random)
{
var variants = tile.PlacementVariants;
@ -143,7 +144,7 @@ public sealed partial class TileSystem : EntitySystem
/// <summary>
/// Returns a tile with a weighted random variant.
/// </summary>
public Tile GetVariantTile(ContentTileDefinition tile, System.Random random)
public Tile GetVariantTile(ContentTileDefinition tile, IRobustRandom random)
{
return new Tile(tile.TileId, variant: PickVariant(tile, random));
}
@ -153,7 +154,8 @@ public sealed partial class TileSystem : EntitySystem
/// </summary>
public Tile GetVariantTile(ContentTileDefinition tile, int seed)
{
var rand = new System.Random(seed);
var rand = new RobustRandom();
rand.SetSeed(seed);
return new Tile(tile.TileId, variant: PickVariant(tile, rand));
}

View file

@ -14,7 +14,7 @@ public sealed partial class WallMountDunGen : IDunGenLayer
/// Chance per free tile to spawn a wallmount.
/// </summary>
[DataField]
public double Prob = 0.1;
public float Prob = 0.1f;
[DataField(required: true)]
public ProtoId<ContentTileDefinition> Tile;

View file

@ -23,28 +23,6 @@ namespace Content.Shared.Random.Helpers
return Loc.GetString(prototype.Values[index]);
}
public static string Pick(this IWeightedRandomPrototype prototype, System.Random random)
{
var picks = prototype.Weights;
var sum = picks.Values.Sum();
var accumulated = 0f;
var rand = random.NextFloat() * sum;
foreach (var (key, weight) in picks)
{
accumulated += weight;
if (accumulated >= rand)
{
return key;
}
}
// Shouldn't happen
throw new InvalidOperationException($"Invalid weighted pick for {prototype.ID}!");
}
public static string Pick(this IWeightedRandomPrototype prototype, IRobustRandom? random = null)
{
IoCManager.Resolve(ref random);
@ -109,7 +87,7 @@ namespace Content.Shared.Random.Helpers
return true;
}
public static T Pick<T>(Dictionary<T, float> weights, System.Random random)
public static T Pick<T>(Dictionary<T, float> weights, IRobustRandom random)
where T : notnull
{
var sum = weights.Values.Sum();
@ -214,7 +192,7 @@ namespace Content.Shared.Random.Helpers
// TODO: REPLACE ALL OF THIS WITH PREDICTED RANDOM WHEN ENGINE PR IS MERGED
/// <summary>
/// Creates an instance of System.Random that will be the same for both the server and client.
/// Creates an instance of IRobustRandom that will be the same for both the server and client.
/// This allows for the client and server to roll the same results when determining things randomly, preventing mispredictions.
/// We generate a unique seed by getting 2-3 unique but predictable integers into a Hashcode.
/// </summary>
@ -225,10 +203,12 @@ namespace Content.Shared.Random.Helpers
/// <param name="netEnt2">An optional relevant net entity to our seed.
/// Typically used if we have an entity checking random potentially multiple times per tick, to ensure we get a unique seed each time.
/// This entity should not be the same entity as <see cref="netEnt"/>.</param>
public static System.Random PredictedRandom(IGameTiming timing, NetEntity netEnt, NetEntity? netEnt2 = null)
public static IRobustRandom PredictedRandom(IGameTiming timing, NetEntity netEnt, NetEntity? netEnt2 = null)
{
var seed = HashCodeCombine((int)timing.CurTick.Value, netEnt.Id, netEnt2?.Id ?? 0);
return new System.Random(seed);
var random = new RobustRandom();
random.SetSeed(seed);
return random;
}
/// <summary>

View file

@ -5,7 +5,7 @@ namespace Content.Shared.Random;
public sealed class RandomSystem : EntitySystem
{
public IBudgetEntry? GetBudgetEntry(ref float budget, ref float probSum, IList<IBudgetEntry> entries, System.Random random)
public IBudgetEntry? GetBudgetEntry(ref float budget, ref float probSum, IList<IBudgetEntry> entries, IRobustRandom random)
{
DebugTools.Assert(budget > 0f);
@ -39,7 +39,7 @@ public sealed class RandomSystem : EntitySystem
/// <summary>
/// Gets a random entry based on each entry having a different probability.
/// </summary>
public IProbEntry GetProbEntry(IEnumerable<IProbEntry> entries, float probSum, System.Random random)
public IProbEntry GetProbEntry(IEnumerable<IProbEntry> entries, float probSum, IRobustRandom random)
{
var value = random.NextFloat() * probSum;

View file

@ -40,14 +40,15 @@ public abstract partial class SharedSalvageSystem
public ISalvageMagnetOffering GetSalvageOffering(int seed)
{
var rand = new System.Random(seed);
var rand = new RobustRandom();
rand.SetSeed(seed);
var type = SharedRandomExtensions.Pick(_offeringWeights, rand);
switch (type)
{
case AsteroidOffering:
var configId = _asteroidConfigs[rand.Next(_asteroidConfigs.Count)];
var configProto =_proto.Index(configId);
var configProto = _proto.Index(configId);
var layers = new Dictionary<string, int>();
var config = new DungeonConfig

View file

@ -3,15 +3,11 @@ using Content.Shared.CCVar;
using Content.Shared.Dataset;
using Content.Shared.Procedural;
using Content.Shared.Procedural.Loot;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
using Content.Shared.Salvage.Expeditions;
using Content.Shared.Salvage.Expeditions.Modifiers;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.Salvage;
@ -27,7 +23,8 @@ public abstract partial class SharedSalvageSystem : EntitySystem
public string GetFTLName(LocalizedDatasetPrototype dataset, int seed)
{
var random = new System.Random(seed);
var random = new RobustRandom();
random.SetSeed(seed);
return $"{Loc.GetString(dataset.Values[random.Next(dataset.Values.Count)])}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
}
@ -35,7 +32,8 @@ public abstract partial class SharedSalvageSystem : EntitySystem
{
// This is on shared to ensure the client display for missions and what the server generates are consistent
var modifierBudget = difficulty.ModifierBudget;
var rand = new System.Random(seed);
var rand = new RobustRandom();
rand.SetSeed(seed);
// Run budget in order of priority
// - Biome
@ -73,7 +71,7 @@ public abstract partial class SharedSalvageSystem : EntitySystem
return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods);
}
public T GetBiomeMod<T>(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod
public T GetBiomeMod<T>(string biome, IRobustRandom rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod
{
var mods = _proto.EnumeratePrototypes<T>().ToList();
mods.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal));
@ -92,7 +90,7 @@ public abstract partial class SharedSalvageSystem : EntitySystem
throw new InvalidOperationException();
}
public T GetMod<T>(System.Random rand, ref float rating) where T : class, IPrototype, ISalvageMod
public T GetMod<T>(IRobustRandom rand, ref float rating) where T : class, IPrototype, ISalvageMod
{
var mods = _proto.EnumeratePrototypes<T>().ToList();
mods.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal));

View file

@ -82,12 +82,6 @@ public static class EntitySpawnCollection
return GetSpawns(protoManager.Index(proto).Entries, random);
}
public static List<string?> GetSpawns(ProtoId<EntitySpawnEntryPrototype> proto, System.Random random, IPrototypeManager? protoManager = null)
{
IoCManager.Resolve(ref protoManager);
return GetSpawns(protoManager.Index(proto).Entries, random);
}
/// <summary>
/// Using a collection of entity spawn entries, picks a random list of entity prototypes to spawn from that collection.
/// </summary>
@ -157,71 +151,6 @@ public static class EntitySpawnCollection
return spawned;
}
public static List<string?> GetSpawns(IEnumerable<EntitySpawnEntry> entries,
System.Random random)
{
var spawned = new List<string?>();
var ungrouped = CollectOrGroups(entries, out var orGroupedSpawns);
foreach (var entry in ungrouped)
{
// Check random spawn
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (entry.SpawnProbability != 1f && !random.Prob(entry.SpawnProbability))
continue;
var amount = (int) entry.GetAmount(random);
for (var i = 0; i < amount; i++)
{
spawned.Add(entry.PrototypeId);
}
}
// Handle OrGroup spawns
foreach (var spawnValue in orGroupedSpawns)
{
// For each group use the added cumulative probability to roll a double in that range
var diceRoll = random.NextDouble() * spawnValue.CumulativeProbability;
// Add the entry's spawn probability to this value, if equals or lower, spawn item, otherwise continue to next item.
var cumulative = 0.0;
foreach (var entry in spawnValue.Entries)
{
cumulative += entry.SpawnProbability;
if (diceRoll > cumulative)
continue;
// Dice roll succeeded, add item and break loop
var amount = (int) entry.GetAmount(random);
for (var i = 0; i < amount; i++)
{
spawned.Add(entry.PrototypeId);
}
break;
}
}
return spawned;
}
public static double GetAmount(this EntitySpawnEntry entry, System.Random random, bool getAverage = false)
{
// Max amount is less or equal than amount, so just return the amount
if (entry.MaxAmount <= entry.Amount)
return entry.Amount;
// If we want the average, just calculate the expected amount
if (getAverage)
return (entry.Amount + entry.MaxAmount) / 2.0;
// Otherwise get a random value in between
return random.Next(entry.Amount, entry.MaxAmount);
}
/// <summary>
/// Collects all entries that belong together in an OrGroup, and then returns the leftover ungrouped entries.
/// </summary>

View file

@ -17,6 +17,7 @@ using Robust.Shared.Physics;
using Robust.Shared.Physics.Components;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Shared.Tiles;
@ -195,8 +196,9 @@ public sealed partial class FloorTileSystem : EntitySystem
{
_adminLogger.Add(LogType.Tile, LogImpact.Low, $"{ToPrettyString(user):actor} placed tile {_tileDefinitionManager[tileId].Name} at {ToPrettyString(gridUid)} {location}");
var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileId];
var random = new System.Random((int)_timing.CurTick.Value);
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tileId];
var random = new RobustRandom();
random.SetSeed((int)_timing.CurTick.Value);
var variant = _tile.PickVariant(tileDef, random);
var tileRef = _map.GetTileRef(gridUid, mapGrid, location.Offset(new Vector2(offset, offset)));

View file

@ -147,7 +147,8 @@ public sealed partial class ToolRefinablSystem : EntitySystem
{
// TODO: Use RandomPredicted https://github.com/space-wizards/RobustToolbox/pull/5849
var rndSeed = SharedRandomExtensions.HashCodeCombine((int)_gameTiming.CurTick.Value, args.User.Id, uid.Id);
var rng = new System.Random(rndSeed);
var rng = new RobustRandom();
rng.SetSeed(rndSeed);
SpawnRefinement(component.RefineResult, uid, rng);
}
@ -158,7 +159,7 @@ public sealed partial class ToolRefinablSystem : EntitySystem
_destructible.DestroyEntity(uid);
}
private void SpawnRefinement(List<EntitySpawnEntry> spawnList, EntityUid source, System.Random rng)
private void SpawnRefinement(List<EntitySpawnEntry> spawnList, EntityUid source, IRobustRandom rng)
{
var spawns = EntitySpawnCollection.GetSpawns(spawnList, rng);
var spawned = new List<EntityUid>(spawns.Count);
@ -169,7 +170,7 @@ public sealed partial class ToolRefinablSystem : EntitySystem
if (!_container.IsEntityOrParentInContainer(refineResultUid))
{
var randVect = rng.NextPolarVector2(2.0f, 2.5f);
var randVect = rng.NextVector2(2.0f, 2.5f);
_physics.SetLinearVelocity(refineResultUid, randVect);
}
}