Files
Nitrox/NitroxClient/GameLogic/Spawning/WorldEntities/RadiationLeakEntitySpawner.cs
2025-07-06 00:23:46 +02:00

103 lines
5.0 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using NitroxClient.GameLogic.Spawning.Abstract;
using NitroxClient.MonoBehaviours;
using NitroxModel.DataStructures.GameLogic.Entities;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
using NitroxModel.DataStructures.Util;
using UnityEngine;
namespace NitroxClient.GameLogic.Spawning.WorldEntities;
public class RadiationLeakEntitySpawner : SyncEntitySpawner<RadiationLeakEntity>
{
// This constant is defined by Subnautica and should never be modified (same as for SubnauticaWorldModifier)
private const int TOTAL_LEAKS = 11;
private readonly TimeManager timeManager;
private readonly List<float> registeredLeaksFixTime = new();
public RadiationLeakEntitySpawner(TimeManager timeManager)
{
this.timeManager = timeManager;
}
protected override IEnumerator SpawnAsync(RadiationLeakEntity entity, TaskResult<Optional<GameObject>> result)
{
SpawnSync(entity, result);
yield break;
}
protected override bool SpawnSync(RadiationLeakEntity entity, TaskResult<Optional<GameObject>> result)
{
// This script is located under (Aurora Scene) //Aurora-Main/Aurora so it's a good starting point to search through the GameObjects
CrashedShipExploder crashedShipExploder = CrashedShipExploder.main;
LeakingRadiation leakingRadiation = LeakingRadiation.main;
if (!crashedShipExploder || !leakingRadiation || entity.Metadata is not RadiationMetadata metadata)
{
return true;
}
Transform radiationLeaksHolder = crashedShipExploder.transform.Find("radiationleaks").GetChild(0);
RadiationLeak radiationLeak = radiationLeaksHolder.GetChild(entity.ObjectIndex).GetComponent<RadiationLeak>();
NitroxEntity.SetNewId(radiationLeak.gameObject, entity.Id);
radiationLeak.liveMixin.health = metadata.Health;
registeredLeaksFixTime.Add(metadata.FixRealTime);
// We can only calculate the radiation increment and dissipation once we got all radiation leaks info
if (crashedShipExploder.IsExploded() && registeredLeaksFixTime.Count == TOTAL_LEAKS)
{
RecalculateRadiationRadius(leakingRadiation);
}
return true;
}
public void RecalculateRadiationRadius(LeakingRadiation leakingRadiation)
{
float realElapsedTime = (float)timeManager.RealTimeElapsed;
// We substract the explosion time from the real time because before that, the radius doesn't increment
float realExplosionTime = timeManager.AuroraRealExplosionTime;
float maxRegisteredLeakFixTime = registeredLeaksFixTime.Max();
// Note: Only increment radius if leaks were fixed AFTER explosion (before, game code doesn't increase radius)
// If leaks aren't all fixed yet we calculate from current real elapsed time
float deltaTimeAfterExplosion = realElapsedTime - realExplosionTime;
if (maxRegisteredLeakFixTime == -1)
{
if (deltaTimeAfterExplosion > 0)
{
float radiusIncrement = deltaTimeAfterExplosion * leakingRadiation.kGrowRate;
// Calculation lines from LeakingRadiation.Update
leakingRadiation.currentRadius = Mathf.Clamp(leakingRadiation.kStartRadius + radiusIncrement, 0f, leakingRadiation.kMaxRadius);
leakingRadiation.damagePlayerInRadius.damageRadius = leakingRadiation.currentRadius;
leakingRadiation.radiatePlayerInRange.radiateRadius = leakingRadiation.currentRadius;
}
// If leaks aren't fixed, we won't need to calculate a radius decrement
return;
}
leakingRadiation.radiationFixed = true;
// If all leaks are fixed we calculate from the time they were fixed
float deltaAliveTime = maxRegisteredLeakFixTime - realExplosionTime;
if (deltaAliveTime > 0)
{
float radiusIncrement = deltaAliveTime * leakingRadiation.kGrowRate;
leakingRadiation.currentRadius = Mathf.Clamp(leakingRadiation.kStartRadius + radiusIncrement, 0f, leakingRadiation.kMaxRadius);
}
// Now calculate the natural dissipation decrement from the time leaks are fixed
// If they were fixed before real explosion time, we calculate from real explosion time
float deltaFixedTimeAfterExplosion = realElapsedTime - Mathf.Max(maxRegisteredLeakFixTime, realExplosionTime);
if (deltaFixedTimeAfterExplosion > 0)
{
float radiusDecrement = deltaFixedTimeAfterExplosion * leakingRadiation.kNaturalDissipation;
leakingRadiation.currentRadius = Mathf.Clamp(leakingRadiation.currentRadius + radiusDecrement, 0f, leakingRadiation.kMaxRadius);
}
leakingRadiation.damagePlayerInRadius.damageRadius = leakingRadiation.currentRadius;
leakingRadiation.radiatePlayerInRange.radiateRadius = leakingRadiation.currentRadius;
}
protected override bool SpawnsOwnChildren(RadiationLeakEntity entity) => false;
}