first commit
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
using NitroxModel.Core;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
|
||||
public abstract class EntityMetadataProcessor<TMetadata> : IEntityMetadataProcessor where TMetadata : EntityMetadata
|
||||
{
|
||||
public abstract void ProcessMetadata(GameObject gameObject, TMetadata metadata);
|
||||
|
||||
public void ProcessMetadata(GameObject gameObject, EntityMetadata metadata)
|
||||
{
|
||||
ProcessMetadata(gameObject, (TMetadata)metadata);
|
||||
}
|
||||
|
||||
protected TService Resolve<TService>() where TService : class
|
||||
{
|
||||
return NitroxServiceLocator.Cache<TService>.Value;
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
|
||||
public interface IEntityMetadataProcessor
|
||||
{
|
||||
public abstract void ProcessMetadata(GameObject gameObject, EntityMetadata metadata);
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.DataStructures.Unity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
|
||||
public abstract class VehicleMetadataProcessor<T> : EntityMetadataProcessor<T> where T : VehicleMetadata
|
||||
{
|
||||
private readonly LiveMixinManager liveMixinManager;
|
||||
|
||||
public VehicleMetadataProcessor(LiveMixinManager liveMixinManager)
|
||||
{
|
||||
this.liveMixinManager = liveMixinManager;
|
||||
}
|
||||
|
||||
protected void SetHealth(GameObject gameObject, float health)
|
||||
{
|
||||
LiveMixin liveMixin = gameObject.RequireComponentInChildren<LiveMixin>(true);
|
||||
liveMixinManager.SyncRemoteHealth(liveMixin, health);
|
||||
}
|
||||
|
||||
protected void SetNameAndColors(SubName subName, string text, NitroxVector3[] nitroxColor) => SubNameInputMetadataProcessor.SetNameAndColors(subName, text, nitroxColor);
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class BatteryMetadataProcessor : EntityMetadataProcessor<BatteryMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, BatteryMetadata metadata)
|
||||
{
|
||||
Battery battery = gameObject.GetComponent<Battery>();
|
||||
|
||||
if (battery)
|
||||
{
|
||||
battery._charge = metadata.Charge;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Could not find Battery on {gameObject.name}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using NitroxClient.Communication;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class ConstructorMetadataProcessor : EntityMetadataProcessor<ConstructorMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, ConstructorMetadata metadata)
|
||||
{
|
||||
if (gameObject.TryGetComponent(out Constructor constructor))
|
||||
{
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
constructor.Deploy(metadata.Deployed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"[{nameof(ConstructorMetadataProcessor)}] Could not find {nameof(Constructor)} on {gameObject.name}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class CrafterMetadataProcessor : EntityMetadataProcessor<CrafterMetadata>
|
||||
{
|
||||
// small increase to prevent this player from swiping item from remote player
|
||||
public const float ANTI_GRIEF_DURATION_BUFFER = 0.2f;
|
||||
|
||||
public override void ProcessMetadata(GameObject gameObject, CrafterMetadata metadata)
|
||||
{
|
||||
if (metadata.TechType == null)
|
||||
{
|
||||
EnsureCrafterReset(gameObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpawnItemInCrafter(gameObject, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureCrafterReset(GameObject gameObject)
|
||||
{
|
||||
CrafterLogic crafterLogic = gameObject.RequireComponentInChildren<CrafterLogic>(true);
|
||||
crafterLogic.ResetCrafter();
|
||||
}
|
||||
|
||||
private void SpawnItemInCrafter(GameObject gameObject, CrafterMetadata metadata)
|
||||
{
|
||||
GhostCrafter ghostCrafter = gameObject.RequireComponentInChildren<GhostCrafter>(true);
|
||||
|
||||
float elapsedFromStart = DayNightCycle.main.timePassedAsFloat - metadata.StartTime;
|
||||
|
||||
// If a craft started way in the past, set duration to 0.01 (the craft function will not work with 0)
|
||||
// Keeping track of both the duration and start time allows us to solve use-cases such as reloading
|
||||
// when an item is being crafted or not picked up yet.
|
||||
float duration = Mathf.Max(metadata.Duration - elapsedFromStart + ANTI_GRIEF_DURATION_BUFFER, 0.01f);
|
||||
|
||||
ghostCrafter.logic.Craft(metadata.TechType.ToUnity(), duration);
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class CrashHomeMetadataProcessor : EntityMetadataProcessor<CrashHomeMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, CrashHomeMetadata metadata)
|
||||
{
|
||||
if (gameObject.TryGetComponent(out CrashHome crashHome))
|
||||
{
|
||||
crashHome.spawnTime = metadata.SpawnTime;
|
||||
UpdateCrashHomeOpen(crashHome);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"[{nameof(CrashHomeMetadataProcessor)}] Could not find {nameof(CrashHome)} on {gameObject}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateCrashHomeOpen(CrashHome crashHome)
|
||||
{
|
||||
// From CrashHome.Update
|
||||
// We also add a distance detection to take into account if the crash is still in the home or not
|
||||
bool isCrashResting = crashHome.crash && crashHome.crash.IsResting() && crashHome &&
|
||||
Vector3.Distance(crashHome.transform.position, crashHome.crash.transform.position) < 1f;
|
||||
crashHome.animator.SetBool(AnimatorHashID.attacking, !isCrashResting);
|
||||
crashHome.prevClosed = isCrashResting;
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
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 CyclopsLightingMetadataProcessor : EntityMetadataProcessor<CyclopsLightingMetadata>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public CyclopsLightingMetadataProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void ProcessMetadata(GameObject gameObject, CyclopsLightingMetadata metadata)
|
||||
{
|
||||
CyclopsLightingPanel lighting = gameObject.RequireComponentInChildren<CyclopsLightingPanel>(true);
|
||||
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
SetInternalLighting(lighting, metadata.InternalLightsOn);
|
||||
SetFloodLighting(lighting, metadata.FloodLightsOn);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetInternalLighting(CyclopsLightingPanel lighting, bool isOn)
|
||||
{
|
||||
if (lighting.lightingOn == isOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lighting.lightingOn = !lighting.lightingOn;
|
||||
lighting.cyclopsRoot.ForceLightingState(lighting.lightingOn);
|
||||
FMODAsset asset = !lighting.lightingOn ? lighting.vn_lightsOff : lighting.vn_lightsOn;
|
||||
FMODUWE.PlayOneShot(asset, lighting.transform.position, 1f);
|
||||
lighting.UpdateLightingButtons();
|
||||
}
|
||||
|
||||
private void SetFloodLighting(CyclopsLightingPanel lighting, bool isOn)
|
||||
{
|
||||
if (lighting.floodlightsOn == isOn)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lighting.floodlightsOn = !lighting.floodlightsOn;
|
||||
lighting.SetExternalLighting(lighting.floodlightsOn);
|
||||
FMODAsset asset = !lighting.floodlightsOn ? lighting.vn_floodlightsOff : lighting.vn_floodlightsOn;
|
||||
FMODUWE.PlayOneShot(asset, lighting.transform.position, 1f);
|
||||
lighting.UpdateLightingButtons();
|
||||
}
|
||||
}
|
@@ -0,0 +1,174 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class EatableMetadataProcessor : EntityMetadataProcessor<EatableMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, EatableMetadata metadata)
|
||||
{
|
||||
if (gameObject.TryGetComponent(out Eatable eatable))
|
||||
{
|
||||
eatable.SetDecomposes(true);
|
||||
eatable.timeDecayStart = metadata.TimeDecayStart;
|
||||
}
|
||||
if (gameObject.TryGetComponent(out LiveMixin liveMixin))
|
||||
{
|
||||
Resolve<LiveMixinManager>().SyncRemoteHealth(liveMixin, 0);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class EggMetadataProcessor : EntityMetadataProcessor<EggMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, EggMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out CreatureEgg creatureEgg))
|
||||
{
|
||||
Log.Error($"[{nameof(EggMetadataProcessor)}] Could not find {nameof(CreatureEgg)} on {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (metadata.TimeStartHatching == -1f)
|
||||
{
|
||||
// If the egg is not in a water park we only need its progress value
|
||||
creatureEgg.progress = metadata.Progress;
|
||||
return;
|
||||
}
|
||||
|
||||
// If the egg is in a water park we only need its time start hatching value
|
||||
// the current progress will be automatically computed by UpdateProgress()
|
||||
creatureEgg.timeStartHatching = metadata.TimeStartHatching;
|
||||
|
||||
// While being fully loaded, the base is inactive and coroutines shouldn't be started (they'll throw an exception)
|
||||
// To avoid, that we postpone their execution to 1 more second which is enough because time is frozen during initial sync
|
||||
if (Multiplayer.Main && !Multiplayer.Main.InitialSyncCompleted &&
|
||||
creatureEgg.timeStartHatching + creatureEgg.GetHatchDuration() < DayNightCycle.main.timePassedAsFloat)
|
||||
{
|
||||
creatureEgg.timeStartHatching = DayNightCycle.main.timePassedAsFloat + 1 - creatureEgg.GetHatchDuration();
|
||||
}
|
||||
|
||||
creatureEgg.UpdateProgress();
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class EntitySignMetadataProcessor : EntityMetadataProcessor<EntitySignMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, EntitySignMetadata metadata)
|
||||
{
|
||||
uGUI_SignInput sign = gameObject.GetComponentInChildren<uGUI_SignInput>(true);
|
||||
if (sign)
|
||||
{
|
||||
sign.text = metadata.Text;
|
||||
sign.colorIndex = metadata.ColorIndex;
|
||||
sign.elementsState = metadata.Elements;
|
||||
sign.scaleIndex = metadata.ScaleIndex;
|
||||
sign.SetBackground(metadata.Background);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class EscapePodMetadataProcessor : EntityMetadataProcessor<EscapePodMetadata>
|
||||
{
|
||||
// For metadata changes outside initial sync we only care about broken -> repaired
|
||||
public override void ProcessMetadata(GameObject gameObject, EscapePodMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out EscapePod pod))
|
||||
{
|
||||
Log.Error($"[{nameof(EscapePodMetadataProcessor)}] Could not get the EscapePod component from the provided gameobject.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pod.liveMixin.IsFullHealth() && metadata.PodRepaired)
|
||||
{
|
||||
pod.liveMixin.health = pod.liveMixin.maxHealth;
|
||||
pod.healthScalar = 1;
|
||||
pod.damageEffectsShowing = true;
|
||||
pod.UpdateDamagedEffects();
|
||||
pod.OnRepair();
|
||||
}
|
||||
|
||||
if (!pod.radioSpawner.spawnedObj.TryGetComponent(out Radio radio))
|
||||
{
|
||||
Log.Error($"[{nameof(EscapePodMetadataProcessor)}] Could not get Radio from EscapePod.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!radio.liveMixin.IsFullHealth() && metadata.RadioRepaired)
|
||||
{
|
||||
radio.liveMixin.AddHealth(radio.liveMixin.maxHealth);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies repaired state without animations and minimal audio playback
|
||||
/// </summary>
|
||||
public static void ProcessInitialSyncMetadata(EscapePod pod, Radio radio, EscapePodMetadata metadata)
|
||||
{
|
||||
if (metadata.PodRepaired)
|
||||
{
|
||||
pod.liveMixin.health = pod.liveMixin.maxHealth;
|
||||
pod.healthScalar = 1;
|
||||
pod.damageEffectsShowing = true; // Needs to be set to true for UpdateDamagedEffects() to function
|
||||
pod.UpdateDamagedEffects();
|
||||
pod.vfxSpawner.SpawnManual(); // Spawn vfx to instantly disable it so no smoke is fading after player has joined
|
||||
pod.vfxSpawner.spawnedObj.SetActive(false);
|
||||
pod.lightingController.SnapToState(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
IntroLifepodDirector introLifepodDirector = pod.GetComponent<IntroLifepodDirector>();
|
||||
introLifepodDirector.OnProtoDeserializeObjectTree(null);
|
||||
introLifepodDirector.ToggleActiveObjects(false);
|
||||
pod.lightingController.SnapToState(2);
|
||||
}
|
||||
|
||||
if (metadata.RadioRepaired)
|
||||
{
|
||||
radio.liveMixin.health = radio.liveMixin.maxHealth;
|
||||
if (radio.liveMixin.loopingDamageEffectObj)
|
||||
{
|
||||
Object.Destroy(radio.liveMixin.loopingDamageEffectObj);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pod.DamageRadio();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
using NitroxClient.Communication;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class ExosuitMetadataProcessor : VehicleMetadataProcessor<ExosuitMetadata>
|
||||
{
|
||||
public ExosuitMetadataProcessor(LiveMixinManager liveMixinManager) : base(liveMixinManager) { }
|
||||
|
||||
public override void ProcessMetadata(GameObject gameObject, ExosuitMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out Exosuit exosuit))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(ExosuitMetadataProcessor)}] Could not find {nameof(Exosuit)} on {gameObject}");
|
||||
return;
|
||||
}
|
||||
if (!gameObject.TryGetComponent(out SubName subName))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(ExosuitMetadataProcessor)}] Could not find {nameof(SubName)} on {gameObject}");
|
||||
return;
|
||||
}
|
||||
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
SetHealth(gameObject, metadata.Health);
|
||||
SetNameAndColors(subName, metadata.Name, metadata.Colors);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class FireExtinguisherHolderMetadataProcessor : EntityMetadataProcessor<FireExtinguisherHolderMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, FireExtinguisherHolderMetadata metadata)
|
||||
{
|
||||
FireExtinguisherHolder holder = gameObject.GetComponent<FireExtinguisherHolder>();
|
||||
|
||||
if (holder)
|
||||
{
|
||||
holder.fuel = metadata.Fuel;
|
||||
holder.hasTank = metadata.HasExtinguisher;
|
||||
holder.tankObject.SetActive(metadata.HasExtinguisher);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Could not find FireExtinguisherHolder on {gameObject.name}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class FlashlightMetadataProcessor : EntityMetadataProcessor<FlashlightMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, FlashlightMetadata metadata)
|
||||
{
|
||||
FlashLight flashLight = gameObject.GetComponent<FlashLight>();
|
||||
|
||||
if (flashLight)
|
||||
{
|
||||
ToggleLights lights = flashLight.gameObject.GetComponent<ToggleLights>();
|
||||
|
||||
if (lights)
|
||||
{
|
||||
lights.lightsActive = metadata.On;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Could not find ToggleLights on {flashLight.name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Could not find FlashLight on {gameObject.name}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,63 @@
|
||||
using NitroxClient.Communication;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class FruitPlantMetadataProcessor : EntityMetadataProcessor<FruitPlantMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, FruitPlantMetadata metadata)
|
||||
{
|
||||
// Two cases:
|
||||
// 1. The entity with an id directly has a FruitPlant onto it
|
||||
if (gameObject.TryGetComponent(out FruitPlant fruitPlant))
|
||||
{
|
||||
ProcessMetadata(fruitPlant, metadata);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. The entity with an id has a Plantable (located in the plot's storage),
|
||||
// we want to access the FruitPlant component which is on the spawned plant object
|
||||
if (!gameObject.TryGetComponent(out Plantable plantable))
|
||||
{
|
||||
Log.Error($"[{nameof(FruitPlantMetadataProcessor)}] Could not find {nameof(FruitPlant)} related to {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plantable.linkedGrownPlant)
|
||||
{
|
||||
// This is an error which will happen quite often since this metadata
|
||||
// is applied from PlantableMetadataProcessor even when linkedGrownPlant isn't available yet
|
||||
return;
|
||||
}
|
||||
|
||||
if (!plantable.linkedGrownPlant.TryGetComponent(out fruitPlant))
|
||||
{
|
||||
Log.Error($"[{nameof(FruitPlantMetadataProcessor)}] Could not find {nameof(FruitPlant)} on {gameObject.name}'s linkedGrownPlant {plantable.linkedGrownPlant.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessMetadata(fruitPlant, metadata);
|
||||
}
|
||||
|
||||
private static void ProcessMetadata(FruitPlant fruitPlant, FruitPlantMetadata metadata)
|
||||
{
|
||||
// Inspired by FruitPlant.Initialize
|
||||
fruitPlant.inactiveFruits.Clear();
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
for (int i = 0; i < fruitPlant.fruits.Length; i++)
|
||||
{
|
||||
fruitPlant.fruits[i].SetPickedState(metadata.PickedStates[i]);
|
||||
if (metadata.PickedStates[i])
|
||||
{
|
||||
fruitPlant.inactiveFruits.Add(fruitPlant.fruits[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fruitPlant.timeNextFruit = metadata.TimeNextFruit;
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class IncubatorMetadataProcessor : EntityMetadataProcessor<IncubatorMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, IncubatorMetadata metadata)
|
||||
{
|
||||
if (metadata.Powered)
|
||||
{
|
||||
IncubatorActivationTerminal terminal = gameObject.GetComponentInChildren<IncubatorActivationTerminal>();
|
||||
terminal.incubator.SetPowered(true);
|
||||
terminal.onUseGoal?.Trigger();
|
||||
terminal.CloseDeck();
|
||||
}
|
||||
|
||||
if (metadata.Hatched)
|
||||
{
|
||||
Incubator incubator = gameObject.GetComponentInChildren<Incubator>();
|
||||
incubator.hatched = true;
|
||||
incubator.OnHatched();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class KeypadMetadataProcessor : EntityMetadataProcessor<KeypadMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, KeypadMetadata metadata)
|
||||
{
|
||||
Log.Debug($"Received keypad metadata change for {gameObject.name} with data of {metadata}");
|
||||
|
||||
KeypadDoorConsole keypad = gameObject.GetComponent<KeypadDoorConsole>();
|
||||
keypad.unlocked = metadata.Unlocked;
|
||||
|
||||
if (metadata.Unlocked)
|
||||
{
|
||||
if (keypad.root)
|
||||
{
|
||||
keypad.root.BroadcastMessage("UnlockDoor");
|
||||
}
|
||||
else
|
||||
{
|
||||
keypad.BroadcastMessage("UnlockDoor");
|
||||
}
|
||||
|
||||
keypad.UnlockDoor();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class PlantableMetadataProcessor(FruitPlantMetadataProcessor fruitPlantMetadataProcessor) : EntityMetadataProcessor<PlantableMetadata>
|
||||
{
|
||||
private readonly FruitPlantMetadataProcessor fruitPlantMetadataProcessor = fruitPlantMetadataProcessor;
|
||||
|
||||
public override void ProcessMetadata(GameObject gameObject, PlantableMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out Plantable plantable))
|
||||
{
|
||||
Log.Error($"[{nameof(PlantableMetadataProcessor)}] Could not find {nameof(Plantable)} on {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
// For Plantables which were replaced by the GrowingPlant object
|
||||
if (plantable.growingPlant)
|
||||
{
|
||||
plantable.growingPlant.timeStartGrowth = metadata.TimeStartGrowth;
|
||||
}
|
||||
// For regular Plantables
|
||||
else if (plantable.model.TryGetComponent(out GrowingPlant growingPlant))
|
||||
{
|
||||
// Calculation from GrowingPlant.GetProgress
|
||||
if (metadata.TimeStartGrowth == -1f)
|
||||
{
|
||||
plantable.plantAge = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the reversed calculation because we're looking for "progress" while we already know timeStartGrowth
|
||||
plantable.plantAge = Mathf.Clamp((DayNightCycle.main.timePassedAsFloat - metadata.TimeStartGrowth) / growingPlant.GetGrowthDuration(), 0f, growingPlant.maxProgress);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Refer to the TODO in PlantableMetadata
|
||||
if (metadata.FruitPlantMetadata != null)
|
||||
{
|
||||
fruitPlantMetadataProcessor.ProcessMetadata(gameObject, metadata.FruitPlantMetadata);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NitroxClient.GameLogic.PlayerLogic;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
using static NitroxModel.DataStructures.GameLogic.Entities.Metadata.PlayerMetadata;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class PlayerMetadataProcessor : EntityMetadataProcessor<PlayerMetadata>
|
||||
{
|
||||
private NitroxId localPlayerId = null;
|
||||
public override void ProcessMetadata(GameObject gameObject, PlayerMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetIdOrWarn(out NitroxId id))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// The local player id should be static, therefor we can cache the id for performance
|
||||
if (localPlayerId == null && !Player.main.TryGetIdOrWarn(out localPlayerId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (id == localPlayerId)
|
||||
{
|
||||
UpdateForLocalPlayer(metadata);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateForRemotePlayer(gameObject, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateForLocalPlayer(PlayerMetadata metadata)
|
||||
{
|
||||
ItemsContainer currentItems = Inventory.Get().container;
|
||||
Equipment equipment = Inventory.main.equipment;
|
||||
|
||||
foreach (EquippedItem equippedItem in metadata.EquippedItems)
|
||||
{
|
||||
InventoryItem inventoryItem = currentItems.FirstOrDefault(item => item.item.TryGetNitroxId(out NitroxId id) && equippedItem.Id == id);
|
||||
|
||||
// It is OK if we don't find the item, this could be a rebroadcast and we've already equipped the item.
|
||||
if (inventoryItem != null)
|
||||
{
|
||||
Pickupable pickupable = inventoryItem.item;
|
||||
currentItems.RemoveItem(pickupable, true);
|
||||
|
||||
inventoryItem.container = equipment;
|
||||
pickupable.Reparent(equipment.tr);
|
||||
equipment.equipment[equippedItem.Slot] = inventoryItem;
|
||||
|
||||
equipment.UpdateCount(pickupable.GetTechType(), true);
|
||||
Equipment.SendEquipmentEvent(pickupable, 0, equipment.owner, equippedItem.Slot);
|
||||
equipment.NotifyEquip(equippedItem.Slot, inventoryItem);
|
||||
|
||||
currentItems.RemoveItem(inventoryItem.item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateForRemotePlayer(GameObject gameObject, PlayerMetadata metadata)
|
||||
{
|
||||
Log.Info("Calling UpdateForRemotePlayer");
|
||||
RemotePlayerIdentifier remotePlayerId = gameObject.RequireComponent<RemotePlayerIdentifier>();
|
||||
|
||||
List<TechType> equippedTechTypes = metadata.EquippedItems.Select(x => x.TechType.ToUnity()).ToList();
|
||||
remotePlayerId.RemotePlayer.UpdateEquipmentVisibility(equippedTechTypes);
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class PrecursorDoorwayMetadataProcessor : EntityMetadataProcessor<PrecursorDoorwayMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, PrecursorDoorwayMetadata metadata)
|
||||
{
|
||||
Log.Info($"Received precursor door metadata change for {gameObject.name} with data of {metadata}");
|
||||
|
||||
PrecursorDoorway precursorDoorway = gameObject.GetComponent<PrecursorDoorway>();
|
||||
precursorDoorway.isOpen = metadata.IsOpen;
|
||||
|
||||
if (metadata.IsOpen)
|
||||
{
|
||||
precursorDoorway.BroadcastMessage("DisableField");
|
||||
}
|
||||
else
|
||||
{
|
||||
precursorDoorway.BroadcastMessage("EnableField");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class PrecursorKeyTerminalMetadataProcessor : EntityMetadataProcessor<PrecursorKeyTerminalMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, PrecursorKeyTerminalMetadata metadata)
|
||||
{
|
||||
Log.Debug($"Received precursor key terminal metadata change for {gameObject.name} with data of {metadata}");
|
||||
|
||||
PrecursorKeyTerminal precursorKeyTerminal = gameObject.GetComponent<PrecursorKeyTerminal>();
|
||||
if (precursorKeyTerminal)
|
||||
{
|
||||
precursorKeyTerminal.slotted = metadata.Slotted;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class PrecursorTeleporterActivationTerminalMetadataProcessor : EntityMetadataProcessor<PrecursorTeleporterActivationTerminalMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, PrecursorTeleporterActivationTerminalMetadata metadata)
|
||||
{
|
||||
Log.Debug($"Received precursor teleporter activation terminal metadata change for {gameObject.name} with data of {metadata}");
|
||||
|
||||
PrecursorTeleporterActivationTerminal precursorTeleporterActivationTerminal = gameObject.GetComponent<PrecursorTeleporterActivationTerminal>();
|
||||
if (precursorTeleporterActivationTerminal)
|
||||
{
|
||||
precursorTeleporterActivationTerminal.unlocked = metadata.Unlocked;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class PrecursorTeleporterMetadataProcessor : EntityMetadataProcessor<PrecursorTeleporterMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, PrecursorTeleporterMetadata metadata)
|
||||
{
|
||||
Log.Debug($"Received precursor teleporter metadata change for {gameObject.name} with data of {metadata}");
|
||||
|
||||
PrecursorTeleporter precursorTeleporter = gameObject.GetComponent<PrecursorTeleporter>();
|
||||
if (precursorTeleporter)
|
||||
{
|
||||
precursorTeleporter.ToggleDoor(metadata.IsOpen);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
using NitroxClient.Communication;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class RadiationMetadataProcessor : EntityMetadataProcessor<RadiationMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, RadiationMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out LiveMixin liveMixin))
|
||||
{
|
||||
Log.Error($"[{nameof(RadiationMetadataProcessor)}] Couldn't find LiveMixin on {gameObject}");
|
||||
return;
|
||||
}
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
Resolve<LiveMixinManager>().SyncRemoteHealth(liveMixin, metadata.Health);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,157 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NitroxClient.Communication;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
using static Rocket;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class RocketMetadataProcessor : EntityMetadataProcessor<RocketMetadata>
|
||||
{
|
||||
// For newly connected players, we will only build the previous stage with construction bots for a certain time period.
|
||||
private const float MAX_ALLOWABLE_TIME_FOR_CONSTRUCTOR_BOTS = 10;
|
||||
|
||||
/** Rocket states :
|
||||
* 0 : Launch Platform
|
||||
* 1 : Gantry
|
||||
* 2 : Boosters
|
||||
* 3 : Fuel Reserve
|
||||
* 4 : Cockpit
|
||||
* 5 : Final rocket
|
||||
**/
|
||||
public override void ProcessMetadata(GameObject gameObject, RocketMetadata metadata)
|
||||
{
|
||||
Rocket rocket = gameObject.GetComponent<Rocket>();
|
||||
|
||||
if (!rocket)
|
||||
{
|
||||
Log.Error($"Could not find Rocket on {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
UpdateElevator(rocket, metadata);
|
||||
UpdateStage(rocket, metadata);
|
||||
UpdatePreflightChecks(rocket, metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateElevator(Rocket rocket, RocketMetadata metadata)
|
||||
{
|
||||
// elevators will only be present on this model after the gantry (p1) is built
|
||||
if (rocket.currentRocketStage > 1)
|
||||
{
|
||||
rocket.elevatorPosition = metadata.ElevatorPosition;
|
||||
rocket.elevatorState = (RocketElevatorStates)metadata.ElevatorState;
|
||||
rocket.SetElevatorPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateStage(Rocket rocket, RocketMetadata metadata)
|
||||
{
|
||||
if (rocket.currentRocketStage == metadata.CurrentStage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool allowConstructorBots = DayNightCycle.main.timePassedAsFloat - metadata.LastStageTransitionTime < MAX_ALLOWABLE_TIME_FOR_CONSTRUCTOR_BOTS;
|
||||
|
||||
RocketConstructor rocketConstructor = rocket.RequireComponentInChildren<RocketConstructor>(true);
|
||||
|
||||
for (int stage = rocket.currentRocketStage; stage < metadata.CurrentStage; stage++)
|
||||
{
|
||||
bool lastStageToBuild = stage == metadata.CurrentStage - 1;
|
||||
|
||||
GameObject build = rocket.StartRocketConstruction();
|
||||
|
||||
// We only want to use construction bots for the last constructed stage (just in case the client is out dated by multiple stages).
|
||||
// For all others, just force the completion of that stage.
|
||||
if (lastStageToBuild && allowConstructorBots)
|
||||
{
|
||||
rocketConstructor.SendBuildBots(build);
|
||||
}
|
||||
else
|
||||
{
|
||||
VFXConstructing vfxConstructing = build.GetComponent<VFXConstructing>();
|
||||
vfxConstructing.EndGracefully();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdatePreflightChecks(Rocket rocket, RocketMetadata metadata)
|
||||
{
|
||||
if (rocket.currentRocketStage < 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IEnumerable<PreflightCheck> completedChecks = metadata.PreflightChecks.Select(i => (PreflightCheck)i);
|
||||
|
||||
RocketPreflightCheckManager rocketPreflightCheckManager = rocket.RequireComponent<RocketPreflightCheckManager>();
|
||||
|
||||
foreach (PreflightCheck completedCheck in completedChecks)
|
||||
{
|
||||
if (!rocketPreflightCheckManager.preflightChecks.Contains(completedCheck))
|
||||
{
|
||||
CompletePreflightCheck(rocket, completedCheck);
|
||||
rocketPreflightCheckManager.CompletePreflightCheck(completedCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CompletePreflightCheck(Rocket rocket, PreflightCheck preflightCheck)
|
||||
{
|
||||
bool isCockpitCheck = preflightCheck == PreflightCheck.LifeSupport ||
|
||||
preflightCheck == PreflightCheck.PrimaryComputer;
|
||||
|
||||
if (isCockpitCheck)
|
||||
{
|
||||
CompleteCockpitPreflightCheck(rocket, preflightCheck);
|
||||
}
|
||||
else
|
||||
{
|
||||
CompleteBasicPreflightCheck(rocket, preflightCheck);
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteCockpitPreflightCheck(Rocket rocket, PreflightCheck preflightCheck)
|
||||
{
|
||||
CockpitSwitch[] cockpitSwitches = rocket.GetComponentsInChildren<CockpitSwitch>(true);
|
||||
|
||||
foreach (CockpitSwitch cockpitSwitch in cockpitSwitches)
|
||||
{
|
||||
if (!cockpitSwitch.completed && cockpitSwitch.preflightCheck == preflightCheck)
|
||||
{
|
||||
cockpitSwitch.animator.SetBool("Completed", true);
|
||||
cockpitSwitch.completed = true;
|
||||
|
||||
if (cockpitSwitch.collision)
|
||||
{
|
||||
cockpitSwitch.collision.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteBasicPreflightCheck(Rocket rocket, PreflightCheck preflightCheck)
|
||||
{
|
||||
ThrowSwitch[] throwSwitches = rocket.GetComponentsInChildren<ThrowSwitch>(true);
|
||||
|
||||
foreach (ThrowSwitch throwSwitch in throwSwitches)
|
||||
{
|
||||
if (!throwSwitch.completed && throwSwitch.preflightCheck == preflightCheck)
|
||||
{
|
||||
throwSwitch.animator.AliveOrNull()?.SetTrigger("Throw");
|
||||
throwSwitch.completed = true;
|
||||
throwSwitch.cinematicTrigger.showIconOnHandHover = false;
|
||||
throwSwitch.triggerCollider.enabled = false;
|
||||
throwSwitch.lamp.GetComponent<SkinnedMeshRenderer>().material = throwSwitch.completeMat;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class SeaTreaderMetadataProcessor : EntityMetadataProcessor<SeaTreaderMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, SeaTreaderMetadata metadata)
|
||||
{
|
||||
if (gameObject.TryGetComponent(out SeaTreader seaTreader))
|
||||
{
|
||||
if (!seaTreader.isInitialized)
|
||||
{
|
||||
seaTreader.InitializeOnce();
|
||||
}
|
||||
|
||||
seaTreader.reverseDirection = metadata.ReverseDirection;
|
||||
|
||||
float grazingTimeLeft = Math.Max(0, metadata.GrazingEndTime - DayNightCycle.main.timePassedAsFloat);
|
||||
|
||||
seaTreader.grazing = grazingTimeLeft > 0;
|
||||
seaTreader.grazingTimeLeft = grazingTimeLeft;
|
||||
|
||||
seaTreader.leashPosition = metadata.LeashPosition.ToUnity();
|
||||
seaTreader.leashPosition.y = gameObject.transform.position.y;
|
||||
seaTreader.isInitialized = true;
|
||||
seaTreader.InitializeAgain();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Could not find {nameof(SeaTreader)} on {gameObject.name}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class SealedDoorMetadataProcessor : EntityMetadataProcessor<SealedDoorMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, SealedDoorMetadata metadata)
|
||||
{
|
||||
Log.Info($"Received door metadata change for {gameObject.name} with data of {metadata}");
|
||||
|
||||
Sealed door = gameObject.GetComponent<Sealed>();
|
||||
door._sealed = metadata.Sealed;
|
||||
door.openedAmount = metadata.OpenedAmount;
|
||||
|
||||
LaserCutObject laseredObject = gameObject.GetComponent<LaserCutObject>();
|
||||
|
||||
if (laseredObject && door._sealed)
|
||||
{
|
||||
laseredObject.lastCutValue = door.openedAmount;
|
||||
laseredObject.ActivateFX();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
using NitroxClient.Communication;
|
||||
using NitroxClient.GameLogic.FMOD;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class SeamothMetadataProcessor : VehicleMetadataProcessor<SeamothMetadata>
|
||||
{
|
||||
public SeamothMetadataProcessor(LiveMixinManager liveMixinManager) : base(liveMixinManager)
|
||||
{ }
|
||||
|
||||
public override void ProcessMetadata(GameObject gameObject, SeamothMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out SeaMoth seamoth))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(SeamothMetadataProcessor)}] Could not find {nameof(SeaMoth)} on {gameObject}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gameObject.TryGetComponent(out SubName subName))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(SeamothMetadataProcessor)}] Could not find {nameof(SubName)} on {gameObject}");
|
||||
return;
|
||||
}
|
||||
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
SetLights(seamoth, metadata.LightsOn);
|
||||
SetHealth(seamoth.gameObject, metadata.Health);
|
||||
SetNameAndColors(subName, metadata.Name, metadata.Colors);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLights(SeaMoth seamoth, bool lightsOn)
|
||||
{
|
||||
using (FMODSystem.SuppressSendingSounds())
|
||||
{
|
||||
seamoth.toggleLights.SetLightsActive(lightsOn);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class StarshipDoorMetadataProcessor : EntityMetadataProcessor<StarshipDoorMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, StarshipDoorMetadata metadata)
|
||||
{
|
||||
StarshipDoor starshipDoor = gameObject.GetComponent<StarshipDoor>();
|
||||
starshipDoor.doorOpen = metadata.DoorOpen;
|
||||
starshipDoor.doorLocked = metadata.DoorLocked;
|
||||
if (metadata.DoorLocked)
|
||||
{
|
||||
starshipDoor.LockDoor();
|
||||
}
|
||||
else
|
||||
{
|
||||
starshipDoor.UnlockDoor();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class StayAtLeashPositionMetadataProcessor : EntityMetadataProcessor<StayAtLeashPositionMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, StayAtLeashPositionMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out Creature creature))
|
||||
{
|
||||
Log.Error($"Could not find {nameof(Creature)} on {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!creature.isInitialized)
|
||||
{
|
||||
// TODO: When #2137 is merged, only a MetadataHolder to the creature and postfix patch creature.Start to consume it
|
||||
creature.InitializeOnce();
|
||||
creature.isInitialized = true;
|
||||
}
|
||||
creature.leashPosition = metadata.LeashPosition.ToUnity();
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
using System.Linq;
|
||||
using NitroxClient.Communication;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using NitroxModel.DataStructures.Unity;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class SubNameInputMetadataProcessor : EntityMetadataProcessor<SubNameInputMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, SubNameInputMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out SubNameInput subNameInput))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(SubNameInputMetadataProcessor)}] Could not find {nameof(SubNameInput)} on {gameObject}");
|
||||
return;
|
||||
}
|
||||
|
||||
SubName subName = subNameInput.target;
|
||||
if (!subName && !subNameInput.TryGetComponent(out subName))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(SubNameInputMetadataProcessor)}] {gameObject}'s {nameof(subNameInput)} doesn't have a target.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the SubNameInput's object is active so that it receives events from its SubName
|
||||
gameObject.SetActive(true);
|
||||
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
// Name and color applying must be applied before SelectedColorIndex
|
||||
SetNameAndColors(subName, metadata.Name, metadata.Colors);
|
||||
subNameInput.SetSelected(metadata.SelectedColorIndex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetNameAndColors(SubName subName, string text, NitroxVector3[] nitroxColors)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
subName.DeserializeName(text);
|
||||
}
|
||||
if (nitroxColors != null)
|
||||
{
|
||||
Vector3[] colors = nitroxColors.Select(c => c.ToUnity()).ToArray();
|
||||
subName.DeserializeColors(colors);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class WaterParkCreatureMetadataProcessor : EntityMetadataProcessor<WaterParkCreatureMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, WaterParkCreatureMetadata metadata)
|
||||
{
|
||||
if (!gameObject.TryGetComponent(out WaterParkCreature waterParkCreature))
|
||||
{
|
||||
Log.Error($"[{nameof(WaterParkCreatureMetadataProcessor)}] Could not find {nameof(WaterParkCreature)} on {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (waterParkCreature.currentWaterPark)
|
||||
{
|
||||
// MatureTime is important for fishes that are already in a WaterPark, to calculate the right age
|
||||
waterParkCreature.matureTime = metadata.MatureTime;
|
||||
double startTime = metadata.MatureTime - waterParkCreature.data.growingPeriod;
|
||||
waterParkCreature.age = Mathf.InverseLerp((float)startTime, (float)metadata.MatureTime, DayNightCycle.main.timePassedAsFloat);
|
||||
waterParkCreature.timeNextBreed = metadata.TimeNextBreed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Age is the only important constant for fishes that are in an item state
|
||||
waterParkCreature.matureTime = -1;
|
||||
waterParkCreature.age = metadata.Age;
|
||||
waterParkCreature.timeNextBreed = -1;
|
||||
}
|
||||
|
||||
// Scaling according to WaterParkCreature.ManagedUpdate
|
||||
waterParkCreature.transform.localScale = Mathf.Lerp(waterParkCreature.data.initialSize, waterParkCreature.data.maxSize, waterParkCreature.age) * Vector3.one;
|
||||
|
||||
waterParkCreature.isMature = waterParkCreature.age == 1f;
|
||||
waterParkCreature.bornInside = metadata.BornInside;
|
||||
|
||||
// This field is not serialized but is always the exact same so it's supposedly recomputed but it would break with our system
|
||||
// (calculation from WaterParkCreature.ManagedUpdate)
|
||||
waterParkCreature.breedInterval = waterParkCreature.data.growingPeriod * 0.5f;
|
||||
|
||||
// While being fully loaded, the base is inactive and coroutines shouldn't be started (they'll throw an exception)
|
||||
// To avoid, that we postpone their execution to 1 more second which is enough because time is frozen during initial sync
|
||||
// This is the mating condition from WaterParkCreature.ManagedUpdate to postpone mating
|
||||
if (Multiplayer.Main && !Multiplayer.Main.InitialSyncCompleted && waterParkCreature.currentWaterPark && waterParkCreature.GetCanBreed() &&
|
||||
waterParkCreature.timeNextBreed != -1 && DayNightCycle.main.timePassedAsFloat > waterParkCreature.timeNextBreed)
|
||||
{
|
||||
waterParkCreature.timeNextBreed = DayNightCycle.main.timePassedAsFloat + 1;
|
||||
}
|
||||
|
||||
waterParkCreature.OnProtoDeserialize(null);
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Metadata;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.GameLogic.Spawning.Metadata.Processor;
|
||||
|
||||
public class WeldableWallPanelGenericMetadataProcessor : EntityMetadataProcessor<WeldableWallPanelGenericMetadata>
|
||||
{
|
||||
public override void ProcessMetadata(GameObject gameObject, WeldableWallPanelGenericMetadata metadata)
|
||||
{
|
||||
WeldableWallPanelGeneric weldableWallPanelGeneric = gameObject.GetComponent<WeldableWallPanelGeneric>();
|
||||
weldableWallPanelGeneric.liveMixin.health = metadata.LiveMixInHealth;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user