2026-06-21 09:54:15 +01:00
|
|
|
using System;
|
2021-02-26 19:01:47 +00:00
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
2026-06-21 09:54:15 +01:00
|
|
|
using GameCult.Aetheria.State.Verse;
|
2021-02-26 19:01:47 +00:00
|
|
|
using UniRx;
|
|
|
|
|
using UnityEngine;
|
2026-06-21 09:37:54 +01:00
|
|
|
using cfloat3 = CultMath.float3;
|
2021-02-26 19:01:47 +00:00
|
|
|
|
|
|
|
|
public class EntityInstance : MonoBehaviour
|
|
|
|
|
{
|
2021-05-12 00:15:11 +01:00
|
|
|
public MeshRenderer MapIcon;
|
2021-05-02 20:59:45 +01:00
|
|
|
public Transform InfluencePrefab;
|
2021-02-26 19:01:47 +00:00
|
|
|
public Material InvisibleMaterial;
|
|
|
|
|
public ShieldManager Shield;
|
|
|
|
|
public HullCollider[] HullColliders;
|
|
|
|
|
|
2021-03-16 16:35:23 +00:00
|
|
|
public Transform[] EquipmentHardpoints;
|
2021-02-26 19:01:47 +00:00
|
|
|
public RadiatorHardpoint[] RadiatorHardpoints;
|
|
|
|
|
public ThrusterHardpoint[] ThrusterHardpoints;
|
|
|
|
|
public WeaponHardpoint[] WeaponHardpoints;
|
|
|
|
|
public ArticulationPoint[] ArticulationPoints;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public event Action OnFadedOut;
|
|
|
|
|
public event Action OnFadedIn;
|
|
|
|
|
|
|
|
|
|
private List<Material> _fadeMaterials = new List<Material>();
|
|
|
|
|
private Dictionary<MeshRenderer, Material[]> _meshes = new Dictionary<MeshRenderer, Material[]>();
|
|
|
|
|
private List<(MeshRenderer mesh, int submesh, Material material)> _nonFadedSubmeshes = new List<(MeshRenderer mesh, int submesh, Material material)>();
|
|
|
|
|
private List<IDisposable> _subscriptions = new List<IDisposable>();
|
|
|
|
|
private float _fade = 0;
|
|
|
|
|
private bool _fading;
|
|
|
|
|
private bool _fadingIn;
|
|
|
|
|
private bool _fadedElementsVisible = false;
|
|
|
|
|
private bool _unfadedElementsVisible = false;
|
|
|
|
|
private float _fadeTime;
|
2021-05-02 20:59:45 +01:00
|
|
|
private Transform _influenceInstance;
|
2021-04-30 06:39:57 +01:00
|
|
|
|
2022-07-10 02:53:09 +01:00
|
|
|
//private List<(GameObject source, EquippedItem item)> _audioSources = new List<(GameObject source, EquippedItem item)>();
|
2021-04-30 06:39:57 +01:00
|
|
|
// private (Reactor reactor, GameObject sfxSource) _reactor;
|
|
|
|
|
// private Dictionary<Radiator, GameObject> _radiatorSfx = new Dictionary<Radiator, GameObject>();
|
2021-03-16 16:35:23 +00:00
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
private static Vector2 ToVector2(CultMath.float2 value) => new Vector2(value.x, value.y);
|
|
|
|
|
private static Vector2 ToVector2(Unity.Mathematics.float2 value) => new Vector2(value.x, value.y);
|
2026-06-14 03:37:27 +01:00
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
private static cfloat3 ToCult(Vector3 value) => new cfloat3(value.x, value.y, value.z);
|
2026-06-14 03:37:27 +01:00
|
|
|
|
2021-05-12 13:49:04 +01:00
|
|
|
public CompassIcon CompassIcon { get; set; }
|
2021-02-26 19:01:47 +00:00
|
|
|
public Dictionary<HardpointData, Transform[]> Barrels { get; private set; }
|
|
|
|
|
public Dictionary<HardpointData, int> BarrelIndices { get; private set; }
|
2021-03-01 01:53:56 +00:00
|
|
|
public Dictionary<Radiator, MeshRenderer> RadiatorMeshes { get; private set; }
|
2021-02-26 19:01:47 +00:00
|
|
|
public Transform LookAtPoint { get; private set; }
|
2026-06-21 17:00:06 +01:00
|
|
|
public int DaemonEntityIndex { get; private set; } = -1;
|
2021-02-26 19:01:47 +00:00
|
|
|
public Entity Entity { get; private set; }
|
2021-03-15 11:40:46 +00:00
|
|
|
public ZoneRenderer ZoneRenderer { get; private set; }
|
2021-04-15 04:25:22 +01:00
|
|
|
public Transform LocalSpace { get; private set; }
|
2021-02-26 19:01:47 +00:00
|
|
|
public bool Visible
|
|
|
|
|
{
|
|
|
|
|
get => _fade > 0.01f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
{
|
2021-04-15 04:25:22 +01:00
|
|
|
LocalSpace = new GameObject().transform;
|
2021-02-26 19:01:47 +00:00
|
|
|
var meshes = gameObject.GetComponentsInChildren<MeshRenderer>();
|
|
|
|
|
var materials = new List<(Material material, List<(MeshRenderer renderer, int index)> submeshes)>();
|
|
|
|
|
foreach (var mesh in meshes)
|
|
|
|
|
{
|
|
|
|
|
_meshes.Add(mesh, mesh.sharedMaterials);
|
|
|
|
|
for (var i = 0; i < mesh.sharedMaterials.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
var material = mesh.sharedMaterials[i];
|
|
|
|
|
if (material.shader.FindPropertyIndex("_Fade") >= 0)
|
|
|
|
|
{
|
|
|
|
|
var match = materials.FirstOrDefault(lm => lm.material == material);
|
|
|
|
|
if(match.material==null || material.shader.FindPropertyIndex("_EmissionFresnel") >= 0)
|
|
|
|
|
{
|
|
|
|
|
match = (material, new List<(MeshRenderer renderer, int index)>());
|
|
|
|
|
materials.Add(match);
|
|
|
|
|
}
|
|
|
|
|
match.submeshes.Add((mesh, i));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_nonFadedSubmeshes.Add((mesh, i, material));
|
|
|
|
|
_meshes[mesh][i] = InvisibleMaterial;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var (material, submeshes) in materials)
|
|
|
|
|
{
|
|
|
|
|
var materialInstance = Instantiate(material);
|
|
|
|
|
_fadeMaterials.Add(materialInstance);
|
|
|
|
|
foreach (var (mesh, index) in submeshes)
|
|
|
|
|
{
|
|
|
|
|
_meshes[mesh][index] = materialInstance;
|
|
|
|
|
}
|
|
|
|
|
materialInstance.SetFloat("_Fade", 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var mesh in _meshes.Keys) mesh.enabled = false;
|
|
|
|
|
|
|
|
|
|
foreach (var mesh in _meshes) mesh.Key.sharedMaterials = mesh.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void ShowUnfadedElements()
|
|
|
|
|
{
|
|
|
|
|
_unfadedElementsVisible = true;
|
|
|
|
|
foreach (var (mesh, submesh, material) in _nonFadedSubmeshes) _meshes[mesh][submesh] = material;
|
|
|
|
|
foreach (var mesh in _meshes) mesh.Key.sharedMaterials = mesh.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected virtual void HideUnfadedElements()
|
|
|
|
|
{
|
|
|
|
|
_unfadedElementsVisible = false;
|
|
|
|
|
foreach (var (mesh, submesh, material) in _nonFadedSubmeshes) _meshes[mesh][submesh] = InvisibleMaterial;
|
|
|
|
|
foreach (var mesh in _meshes) mesh.Key.sharedMaterials = mesh.Value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void FadeIn(float time)
|
|
|
|
|
{
|
|
|
|
|
if (_fade > .99f)
|
|
|
|
|
{
|
|
|
|
|
_fading = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_fadeTime = time;
|
|
|
|
|
_fading = true;
|
|
|
|
|
_fadingIn = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void FadeOut(float time)
|
|
|
|
|
{
|
|
|
|
|
if (_fade < .01f)
|
|
|
|
|
{
|
|
|
|
|
_fading = false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
_fadeTime = time;
|
|
|
|
|
_fading = true;
|
|
|
|
|
_fadingIn = false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-15 11:40:46 +00:00
|
|
|
public virtual void SetEntity(ZoneRenderer zoneRenderer, Entity entity)
|
2021-02-26 19:01:47 +00:00
|
|
|
{
|
|
|
|
|
gameObject.name = entity.Name;
|
2021-04-15 04:25:22 +01:00
|
|
|
LocalSpace.gameObject.name = $"{entity.Name} Sim Space";
|
|
|
|
|
LocalSpace.SetParent(transform.parent);
|
2021-02-26 19:01:47 +00:00
|
|
|
Entity = entity;
|
2026-06-21 17:00:06 +01:00
|
|
|
DaemonEntityIndex = entity.DaemonEntityIndex;
|
2021-03-15 11:40:46 +00:00
|
|
|
ZoneRenderer = zoneRenderer;
|
2026-06-25 18:09:33 +01:00
|
|
|
var typedHull = ZoneRenderer?.FindCatalogItem(entity.Hull);
|
2026-06-14 03:37:27 +01:00
|
|
|
if (typedHull == null || typedHull.ShapeWidth <= 0 || typedHull.ShapeHeight <= 0 || typedHull.ShapeCells.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
Debug.LogError($"Cannot bind entity instance for {entity.Name}: missing typed hull shape.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
if(Shield)
|
|
|
|
|
Shield.Entity = entity;
|
|
|
|
|
foreach (var hullCollider in HullColliders) hullCollider.Entity = entity;
|
|
|
|
|
|
2021-03-01 01:53:56 +00:00
|
|
|
RadiatorMeshes = new Dictionary<Radiator, MeshRenderer>();
|
2021-02-26 19:01:47 +00:00
|
|
|
Barrels = new Dictionary<HardpointData, Transform[]>();
|
|
|
|
|
BarrelIndices = new Dictionary<HardpointData, int>();
|
2021-03-01 01:53:56 +00:00
|
|
|
foreach (var radiator in entity.GetBehaviors<Radiator>())
|
2021-02-26 19:01:47 +00:00
|
|
|
{
|
2021-03-01 01:53:56 +00:00
|
|
|
var hp = Entity.Hardpoints[radiator.Item.Position.x, radiator.Item.Position.y];
|
|
|
|
|
if (hp != null && hp.Type == HardpointType.Radiator)
|
2021-02-26 19:01:47 +00:00
|
|
|
{
|
|
|
|
|
var mesh = RadiatorHardpoints.FirstOrDefault(x => x.name == hp.Transform);
|
|
|
|
|
if (mesh)
|
|
|
|
|
{
|
2021-03-01 01:53:56 +00:00
|
|
|
RadiatorMeshes.Add(radiator, mesh.Mesh);
|
2021-02-26 19:01:47 +00:00
|
|
|
}
|
|
|
|
|
}
|
2021-03-01 01:53:56 +00:00
|
|
|
}
|
2026-06-14 03:37:27 +01:00
|
|
|
foreach (var hp in Entity.Hardpoints.Cast<HardpointData>().Where(hp => hp != null).Distinct())
|
2021-03-01 01:53:56 +00:00
|
|
|
{
|
2021-02-26 19:01:47 +00:00
|
|
|
if(hp.Type == HardpointType.Ballistic || hp.Type == HardpointType.Energy || hp.Type == HardpointType.Launcher)
|
|
|
|
|
{
|
|
|
|
|
var whp = WeaponHardpoints.FirstOrDefault(x => x.name == hp.Transform);
|
|
|
|
|
if (whp)
|
|
|
|
|
{
|
|
|
|
|
Barrels.Add(hp, whp.FiringPoint);
|
|
|
|
|
BarrelIndices.Add(hp, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LookAtPoint = new GameObject($"{entity.Name} Look Point").transform;
|
|
|
|
|
|
|
|
|
|
foreach (var articulationPoint in ArticulationPoints)
|
|
|
|
|
{
|
|
|
|
|
articulationPoint.Target = LookAtPoint;
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 04:45:42 +01:00
|
|
|
if (entity is OrbitalEntity orbital && orbital.IsSecureArea)
|
2021-05-02 20:59:45 +01:00
|
|
|
{
|
|
|
|
|
_influenceInstance = Instantiate(InfluencePrefab);
|
|
|
|
|
_influenceInstance.transform.localScale = Vector3.one * orbital.SecurityRadius;
|
|
|
|
|
}
|
2021-02-26 19:01:47 +00:00
|
|
|
}
|
2022-08-08 22:43:55 +01:00
|
|
|
|
2021-02-26 19:01:47 +00:00
|
|
|
public Transform GetBarrel(HardpointData hardpoint)
|
|
|
|
|
{
|
|
|
|
|
if (Barrels.ContainsKey(hardpoint))
|
|
|
|
|
{
|
|
|
|
|
var barrel = Barrels[hardpoint][BarrelIndices[hardpoint]];
|
|
|
|
|
BarrelIndices[hardpoint] = (BarrelIndices[hardpoint] + 1) % Barrels[hardpoint].Length;
|
|
|
|
|
return barrel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return transform;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual void Update()
|
|
|
|
|
{
|
|
|
|
|
if (_fading)
|
|
|
|
|
{
|
|
|
|
|
if (_fadingIn)
|
|
|
|
|
{
|
|
|
|
|
_fade += Time.deltaTime / _fadeTime;
|
|
|
|
|
if (!_fadedElementsVisible && _fade > .01f)
|
|
|
|
|
{
|
|
|
|
|
_fadedElementsVisible = true;
|
|
|
|
|
foreach (var mesh in _meshes.Keys) mesh.enabled = true;
|
|
|
|
|
}
|
|
|
|
|
if (_fade > 1)
|
|
|
|
|
{
|
|
|
|
|
_fade = 1;
|
|
|
|
|
_fading = false;
|
|
|
|
|
OnFadedIn?.Invoke();
|
|
|
|
|
OnFadedIn = null;
|
|
|
|
|
ShowUnfadedElements();
|
|
|
|
|
}
|
|
|
|
|
foreach(var material in _fadeMaterials) material.SetFloat("_Fade", _fade);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_fade -= Time.deltaTime / _fadeTime;
|
|
|
|
|
if(_unfadedElementsVisible && _fade < .99f) HideUnfadedElements();
|
|
|
|
|
if (_fade < 0)
|
|
|
|
|
{
|
|
|
|
|
_fadedElementsVisible = false;
|
|
|
|
|
foreach (var mesh in _meshes.Keys) mesh.enabled = false;
|
|
|
|
|
_fade = 0;
|
|
|
|
|
_fading = false;
|
|
|
|
|
OnFadedOut?.Invoke();
|
|
|
|
|
OnFadedOut = null;
|
|
|
|
|
}
|
|
|
|
|
foreach(var material in _fadeMaterials) material.SetFloat("_Fade", _fade);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var x in RadiatorMeshes)
|
|
|
|
|
{
|
2026-06-21 20:29:03 +01:00
|
|
|
x.Value.material.SetFloat("_Emission", (float)ZoneRenderer.RenderSettings.TemperatureEmissionCurve.Evaluate(x.Key.RadiatorTemperature));
|
2021-02-26 19:01:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var x in Barrels)
|
|
|
|
|
{
|
2026-06-21 09:37:54 +01:00
|
|
|
Entity.HardpointTransforms[x.Key] = (
|
|
|
|
|
ToCult(x.Value[0].position),
|
|
|
|
|
ToCult(x.Value[0].forward));
|
2021-02-26 19:01:47 +00:00
|
|
|
}
|
|
|
|
|
|
2026-06-21 09:37:54 +01:00
|
|
|
var entityPosition = (Vector3)AetheriaMath.ToUnity(Entity.CultPosition);
|
|
|
|
|
var entityLookDirection = (Vector3)AetheriaMath.ToUnity(Entity.CultLookDirection);
|
2026-06-21 17:52:41 +01:00
|
|
|
var lookAtDistance = ZoneRenderer != null &&
|
|
|
|
|
ZoneRenderer.TryGetDaemonTargetDistance(DaemonEntityIndex, out var daemonTargetDistance)
|
2026-06-21 20:29:03 +01:00
|
|
|
? Mathf.Max(daemonTargetDistance, (float)ZoneRenderer.RenderSettings.ConvergenceMinimumDistance)
|
2026-06-21 17:52:41 +01:00
|
|
|
: 10000;
|
2026-06-21 09:37:54 +01:00
|
|
|
|
2026-06-21 17:52:41 +01:00
|
|
|
LookAtPoint.position = transform.position + entityLookDirection * lookAtDistance;
|
2026-06-21 09:37:54 +01:00
|
|
|
LocalSpace.localPosition = transform.position = entityPosition;
|
2021-05-02 20:59:45 +01:00
|
|
|
if (_influenceInstance)
|
2026-06-21 09:37:54 +01:00
|
|
|
_influenceInstance.position = new Vector3(entityPosition.x, 0, entityPosition.z);
|
2021-02-26 19:01:47 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-16 16:35:23 +00:00
|
|
|
public virtual void OnDestroy()
|
2021-02-26 19:01:47 +00:00
|
|
|
{
|
2021-05-02 20:59:45 +01:00
|
|
|
if (_influenceInstance) Destroy(_influenceInstance.gameObject);
|
2021-04-15 04:25:22 +01:00
|
|
|
Destroy(LocalSpace.gameObject);
|
2021-02-26 19:01:47 +00:00
|
|
|
foreach(var x in _subscriptions)
|
|
|
|
|
x.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|