using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using NitroxClient.GameLogic; using NitroxClient.Unity.Helper; using NitroxModel.DataStructures; using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel.DataStructures.GameLogic.Entities.Bases; using NitroxModel.DataStructures.Util; using NitroxModel_Subnautica.DataStructures; using UnityEngine; namespace NitroxClient.MonoBehaviours; /// /// Saves the moonpools NitroxEntity of a to assign them back after each . /// /// /// To recognize pieces even after the base is rebuilt, we use the base anchor () to get an absolute cell value. /// public class MoonpoolManager : MonoBehaviour { private Entities entities; private Base @base; private NitroxId baseId; private Dictionary moonpoolsByCell; public MoonpoolEntity LatestRegisteredMoonpool { get; private set; } public void Awake() { entities = this.Resolve(); if (!TryGetComponent(out @base)) { Log.Error($"Tried adding a {nameof(MoonpoolManager)} to a GameObject that isn't a bases, deleting it."); Destroy(this); return; } @base.TryGetNitroxId(out baseId); moonpoolsByCell = new(); @base.onPostRebuildGeometry += OnPostRebuildGeometry; } public void OnDestroy() { @base.onPostRebuildGeometry -= OnPostRebuildGeometry; } public void LateAssignNitroxEntity(NitroxId baseId) { this.baseId = baseId; NitroxId nextId = baseId.Increment(); // To be recognizable, we need it to be deterministic foreach (MoonpoolEntity moonpoolEntity in moonpoolsByCell.Values) { moonpoolEntity.ParentId = baseId; moonpoolEntity.Id = nextId; nextId = nextId.Increment(); } } public void OnPostRebuildGeometry(Base _) { foreach (KeyValuePair moonpoolEntry in moonpoolsByCell) { AssignNitroxEntityToMoonpool(moonpoolEntry.Key, moonpoolEntry.Value.Id); } } private void AssignNitroxEntityToMoonpool(Int3 absoluteCell, NitroxId moonpoolId, TaskResult> result = null) { Int3 relativeCell = Relative(absoluteCell); Transform baseCellTransform = @base.GetCellObject(relativeCell); if (!baseCellTransform) { Log.Warn($"[{nameof(AssignNitroxEntityToMoonpool)}] CellObject not found for RelativeCell: {relativeCell}, AbsoluteCell: {absoluteCell}"); return; } if (baseCellTransform.TryGetComponentInChildren(out VehicleDockingBay vehicleDockingBay, true)) { result?.Set(vehicleDockingBay.gameObject); NitroxEntity.SetNewId(vehicleDockingBay.gameObject, moonpoolId); } } public Optional RegisterMoonpool(Transform constructableTransform, NitroxId moonpoolId) { return RegisterMoonpool(Absolute(constructableTransform.position), moonpoolId); } public Optional RegisterMoonpool(Int3 absoluteCell, NitroxId moonpoolId) { moonpoolsByCell[absoluteCell] = new(moonpoolId, baseId, absoluteCell.ToDto()); TaskResult> resultObject = new(); AssignNitroxEntityToMoonpool(absoluteCell, moonpoolId, resultObject); LatestRegisteredMoonpool = moonpoolsByCell[absoluteCell]; return resultObject.Get(); } public NitroxId DeregisterMoonpool(Transform constructableTransform) { Int3 absoluteCell = Absolute(constructableTransform.position); if (moonpoolsByCell.TryGetValue(absoluteCell, out MoonpoolEntity moonpoolEntity)) { moonpoolsByCell.Remove(absoluteCell); return moonpoolEntity.Id; } return null; } public void LoadMoonpools(IEnumerable moonpoolEntities) { moonpoolsByCell.Clear(); foreach (MoonpoolEntity moonpoolEntity in moonpoolEntities) { moonpoolsByCell[moonpoolEntity.Cell.ToUnity()] = moonpoolEntity; } } public IEnumerator SpawnVehicles() { foreach (MoonpoolEntity moonpoolEntity in moonpoolsByCell.Values) { VehicleWorldEntity moonpoolVehicleEntity = moonpoolEntity.ChildEntities.OfType().FirstOrFallback(null); if (moonpoolVehicleEntity != null) { yield return entities.SpawnEntityAsync(moonpoolVehicleEntity); } } } private Int3 Absolute(Vector3 position) { return Absolute(@base.WorldToGrid(position)); } private Int3 Absolute(Int3 baseCell) { return baseCell - @base.GetAnchor(); } private Int3 Relative(Int3 baseCell) { return baseCell + @base.GetAnchor(); } public List GetSavedMoonpools() { return moonpoolsByCell.Values.ToList(); } public Dictionary GetMoonpoolsUpdate() { return moonpoolsByCell.ToDictionary(entry => entry.Value.Id, entry => entry.Key.ToDto()); } [Conditional("DEBUG")] public void PrintDebug() { Log.Debug($"MoonpoolManager's registered moonpools (anchor: {@base.GetAnchor()}):"); foreach (MoonpoolEntity moonpoolEntity in moonpoolsByCell.Values) { Int3 absoluteCell = moonpoolEntity.Cell.ToUnity(); Int3 baseCell = Relative(moonpoolEntity.Cell.ToUnity()); Log.Debug($"AbsoluteCell: {absoluteCell}, BaseCell: {baseCell}, id: {moonpoolEntity.Id}"); } } public static IEnumerator RestoreMoonpools(IEnumerable moonpoolEntities, Base @base) { MoonpoolManager moonpoolManager = @base.gameObject.EnsureComponent(); moonpoolManager.LoadMoonpools(moonpoolEntities); moonpoolManager.OnPostRebuildGeometry(@base); yield return moonpoolManager.SpawnVehicles(); } }