This repository has been archived on 2026-10-29. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
EveUnity/packages/org.gamecult.eve.unity-scene/Runtime/EveUnityFeedbackEffectRenderer.cs
2026-07-12 05:27:38 +01:00

98 lines
3.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
#nullable enable
namespace GameCult.Eve.UnityScene
{
public sealed class EveUnityFeedbackEffectRenderer : MonoBehaviour
{
[SerializeField] private float fallbackLifetimeSeconds = 5f;
private readonly List<ActiveEffect> _active = new List<ActiveEffect>();
private EveUnityPlayableWorldClientHost? _host;
private IEveUnityGameObjectAssetProvider? _assetProvider;
public int ActiveEffectCount => _active.Count;
public void Bind(EveUnityPlayableWorldClientHost host, IEveUnityGameObjectAssetProvider? assetProvider = null)
{
if (host == null) throw new ArgumentNullException(nameof(host));
if (ReferenceEquals(_host, host) && ReferenceEquals(_assetProvider, assetProvider)) return;
Unbind();
_host = host;
_assetProvider = assetProvider;
_host.FeedbackAvailable += Present;
}
public void Unbind()
{
if (_host != null) _host.FeedbackAvailable -= Present;
_host = null;
_assetProvider = null;
}
public void Present(EveUnityFeedbackEvent feedback)
{
if (feedback == null) throw new ArgumentNullException(nameof(feedback));
if (string.IsNullOrWhiteSpace(feedback.Kind)) return;
var prefab = ResolveRolePrefab("effect.feedback." + feedback.Kind);
if (prefab == null) return;
var effect = Instantiate(prefab, transform);
effect.name = "Eve feedback " + feedback.Kind + " " + feedback.EventId;
if (TryVector(feedback.Position, out var position)) effect.transform.position = position;
_active.Add(new ActiveEffect(effect, Time.unscaledTime + Math.Max(0.01f, fallbackLifetimeSeconds)));
}
private void Update()
{
var now = Time.unscaledTime;
for (var index = _active.Count - 1; index >= 0; index--)
{
var effect = _active[index];
if (effect.Root != null && now < effect.DestroyAt) continue;
if (effect.Root != null) Destroy(effect.Root);
_active.RemoveAt(index);
}
}
private GameObject? ResolveRolePrefab(string role) => _assetProvider?.ResolvePrefab(
new EveUnityPlayableWorldAssetBinding("", role, "provider-asset-ref"));
private static bool TryVector(string value, out Vector3 vector)
{
vector = Vector3.zero;
var parts = (value ?? "").Split(',');
if (parts.Length < 2 ||
!float.TryParse(parts[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var x) ||
!float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var z))
return false;
var y = 0f;
if (parts.Length >= 3)
{
if (!float.TryParse(parts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out y) ||
!float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out z))
return false;
}
vector = new Vector3(x, y, z);
return true;
}
private void OnDestroy()
{
Unbind();
foreach (var effect in _active)
if (effect.Root != null) Destroy(effect.Root);
_active.Clear();
}
private readonly struct ActiveEffect
{
public ActiveEffect(GameObject root, float destroyAt) { Root = root; DestroyAt = destroyAt; }
public GameObject Root { get; }
public float DestroyAt { get; }
}
}
}