Files
Nitrox/NitroxClient/GameLogic/Spawning/Metadata/Processor/CyclopsMetadataProcessor.cs
2025-07-06 00:23:46 +02:00

175 lines
5.8 KiB
C#

using NitroxClient.Communication;
using NitroxClient.Communication.Abstract;
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
using NitroxClient.Unity.Helper;
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
using NitroxModel.Packets;
using UnityEngine;
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
public class CyclopsMetadataProcessor : EntityMetadataProcessor<CyclopsMetadata>
{
private readonly IPacketSender packetSender;
private readonly LiveMixinManager liveMixinManager;
public CyclopsMetadataProcessor(IPacketSender packetSender, LiveMixinManager liveMixinManager)
{
this.packetSender = packetSender;
this.liveMixinManager = liveMixinManager;
}
public override void ProcessMetadata(GameObject cyclops, CyclopsMetadata metadata)
{
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
{
SetEngineMode(cyclops, (CyclopsMotorMode.CyclopsMotorModes)metadata.EngineMode);
ChangeSilentRunning(cyclops, metadata.SilentRunningOn);
ChangeShieldMode(cyclops, metadata.ShieldOn);
ChangeSonarMode(cyclops, metadata.SonarOn);
SetEngineState(cyclops, metadata.EngineOn);
SetHealth(cyclops, metadata.Health);
SetDestroyed(cyclops, metadata.IsDestroyed);
}
}
private void SetEngineState(GameObject cyclops, bool isOn)
{
CyclopsEngineChangeState engineState = cyclops.RequireComponentInChildren<CyclopsEngineChangeState>(true);
if (isOn == engineState.motorMode.engineOn)
{
// engine state is the same - nothing to do.
return;
}
// During initial sync or when the cyclops HUD isn't shown (from outside of the cyclops)
if (Player.main.currentSub != engineState.subRoot)
{
engineState.startEngine = isOn;
engineState.subRoot.BroadcastMessage(nameof(CyclopsMotorMode.InvokeChangeEngineState), isOn, SendMessageOptions.RequireReceiver);
engineState.invalidButton = true;
engineState.Invoke(nameof(CyclopsEngineChangeState.ResetInvalidButton), 2.5f);
}
// When inside of the cyclops, we play the cinematics
else
{
// To invoke the whole OnClick method we need to set the right parameters first
engineState.invalidButton = false;
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
{
engineState.OnClick();
}
}
}
private void SetEngineMode(GameObject cyclops, CyclopsMotorMode.CyclopsMotorModes mode)
{
foreach (CyclopsMotorModeButton button in cyclops.GetComponentsInChildren<CyclopsMotorModeButton>(true))
{
// At initial sync, this kind of processor is executed before the Start()
if (!button.subRoot)
{
button.Start();
}
button.SetCyclopsMotorMode(mode);
}
}
private void ChangeSilentRunning(GameObject cyclops, bool isOn)
{
CyclopsSilentRunningAbilityButton ability = cyclops.RequireComponentInChildren<CyclopsSilentRunningAbilityButton>(true);
if (isOn == ability.active)
{
return;
}
Log.Debug($"Set silent running to {isOn} for cyclops");
ability.active = isOn;
if (isOn)
{
ability.image.sprite = ability.activeSprite;
ability.subRoot.BroadcastMessage("RigForSilentRunning");
ability.InvokeRepeating(nameof(CyclopsSilentRunningAbilityButton.SilentRunningIteration), 0f, ability.silentRunningIteration);
}
else
{
ability.image.sprite = ability.inactiveSprite;
ability.subRoot.BroadcastMessage("SecureFromSilentRunning");
ability.CancelInvoke(nameof(CyclopsSilentRunningAbilityButton.SilentRunningIteration));
}
}
private void ChangeShieldMode(GameObject cyclops, bool isOn)
{
CyclopsShieldButton shield = cyclops.GetComponentInChildren<CyclopsShieldButton>(true);
if (!shield)
{
// may not have a shield installed.
return;
}
bool isShieldOn = shield.activeSprite == shield.image.sprite;
if (isShieldOn == isOn)
{
return;
}
if (isOn)
{
shield.StartShield();
}
else
{
shield.StopShield();
}
}
private void ChangeSonarMode(GameObject cyclops, bool isOn)
{
CyclopsSonarButton sonarButton = cyclops.GetComponentInChildren<CyclopsSonarButton>(true);
if (sonarButton && sonarButton.sonarActive != isOn)
{
if (isOn)
{
sonarButton.TurnOnSonar();
}
else
{
sonarButton.TurnOffSonar();
}
}
}
private void SetHealth(GameObject gameObject, float health)
{
LiveMixin liveMixin = gameObject.RequireComponentInChildren<LiveMixin>(true);
liveMixinManager.SyncRemoteHealth(liveMixin, health);
}
private void SetDestroyed(GameObject gameObject, bool isDestroyed)
{
CyclopsDestructionEvent destructionEvent = gameObject.RequireComponentInChildren<CyclopsDestructionEvent>(true);
// Don't play VFX and SFX if the Cyclops is already destroyed or was spawned in as destroyed
if (destructionEvent.subRoot.subDestroyed == isDestroyed) return;
if (isDestroyed)
{
// Use packet suppressor as sentinel so the patch callback knows not to spawn loot
using (PacketSuppressor<EntitySpawnedByClient>.Suppress())
{
destructionEvent.DestroyCyclops();
}
}
else
{
destructionEvent.RestoreCyclops();
}
}
}