Skip to content

Commit e6fdf03

Browse files
committed
Add failsafe at high slot counts.
1 parent afbe174 commit e6fdf03

File tree

3 files changed

+34
-10
lines changed

3 files changed

+34
-10
lines changed

SubnauticaRandomiser/Patches/EntitySlotsTrackerPatcher.cs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ namespace SubnauticaRandomiser.Patches
1515
[HarmonyPatch]
1616
internal static class EntitySlotsTrackerPatcher
1717
{
18+
private const float AdjustedSlotMult = 1.25f;
19+
private const float SlotEmergencyThreshold = 0.95f;
20+
1821
private static EntitySlotsTrackerSaveData _saveData;
1922
private static ILogHandler _log = PrefixLogHandler.Get("[SlotTrackerPatcher]");
2023
private static IRandomHandler _rng = new RandomHandler();
@@ -127,17 +130,25 @@ private static EntitySlot.Filler GetForcedSpawn(BiomeType biome, EntitySlotData.
127130
return default;
128131
// Pretend that more slots have spawned than really did so that we reach guaranteed 100% of entities spawned
129132
// *before* we run out of slots to do so.
130-
slotProgress *= 1.25f; // Works out to 100% fragment saturation after 80% of slots have been processed.
131-
132-
if (slotProgress < entityCounts.NextCheckThreshold)
133+
var adjustedProgress = slotProgress * AdjustedSlotMult;
134+
if (adjustedProgress < entityCounts.NextCheckThreshold)
133135
return default;
134136

135-
var techType = entityCounts.GetForcedSpawn(slotProgress);
137+
var techType = entityCounts.GetForcedSpawn(adjustedProgress);
136138
if (techType == TechType.None)
137139
return default;
138140

139141
_log.Debug($"Forcing spawn of '{techType}' in biome '{biome}'");
140-
return new EntitySlot.Filler { classId = _saveData.Spawnables[techType].GetRandomPrefab(_rng), count = 1 };
142+
int spawnCount = 1;
143+
// If almost no slots are left do an emergency spawn where several entities are layered on top of each
144+
// other. It's not pretty, but it prevents getting stuck / softlocked.
145+
if (slotProgress >= SlotEmergencyThreshold)
146+
{
147+
spawnCount = entityCounts.GetNumMissingSpawns(techType);
148+
_log.Warn($"Forcing emergency spawn of {spawnCount} {techType} in {biome}!");
149+
}
150+
151+
return new EntitySlot.Filler { classId = _saveData.Spawnables[techType].GetRandomPrefab(_rng), count = spawnCount };
141152
}
142153
}
143154
}

SubnauticaRandomiser/Serialization/Modules/EntitySlots/EntityCounts.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ public void AddEntity(TechType techType, int required)
2626
/// <summary>
2727
/// Count one successful spawn for an entity.
2828
/// </summary>
29-
public void CountSpawn(TechType techType)
29+
public void CountSpawn(TechType techType, int spawned = 1)
3030
{
3131
var counter = SpawnCounters.Find(c => c.TechType == techType);
3232
if (counter is null)
3333
return;
3434

35-
counter.Add(1);
35+
counter.Add(spawned);
3636
SortCounters();
3737
// Consider this biome completed when all minimum spawns have been reached.
3838
if (SpawnCounters[0].Spawned >= SpawnCounters[0].Required)
@@ -77,6 +77,20 @@ public TechType GetForcedSpawn(float completionThreshold)
7777
return counter.TechType;
7878
}
7979

80+
/// <summary>
81+
/// Get the number of remaining spawns needed to satisfy the minimum spawn requirements of an entity.
82+
/// </summary>
83+
/// <exception cref="ArgumentException"></exception>
84+
public int GetNumMissingSpawns(TechType entity)
85+
{
86+
var counter = SpawnCounters.Find(c => c.TechType == entity);
87+
if (counter is null)
88+
throw new ArgumentException($"No entity with TechType '{entity}' present in spawn counters!");
89+
90+
// Never return negatives.
91+
return Mathf.Max(counter.Required - counter.Spawned, 0);
92+
}
93+
8094
[Serializable]
8195
internal class SpawnCounter
8296
{

SubnauticaRandomiser/Serialization/Modules/EntitySlots/EntitySlotsTrackerSaveData.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,8 @@ public void CountSpawnedEntity(BiomeType biome, EntitySlot.Filler filler)
9898
{
9999
throw new KeyNotFoundException($"Filler classId '{filler.classId}' is not in WorldEntityDB!");
100100
}
101-
102-
var techType = info.techType;
103-
counts.CountSpawn(techType);
101+
102+
counts.CountSpawn(info.techType, filler.count);
104103
}
105104
}
106105
}

0 commit comments

Comments
 (0)