Files
tbd-station-14/Content.Server/Worldgen/Tools/EntitySpawnCollectionCache.cs
Moony e91fc652a3 Dynamic space world generation and debris. (#15120)
* World generation (squash)

* Test fixes.

* command

* o

* Access cleanup.

* Documentation touchups.

* Use a prototype serializer for BiomeSelectionComponent

* Struct enumerator in SimpleFloorPlanPopulatorSystem

* Safety margins around PoissonDiskSampler, cookie acquisition methodologies

* Struct enumerating PoissonDiskSampler; internal side

* Struct enumerating PoissonDiskSampler: Finish it

* Update WorldgenConfigSystem.cs

awa

---------

Co-authored-by: moonheart08 <moonheart08@users.noreply.github.com>
Co-authored-by: 20kdc <asdd2808@gmail.com>
2023-05-16 06:36:45 -05:00

97 lines
3.6 KiB
C#

using System.Linq;
using Content.Shared.Storage;
using Robust.Shared.Random;
namespace Content.Server.Worldgen.Tools;
/// <summary>
/// A faster version of EntitySpawnCollection that requires caching to work.
/// </summary>
public sealed class EntitySpawnCollectionCache
{
[ViewVariables] private readonly Dictionary<string, OrGroup> _orGroups = new();
public EntitySpawnCollectionCache(IEnumerable<EntitySpawnEntry> entries)
{
// collect groups together, create singular items that pass probability
foreach (var entry in entries)
{
if (!_orGroups.TryGetValue(entry.GroupId ?? string.Empty, out var orGroup))
{
orGroup = new OrGroup();
_orGroups.Add(entry.GroupId ?? string.Empty, orGroup);
}
orGroup.Entries.Add(entry);
orGroup.CumulativeProbability += entry.SpawnProbability;
}
}
/// <summary>
/// Using a collection of entity spawn entries, picks a random list of entity prototypes to spawn from that collection.
/// </summary>
/// <remarks>
/// This does not spawn the entities. The caller is responsible for doing so, since it may want to do something
/// special to those entities (offset them, insert them into storage, etc)
/// </remarks>
/// <param name="random">Resolve param.</param>
/// <param name="spawned">List that spawned entities are inserted into.</param>
/// <returns>A list of entity prototypes that should be spawned.</returns>
/// <remarks>This is primarily useful if you're calling it many times over, as it lets you reuse the list repeatedly.</remarks>
public void GetSpawns(IRobustRandom random, ref List<string?> spawned)
{
// handle orgroup spawns
foreach (var spawnValue in _orGroups.Values)
{
//HACK: This doesn't seem to work without this if there's only a single orgroup entry. Not sure how to fix the original math properly, but it works in every other case.
if (spawnValue.Entries.Count == 1)
{
var entry = spawnValue.Entries.First();
var amount = entry.Amount;
if (entry.MaxAmount > amount)
amount = random.Next(amount, entry.MaxAmount);
for (var index = 0; index < amount; index++)
{
spawned.Add(entry.PrototypeId);
}
continue;
}
// 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 = entry.Amount;
if (entry.MaxAmount > amount)
amount = random.Next(amount, entry.MaxAmount);
for (var index = 0; index < amount; index++)
{
spawned.Add(entry.PrototypeId);
}
break;
}
}
}
private sealed class OrGroup
{
[ViewVariables] public List<EntitySpawnEntry> Entries { get; } = new();
[ViewVariables] public float CumulativeProbability { get; set; }
}
}