306 lines
10 KiB
C#
306 lines
10 KiB
C#
using UnityEngine;
|
|
using System.Collections.Generic;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
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<Renderer> ledsRenderers = new List<Renderer>();
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Génère les LEDs d'activité sur la face avant de l'équipement.
|
|
/// </summary>
|
|
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<Collider>();
|
|
if (ledCol != null)
|
|
{
|
|
if (Application.isPlaying) Destroy(ledCol);
|
|
else DestroyImmediate(ledCol);
|
|
}
|
|
|
|
// Material noir par défaut
|
|
Renderer rend = ledObj.GetComponent<Renderer>();
|
|
if (rend != null)
|
|
{
|
|
rend.material = new Material(Shader.Find("Standard"));
|
|
rend.material.color = couleurLEDEteinte;
|
|
}
|
|
|
|
ledsRenderers.Add(rend);
|
|
}
|
|
|
|
_ledsGenerees = true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public void VerifierAlimentation()
|
|
{
|
|
bool ancienEtat = estSousTension;
|
|
|
|
PortAlimentation[] ports = GetComponentsInChildren<PortAlimentation>();
|
|
|
|
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<AmbianceSonore>();
|
|
if (ambiance != null)
|
|
ambiance.RecalculerAmbiance();
|
|
|
|
// v7.1 : propager l'etat sous-tension au EtatEquipementNetworkSync (pour rejoin)
|
|
if (Mirror.NetworkServer.active)
|
|
{
|
|
EtatEquipementNetworkSync sync = GetComponent<EtatEquipementNetworkSync>();
|
|
if (sync == null) sync = GetComponentInParent<EtatEquipementNetworkSync>();
|
|
if (sync != null) sync.ServerSyncEtat();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Met à jour l'apparence visuelle selon l'état d'alimentation.
|
|
/// </summary>
|
|
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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fait clignoter aléatoirement les LEDs pour simuler l'activité.
|
|
/// </summary>
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retourne la consommation actuelle en watts (0 si éteint).
|
|
/// </summary>
|
|
public float GetConsommationActuelle()
|
|
{
|
|
return estSousTension ? consommationWatts : 0f;
|
|
}
|
|
|
|
private Bounds GetBounds()
|
|
{
|
|
BoxCollider boxCol = GetComponent<BoxCollider>();
|
|
if (boxCol != null)
|
|
return new Bounds(boxCol.center, boxCol.size);
|
|
|
|
Renderer rend = GetComponent<Renderer>();
|
|
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));
|
|
}
|
|
} |