using System.Collections; using NitroxClient.Unity.Helper; using NitroxModel.DataStructures.GameLogic.Entities.Metadata; using NitroxModel.DataStructures.GameLogic.Entities.Metadata.Bases; using NitroxModel_Subnautica.DataStructures; using UnityEngine; using UWE; namespace NitroxClient.GameLogic.Bases; public static class GhostMetadataApplier { public static void ApplyBasicMetadataTo(this GhostMetadata ghostMetadata, BaseGhost baseGhost) { baseGhost.targetOffset = ghostMetadata.TargetOffset.ToUnity(); } /// /// Applies the given metadata to a ghost depending on their types. /// /// An extra instruction set to yield for BaseDeconstructable ghosts or null if unrequired. public static IEnumerator ApplyMetadataToGhost(BaseGhost baseGhost, EntityMetadata entityMetadata, Base @base) { if (entityMetadata is not GhostMetadata ghostMetadata) { Log.Error($"Trying to apply metadata to a ghost that is not of type {nameof(GhostMetadata)} : [{entityMetadata.GetType()}]"); return null; } if (BuildUtils.IsUnderBaseDeconstructable(baseGhost, false) && entityMetadata is BaseDeconstructableGhostMetadata deconstructableMetadata) { return deconstructableMetadata.ApplyBaseDeconstructableMetadataTo(baseGhost, @base); } switch (baseGhost) { case BaseAddWaterPark: case BaseAddPartitionDoorGhost: case BaseAddModuleGhost: case BaseAddFaceGhost: if (ghostMetadata is BaseAnchoredFaceGhostMetadata faceMetadata) { faceMetadata.ApplyBaseAnchoredFaceMetadataTo(baseGhost); return null; } break; case BaseAddPartitionGhost: if (ghostMetadata is BaseAnchoredCellGhostMetadata cellMetadata) { cellMetadata.ApplyBaseAnchoredCellMetadataTo(baseGhost); return null; } break; default: ghostMetadata.ApplyBasicMetadataTo(baseGhost); return null; } Log.Error($"[{nameof(GhostMetadataApplier)}] Metadata of type {entityMetadata.GetType()} can't be applied to ghost of type {baseGhost.GetType()}"); return null; } public static void ApplyBaseAnchoredCellMetadataTo(this BaseAnchoredCellGhostMetadata ghostMetadata, BaseGhost baseGhost) { ApplyBasicMetadataTo(ghostMetadata, baseGhost); if (ghostMetadata.AnchoredCell.HasValue && baseGhost is BaseAddPartitionGhost ghost) { ghost.anchoredCell = ghostMetadata.AnchoredCell.Value.ToUnity(); } } public static void ApplyBaseAnchoredFaceMetadataTo(this BaseAnchoredFaceGhostMetadata ghostMetadata, BaseGhost baseGhost) { ApplyBasicMetadataTo(ghostMetadata, baseGhost); if (ghostMetadata.AnchoredFace.HasValue) { switch (baseGhost) { case BaseAddWaterPark ghost: ghost.anchoredFace = ghostMetadata.AnchoredFace.Value.ToUnity(); break; case BaseAddPartitionDoorGhost ghost: ghost.anchoredFace = ghostMetadata.AnchoredFace.Value.ToUnity(); break; case BaseAddModuleGhost ghost: ghost.anchoredFace = ghostMetadata.AnchoredFace.Value.ToUnity(); break; case BaseAddFaceGhost ghost: ghost.anchoredFace = ghostMetadata.AnchoredFace.Value.ToUnity(); break; } } } public static IEnumerator ApplyBaseDeconstructableMetadataTo(this BaseDeconstructableGhostMetadata ghostMetadata, BaseGhost baseGhost, Base @base) { ghostMetadata.ApplyBasicMetadataTo(baseGhost); baseGhost.DisableGhostModelScripts(); if (ghostMetadata.ModuleFace.HasValue) { if (!baseGhost.TryGetComponentInParent(out ConstructableBase constructableBase, true)) { Log.Error($"Couldn't find an interior piece's parent ConstructableBase to apply a {nameof(BaseDeconstructableGhostMetadata)} to."); yield break; } constructableBase.moduleFace = ghostMetadata.ModuleFace.Value.ToUnity(); IPrefabRequest request = PrefabDatabase.GetPrefabAsync(ghostMetadata.ClassId); yield return request; if (!request.TryGetPrefab(out GameObject prefab)) { // Without its module, the ghost will be useless, so we delete it (like in base game) Object.Destroy(constructableBase.gameObject); Log.Error($"Couldn't find a prefab for module of interior piece of ClassId: {ghostMetadata.ClassId}"); yield break; } if (!baseGhost.targetBase) { baseGhost.targetBase = @base; } Base.Face face = ghostMetadata.ModuleFace.Value.ToUnity(); face.cell += baseGhost.targetBase.GetAnchor(); GameObject moduleObject = baseGhost.targetBase.SpawnModule(prefab, face); if (!moduleObject) { Object.Destroy(constructableBase.gameObject); Log.Error("Module couldn't be spawned for interior piece"); yield break; } if (moduleObject.TryGetComponent(out IBaseModule baseModule)) { baseModule.constructed = constructableBase.constructedAmount; } } } }