using UnityEngine;
using System.Collections.Generic;
///
/// Gère l'état sous tension d'un équipement rackmount.
///
/// NE GÉNÈRE PAS les ports alimentation → utiliser EquipementAlim pour ça.
/// NE GÉNÈRE PAS de ventilateur → utiliser un child "Ventilateur" existant
/// ou laisser vide (pas de ventilo visuel).
///
/// Quand alimenté :
/// - LEDs d'activité s'allument (emission verte) sur la face avant
/// - Ventilateur tourne (si un child "Ventilateur" est assigné)
/// - Signale à AmbianceSonore qu'une machine est active
///
/// Setup Unity :
/// 1. Ajouter EquipementAlim sur l'équipement → générer les ports alim
/// 2. Ajouter EtatEquipement sur l'équipement
/// 3. Les ports alim sont trouvés automatiquement (GetComponentsInChildren)
/// 4. Optionnel : créer un child "Ventilateur" et l'assigner
/// 5. Configurer le nombre de LEDs, consommation, etc.
///
public class EtatEquipement : MonoBehaviour
{
[Header("Configuration")]
[Tooltip("Mode alimentation redondante : l'équipement reste allumé si au moins 1 port est alimenté")]
public bool alimentationRedondante = false;
[Tooltip("Consommation électrique en watts")]
public float consommationWatts = 350f;
[Header("LEDs")]
[Tooltip("Nombre de LEDs d'activité sur la face avant")]
[Range(0, 8)]
public int nombreLEDs = 3;
public Color couleurLEDAllumee = new Color(0f, 1f, 0f, 1f); // Vert
public Color couleurLEDEteinte = new Color(0.05f, 0.05f, 0.05f, 1f); // Quasi noir
public Color couleurLEDStandby = new Color(1f, 0.5f, 0f, 1f); // Orange
[Tooltip("Intensité de l'émission des LEDs")]
public float intensiteLED = 3f;
[Tooltip("Décalage vertical des LEDs depuis le centre")]
public float ledsDecalageY = 0f;
[Tooltip("Décalage horizontal de départ des LEDs")]
public float ledsDecalageX = 0f;
[Tooltip("Espacement entre les LEDs")]
public float ledsEspacement = 0.015f;
[Tooltip("Taille d'une LED")]
public Vector3 ledsTaille = new Vector3(0.006f, 0.006f, 0.003f);
[Header("Ventilateur")]
[Tooltip("Assigner un child 'Ventilateur' existant. Si vide, pas d'animation ventilo.")]
public Transform ventilateur;
[Tooltip("Vitesse de rotation du ventilateur en degrés/seconde")]
public float vitesseVentilateur = 720f;
[Tooltip("Axe de rotation du ventilateur (local)")]
public Vector3 axeRotation = Vector3.forward;
[Header("État (lecture seule)")]
public bool estSousTension = false;
public bool estEnStandby = false;
[Header("Références (auto-remplies au Start)")]
public List ledsRenderers = new List();
// Privé
private bool _ledsGenerees = false;
void Start()
{
// Génère les LEDs visuelles si configurées
if (nombreLEDs > 0 && !_ledsGenerees)
{
GenererLEDs();
}
// Cherche un ventilateur existant si pas assigné
if (ventilateur == null)
{
Transform ventiloChild = transform.Find("Ventilateur");
if (ventiloChild != null)
ventilateur = ventiloChild;
// PAS de création automatique — on ne pollue plus le mesh
}
// État initial : éteint
MettreAJourVisuel();
}
void Update()
{
// Animation ventilateur
if (estSousTension && ventilateur != null)
{
ventilateur.Rotate(axeRotation, vitesseVentilateur * Time.deltaTime, Space.Self);
}
}
///
/// Génère les LEDs d'activité sur la face avant de l'équipement.
///
private void GenererLEDs()
{
// Supprime les anciennes LEDs
for (int i = transform.childCount - 1; i >= 0; i--)
{
Transform enfant = transform.GetChild(i);
if (enfant.name.StartsWith("LED_Activity_"))
{
if (Application.isPlaying) Destroy(enfant.gameObject);
else DestroyImmediate(enfant.gameObject);
}
}
ledsRenderers.Clear();
Bounds bounds = GetBounds();
float startX = ledsDecalageX - ((nombreLEDs - 1) * ledsEspacement) / 2f;
for (int i = 0; i < nombreLEDs; i++)
{
GameObject ledObj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
ledObj.name = $"LED_Activity_{i}";
ledObj.transform.SetParent(transform);
ledObj.transform.localPosition = new Vector3(
startX + i * ledsEspacement,
ledsDecalageY,
bounds.extents.z + 0.002f // Juste devant la face avant
);
ledObj.transform.localScale = ledsTaille;
// Désactive le collider (pas interactif)
Collider ledCol = ledObj.GetComponent();
if (ledCol != null)
{
if (Application.isPlaying) Destroy(ledCol);
else DestroyImmediate(ledCol);
}
// Material noir par défaut
Renderer rend = ledObj.GetComponent();
if (rend != null)
{
rend.material = new Material(Shader.Find("Standard"));
rend.material.color = couleurLEDEteinte;
}
ledsRenderers.Add(rend);
}
_ledsGenerees = true;
}
///
/// Vérifie l'état d'alimentation en fonction des ports connectés.
/// Appelé par PortAlimentation quand l'état change.
/// Cherche les ports dynamiquement via GetComponentsInChildren.
///
public void VerifierAlimentation()
{
bool ancienEtat = estSousTension;
PortAlimentation[] ports = GetComponentsInChildren();
if (ports.Length == 0)
{
estSousTension = false;
}
else if (alimentationRedondante)
{
// Au moins 1 port alimenté suffit
estSousTension = false;
foreach (var port in ports)
{
if (port.estAlimente)
{
estSousTension = true;
break;
}
}
}
else
{
// Tous les ports doivent être alimentés
estSousTension = true;
foreach (var port in ports)
{
if (!port.estAlimente)
{
estSousTension = false;
break;
}
}
}
if (ancienEtat != estSousTension)
{
MettreAJourVisuel();
string etat = estSousTension ? "SOUS TENSION" : "HORS TENSION";
Debug.Log($"{gameObject.name}: {etat}");
// Notifie l'ambiance sonore
AmbianceSonore ambiance = FindObjectOfType();
if (ambiance != null)
ambiance.RecalculerAmbiance();
// v7.1 : propager l'etat sous-tension au EtatEquipementNetworkSync (pour rejoin)
if (Mirror.NetworkServer.active)
{
EtatEquipementNetworkSync sync = GetComponent();
if (sync == null) sync = GetComponentInParent();
if (sync != null) sync.ServerSyncEtat();
}
}
}
///
/// Met à jour l'apparence visuelle selon l'état d'alimentation.
///
public void MettreAJourVisuel()
{
// LEDs
foreach (var ledRenderer in ledsRenderers)
{
if (ledRenderer == null) continue;
Color couleur;
if (estSousTension)
couleur = couleurLEDAllumee;
else if (estEnStandby)
couleur = couleurLEDStandby;
else
couleur = couleurLEDEteinte;
ledRenderer.material.color = couleur;
ledRenderer.material.EnableKeyword("_EMISSION");
if (estSousTension || estEnStandby)
ledRenderer.material.SetColor("_EmissionColor", couleur * intensiteLED);
else
ledRenderer.material.SetColor("_EmissionColor", Color.black);
}
// Clignotement
if (estSousTension)
InvokeRepeating(nameof(ClignoterLEDs), 0.5f, 0.3f);
else
CancelInvoke(nameof(ClignoterLEDs));
}
///
/// Fait clignoter aléatoirement les LEDs pour simuler l'activité.
///
private void ClignoterLEDs()
{
if (!estSousTension) return;
foreach (var ledRenderer in ledsRenderers)
{
if (ledRenderer == null) continue;
if (Random.value < 0.3f)
{
bool allumee = Random.value > 0.5f;
Color couleur = allumee ? couleurLEDAllumee : couleurLEDEteinte;
ledRenderer.material.color = couleur;
ledRenderer.material.SetColor("_EmissionColor",
allumee ? couleurLEDAllumee * intensiteLED : Color.black);
}
}
}
///
/// Retourne la consommation actuelle en watts (0 si éteint).
///
public float GetConsommationActuelle()
{
return estSousTension ? consommationWatts : 0f;
}
private Bounds GetBounds()
{
BoxCollider boxCol = GetComponent();
if (boxCol != null)
return new Bounds(boxCol.center, boxCol.size);
Renderer rend = GetComponent();
if (rend != null)
{
Bounds worldBounds = rend.bounds;
Vector3 localCenter = transform.InverseTransformPoint(worldBounds.center);
Vector3 localSize = new Vector3(
worldBounds.size.x / transform.lossyScale.x,
worldBounds.size.y / transform.lossyScale.y,
worldBounds.size.z / transform.lossyScale.z
);
return new Bounds(localCenter, localSize);
}
return new Bounds(Vector3.zero, new Vector3(0.48f, 0.044f, 0.7f));
}
}