first commit
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel.Packets.Processors.Abstract;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors.Abstract
|
||||
{
|
||||
public abstract class ClientPacketProcessor<T> : PacketProcessor where T : Packet
|
||||
{
|
||||
public override void ProcessPacket(Packet packet, IProcessorContext context)
|
||||
{
|
||||
Process((T)packet);
|
||||
}
|
||||
|
||||
public abstract void Process(T packet);
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
|
||||
public class KeepInventoryChangedProcessor : ClientPacketProcessor<KeepInventoryChanged>
|
||||
{
|
||||
private readonly LocalPlayer localPlayer;
|
||||
|
||||
public KeepInventoryChangedProcessor(LocalPlayer localPlayer)
|
||||
{
|
||||
this.localPlayer = localPlayer;
|
||||
}
|
||||
|
||||
public override void Process(KeepInventoryChanged packet)
|
||||
{
|
||||
localPlayer.KeepInventoryOnDeath = packet.KeepInventoryOnDeath;
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class AggressiveWhenSeeTargetChangedProcessor : ClientPacketProcessor<AggressiveWhenSeeTargetChanged>
|
||||
{
|
||||
public override void Process(AggressiveWhenSeeTargetChanged packet)
|
||||
{
|
||||
AI.AggressiveWhenSeeTargetChanged(packet.CreatureId, packet.TargetId, packet.Locked, packet.AggressionAmount);
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class AnimationProcessor : ClientPacketProcessor<AnimationChangeEvent>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
|
||||
public AnimationProcessor(PlayerManager remotePlayerManager)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
}
|
||||
|
||||
public override void Process(AnimationChangeEvent animEvent)
|
||||
{
|
||||
Optional<RemotePlayer> opPlayer = remotePlayerManager.Find(animEvent.PlayerId);
|
||||
if (opPlayer.HasValue)
|
||||
{
|
||||
opPlayer.Value.UpdateAnimationAndCollider((AnimChangeType)animEvent.Type, (AnimChangeState)animEvent.State);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class AttackCyclopsTargetChangedProcessor : ClientPacketProcessor<AttackCyclopsTargetChanged>
|
||||
{
|
||||
public override void Process(AttackCyclopsTargetChanged packet)
|
||||
{
|
||||
AI.AttackCyclopsTargetChanged(packet.CreatureId, packet.TargetId, packet.AggressiveToNoiseAmount);
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class AuroraAndTimeUpdateProcessor : ClientPacketProcessor<AuroraAndTimeUpdate>
|
||||
{
|
||||
private readonly TimeManager timeManager;
|
||||
|
||||
public AuroraAndTimeUpdateProcessor(TimeManager timeManager)
|
||||
{
|
||||
this.timeManager = timeManager;
|
||||
}
|
||||
|
||||
public override void Process(AuroraAndTimeUpdate packet)
|
||||
{
|
||||
timeManager.ProcessUpdate(packet.TimeData.TimePacket);
|
||||
StoryManager.UpdateAuroraData(packet.TimeData.AuroraEventData);
|
||||
timeManager.AuroraRealExplosionTime = packet.TimeData.AuroraEventData.AuroraRealExplosionTime;
|
||||
if (packet.Restore)
|
||||
{
|
||||
StoryManager.RestoreAurora();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
class BedEnterProcessor : ClientPacketProcessor<BedEnter>
|
||||
{
|
||||
public override void Process(BedEnter packet)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.Bases;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public abstract class BuildProcessor<T> : ClientPacketProcessor<T> where T : Packet
|
||||
{
|
||||
public override void Process(T packet)
|
||||
{
|
||||
BuildingHandler.Main.BuildQueue.Enqueue(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public class PlaceGhostProcessor : BuildProcessor<PlaceGhost> { }
|
||||
|
||||
public class PlaceModuleProcessor : BuildProcessor<PlaceModule> { }
|
||||
|
||||
public class ModifyConstructedAmountProcessor : BuildProcessor<ModifyConstructedAmount> { }
|
||||
|
||||
public class PlaceBaseProcessor : BuildProcessor<PlaceBase> { }
|
||||
|
||||
public class UpdateBaseProcessor : BuildProcessor<UpdateBase> { }
|
||||
|
||||
public class BaseDeconstructedProcessor : BuildProcessor<BaseDeconstructed> { }
|
||||
|
||||
public class PieceDeconstructedProcessor : BuildProcessor<PieceDeconstructed> { }
|
||||
|
||||
public class WaterParkDeconstructedProcessor : BuildProcessor<WaterParkDeconstructed> { }
|
||||
|
||||
public class LargeWaterParkDeconstructedProcessor : BuildProcessor<LargeWaterParkDeconstructed> { }
|
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.Bases;
|
||||
using NitroxClient.GameLogic.Settings;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class BuildingDesyncWarningProcessor : ClientPacketProcessor<BuildingDesyncWarning>
|
||||
{
|
||||
public override void Process(BuildingDesyncWarning packet)
|
||||
{
|
||||
if (!BuildingHandler.Main)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<NitroxId, int> operation in packet.Operations)
|
||||
{
|
||||
OperationTracker tracker = BuildingHandler.Main.EnsureTracker(operation.Key);
|
||||
tracker.LastOperationId = operation.Value;
|
||||
tracker.FailedOperations++;
|
||||
}
|
||||
|
||||
if (NitroxPrefs.SafeBuildingLog.Value)
|
||||
{
|
||||
Log.InGame(Language.main.Get("Nitrox_BuildingDesyncDetected"));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,179 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.GameLogic.Bases;
|
||||
using NitroxClient.GameLogic.Spawning.Bases;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities.Bases;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class BuildingResyncProcessor : ClientPacketProcessor<BuildingResync>
|
||||
{
|
||||
private readonly Entities entities;
|
||||
private readonly EntityMetadataManager entityMetadataManager;
|
||||
|
||||
public BuildingResyncProcessor(Entities entities, EntityMetadataManager entityMetadataManager)
|
||||
{
|
||||
this.entities = entities;
|
||||
this.entityMetadataManager = entityMetadataManager;
|
||||
}
|
||||
|
||||
public override void Process(BuildingResync packet)
|
||||
{
|
||||
if (!BuildingHandler.Main)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BuildingHandler.Main.StartCoroutine(ResyncBuildingEntities(packet.BuildEntities, packet.ModuleEntities));
|
||||
}
|
||||
|
||||
public IEnumerator ResyncBuildingEntities(Dictionary<BuildEntity, int> buildEntities, Dictionary<ModuleEntity, int> moduleEntities)
|
||||
{
|
||||
Stopwatch stopwatch = Stopwatch.StartNew();
|
||||
BuildingHandler.Main.StartResync(buildEntities);
|
||||
yield return UpdateEntities<Base, BuildEntity>(buildEntities.Keys.ToList(), OverwriteBase, IsInCloseProximity).OnYieldError(exception => Log.Error(exception, $"Encountered an exception while resyncing BuildEntities"));
|
||||
|
||||
BuildingHandler.Main.StartResync(moduleEntities);
|
||||
yield return UpdateEntities<Constructable, ModuleEntity>(moduleEntities.Keys.ToList(), OverwriteModule, IsInCloseProximity).OnYieldError(exception => Log.Error(exception, $"Encountered an exception while resyncing ModuleEntities"));
|
||||
BuildingHandler.Main.StopResync();
|
||||
|
||||
stopwatch.Stop();
|
||||
|
||||
int totalEntities = buildEntities.Count + moduleEntities.Count;
|
||||
Log.InGame(Language.main.Get("Nitrox_FinishedResyncRequest").Replace("{TIME}", stopwatch.ElapsedMilliseconds.ToString()).Replace("{COUNT}", totalEntities.ToString()));
|
||||
}
|
||||
|
||||
private bool IsInCloseProximity<C>(WorldEntity entity, C componentInWorld) where C : Component
|
||||
{
|
||||
return Vector3.Distance(entity.Transform.Position.ToUnity(), componentInWorld.transform.position) < 0.001f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to overwrite components of the provided type found in GlobalRoot's hierarchy by the provided list of entities to update.
|
||||
/// If no component is found to be corresponding to a provided entity, the entity will be spawned independently.
|
||||
/// Other components of the provided type which weren't updated shall be destroyed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The provided list is modified by the function. Make sure it's not used somewhere else.
|
||||
/// </remarks>
|
||||
/// <typeparam name="C">The Unity component to be looked for</typeparam>
|
||||
/// <typeparam name="E">The GlobalRootEntity type which will be updated</typeparam>
|
||||
/// <param name="overwrite">A function to overwrite a given component by a given entity</param>
|
||||
/// <param name="correspondingPredicate">
|
||||
/// Predicate to determine if an entity can overwrite the GameObject of the provided component.
|
||||
/// </param>
|
||||
public IEnumerator UpdateEntities<C,E>(List<E> entitiesToUpdate, Func<C, E, IEnumerator> overwrite, Func<E, C, bool> correspondingPredicate) where C : Component where E : GlobalRootEntity
|
||||
{
|
||||
List<C> unmarkedComponents = new();
|
||||
Dictionary<NitroxId, E> entitiesToUpdateById = entitiesToUpdate.ToDictionary(e => e.Id);
|
||||
|
||||
foreach (Transform childTransform in LargeWorldStreamer.main.globalRoot.transform)
|
||||
{
|
||||
if (childTransform.TryGetComponent(out C component))
|
||||
{
|
||||
if (component.TryGetNitroxId(out NitroxId id) && entitiesToUpdateById.TryGetValue(id, out E correspondingEntity))
|
||||
{
|
||||
yield return overwrite(component, correspondingEntity).OnYieldError(Log.Error);
|
||||
entitiesToUpdate.Remove(correspondingEntity);
|
||||
continue;
|
||||
}
|
||||
unmarkedComponents.Add(component);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = entitiesToUpdate.Count - 1; i >= 0; i--)
|
||||
{
|
||||
E entity = entitiesToUpdate[i];
|
||||
C associatedComponent = unmarkedComponents.Find(c =>
|
||||
correspondingPredicate(entity, c));
|
||||
yield return overwrite(associatedComponent, entity).OnYieldError(Log.Error);
|
||||
|
||||
unmarkedComponents.Remove(associatedComponent);
|
||||
entitiesToUpdate.RemoveAt(i);
|
||||
}
|
||||
|
||||
for (int i = unmarkedComponents.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Log.Info($"[{typeof(E)} RESYNC] Destroyed GameObject {unmarkedComponents[i].gameObject}");
|
||||
GameObject.Destroy(unmarkedComponents[i].gameObject);
|
||||
}
|
||||
foreach (E entity in entitiesToUpdate)
|
||||
{
|
||||
Log.Info($"[{typeof(E)} RESYNC] spawning entity {entity.Id}");
|
||||
yield return entities.SpawnEntityAsync(entity).OnYieldError(Log.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator OverwriteBase(Base @base, BuildEntity buildEntity)
|
||||
{
|
||||
Log.Info($"[Base RESYNC] Overwriting base with id {buildEntity.Id}");
|
||||
ClearBaseChildren(@base);
|
||||
// Frame to let all children be deleted properly
|
||||
yield return Yielders.WaitForEndOfFrame;
|
||||
|
||||
yield return BuildEntitySpawner.SetupBase(buildEntity, @base, entities);
|
||||
yield return MoonpoolManager.RestoreMoonpools(buildEntity.ChildEntities.OfType<MoonpoolEntity>(), @base);
|
||||
yield return entities.SpawnBatchAsync(buildEntity.ChildEntities.OfType<PlayerWorldEntity>().ToList<Entity>(), false, false);
|
||||
|
||||
foreach (Entity childEntity in buildEntity.ChildEntities)
|
||||
{
|
||||
switch (childEntity)
|
||||
{
|
||||
case MapRoomEntity mapRoomEntity:
|
||||
yield return InteriorPieceEntitySpawner.RestoreMapRoom(@base, mapRoomEntity);
|
||||
break;
|
||||
case BaseLeakEntity baseLeakEntity:
|
||||
yield return entities.SpawnEntityAsync(baseLeakEntity, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator OverwriteModule(Constructable constructable, ModuleEntity moduleEntity)
|
||||
{
|
||||
Log.Info($"[Module RESYNC] Overwriting module with id {moduleEntity.Id}");
|
||||
ModuleEntitySpawner.ApplyModuleData(moduleEntity, constructable.gameObject);
|
||||
entityMetadataManager.ApplyMetadata(constructable.gameObject, moduleEntity.Metadata);
|
||||
yield break;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys manually ghosts, modules, interior pieces and vehicles of a base
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the destructive way of clearing the base, if the base isn't modified consequently, IBaseModuleGeometry under the base cells may start spamming errors.
|
||||
/// </remarks>
|
||||
public static void ClearBaseChildren(Base @base)
|
||||
{
|
||||
for (int i = @base.transform.childCount - 1; i >= 0; i--)
|
||||
{
|
||||
Transform child = @base.transform.GetChild(i);
|
||||
if (child.GetComponent<IBaseModule>().AliveOrNull() || child.GetComponent<Constructable>())
|
||||
{
|
||||
UnityEngine.Object.Destroy(child.gameObject);
|
||||
}
|
||||
}
|
||||
foreach (VehicleDockingBay vehicleDockingBay in @base.GetComponentsInChildren<VehicleDockingBay>(true))
|
||||
{
|
||||
if (vehicleDockingBay.dockedVehicle)
|
||||
{
|
||||
UnityEngine.Object.Destroy(vehicleDockingBay.dockedVehicle.gameObject);
|
||||
vehicleDockingBay.SetVehicleUndocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.GameLogic.ChatUI;
|
||||
using NitroxClient.GameLogic.Settings;
|
||||
using NitroxModel.DataStructures.Unity;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
class ChatMessageProcessor : ClientPacketProcessor<ChatMessage>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
private readonly LocalPlayer localPlayer;
|
||||
private readonly PlayerChatManager playerChatManager;
|
||||
|
||||
private readonly Color32 serverMessageColor = new Color32(0x8c, 0x00, 0xFF, 0xFF);
|
||||
|
||||
public ChatMessageProcessor(PlayerManager remotePlayerManager, LocalPlayer localPlayer, PlayerChatManager playerChatManager)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
this.localPlayer = localPlayer;
|
||||
this.playerChatManager = playerChatManager;
|
||||
}
|
||||
|
||||
public override void Process(ChatMessage message)
|
||||
{
|
||||
if (message.PlayerId != ChatMessage.SERVER_ID)
|
||||
{
|
||||
LogClientMessage(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogServerMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
private void LogClientMessage(ChatMessage message)
|
||||
{
|
||||
// The message can come from either the local player or other players
|
||||
string playerName;
|
||||
NitroxColor color;
|
||||
if (localPlayer.PlayerId == message.PlayerId)
|
||||
{
|
||||
playerName = localPlayer.PlayerName;
|
||||
color = localPlayer.PlayerSettings.PlayerColor;
|
||||
}
|
||||
else
|
||||
{
|
||||
Optional<RemotePlayer> remotePlayer = remotePlayerManager.Find(message.PlayerId);
|
||||
if (!remotePlayer.HasValue)
|
||||
{
|
||||
string playerTableFormatted = string.Join("\n", remotePlayerManager.GetAll().Select(ply => $"Name: '{ply.PlayerName}', Id: {ply.PlayerId}"));
|
||||
Log.Error($"Tried to add chat message for remote player that could not be found with id '${message.PlayerId}' and message: '{message.Text}'.\nAll remote players right now:\n{playerTableFormatted}");
|
||||
throw new Exception($"Tried to add chat message for remote player that could not be found with id '${message.PlayerId}' and message: '{message.Text}'.\nAll remote players right now:\n{playerTableFormatted}");
|
||||
}
|
||||
|
||||
playerName = remotePlayer.Value.PlayerName;
|
||||
color = remotePlayer.Value.PlayerSettings.PlayerColor;
|
||||
}
|
||||
|
||||
playerChatManager.AddMessage(playerName, message.Text, color.ToUnity());
|
||||
if (!NitroxPrefs.SilenceChat.Value)
|
||||
{
|
||||
playerChatManager.ShowChat();
|
||||
}
|
||||
}
|
||||
|
||||
private void LogServerMessage(ChatMessage message)
|
||||
{
|
||||
playerChatManager.AddMessage("Server", message.Text, serverMessageColor);
|
||||
if (!NitroxPrefs.SilenceChat.Value)
|
||||
{
|
||||
playerChatManager.ShowChat();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class CreatureActionProcessor : ClientPacketProcessor<CreatureActionChanged>
|
||||
{
|
||||
private readonly AI ai;
|
||||
|
||||
public CreatureActionProcessor(AI ai)
|
||||
{
|
||||
this.ai = ai;
|
||||
}
|
||||
|
||||
public override void Process(CreatureActionChanged packet)
|
||||
{
|
||||
ai.CreatureActionChanged(packet.CreatureId, packet.CreatureActionType);
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class CreaturePoopPerformedProcessor : ClientPacketProcessor<CreaturePoopPerformed>
|
||||
{
|
||||
public override void Process(CreaturePoopPerformed packet)
|
||||
{
|
||||
AI.CreaturePoopPerformed(packet.CreatureId);
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel_Subnautica.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class CyclopsDamagePointHealthChangedProcessor : ClientPacketProcessor<CyclopsDamagePointRepaired>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public CyclopsDamagePointHealthChangedProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void Process(CyclopsDamagePointRepaired packet)
|
||||
{
|
||||
GameObject gameObject = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
SubRoot cyclops = gameObject.RequireComponent<SubRoot>();
|
||||
|
||||
using (PacketSuppressor<CyclopsDamage>.Suppress())
|
||||
using (PacketSuppressor<CyclopsDamagePointRepaired>.Suppress())
|
||||
{
|
||||
cyclops.damageManager.damagePoints[packet.DamagePointIndex].liveMixin.AddHealth(packet.RepairAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,202 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures.GameLogic;
|
||||
using NitroxModel_Subnautica.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
/// <summary>
|
||||
/// Add/remove <see cref="CyclopsDamagePoint"/>s and <see cref="Fire"/>s to match the <see cref="CyclopsDamage"/> packet received
|
||||
/// </summary>
|
||||
public class CyclopsDamageProcessor : ClientPacketProcessor<CyclopsDamage>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
private readonly Fires fires;
|
||||
|
||||
public CyclopsDamageProcessor(IPacketSender packetSender, Fires fires)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
this.fires = fires;
|
||||
}
|
||||
|
||||
public override void Process(CyclopsDamage packet)
|
||||
{
|
||||
SubRoot subRoot = NitroxEntity.RequireObjectFrom(packet.Id).GetComponent<SubRoot>();
|
||||
|
||||
using (PacketSuppressor<CyclopsDamagePointRepaired>.Suppress())
|
||||
{
|
||||
SetActiveDamagePoints(subRoot, packet.DamagePointIndexes);
|
||||
}
|
||||
|
||||
using (PacketSuppressor<FireDoused>.Suppress())
|
||||
{
|
||||
SetActiveRoomFires(subRoot, packet.RoomFires);
|
||||
}
|
||||
|
||||
LiveMixin subHealth = subRoot.gameObject.RequireComponent<LiveMixin>();
|
||||
|
||||
float oldHPPercent = subRoot.oldHPPercent;
|
||||
|
||||
// Client side noises. Not necessary for keeping the health synced
|
||||
if (subHealth.GetHealthFraction() < 0.5f && oldHPPercent >= 0.5f)
|
||||
{
|
||||
subRoot.voiceNotificationManager.PlayVoiceNotification(subRoot.hullLowNotification, true, false);
|
||||
}
|
||||
else if (subHealth.GetHealthFraction() < 0.25f && oldHPPercent >= 0.25f)
|
||||
{
|
||||
subRoot.voiceNotificationManager.PlayVoiceNotification(subRoot.hullCriticalNotification, true, false);
|
||||
}
|
||||
|
||||
using (PacketSuppressor<CyclopsDamage>.Suppress())
|
||||
{
|
||||
// Not necessary, but used by above code whenever damage is done
|
||||
subRoot.oldHPPercent = subHealth.GetHealthFraction();
|
||||
|
||||
// Apply the actual health changes
|
||||
subRoot.gameObject.RequireComponent<LiveMixin>().health = packet.SubHealth;
|
||||
subRoot.gameObject.RequireComponentInChildren<CyclopsExternalDamageManager>().subLiveMixin.health = packet.DamageManagerHealth;
|
||||
subRoot.gameObject.RequireComponent<SubFire>().liveMixin.health = packet.SubFireHealth;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add/remove <see cref="CyclopsDamagePoint"/>s until it matches the <paramref name="damagePointIndexes"/> array passed. Can trigger <see cref="CyclopsDamagePointRepaired"/> packets
|
||||
/// </summary>
|
||||
private void SetActiveDamagePoints(SubRoot cyclops, int[] damagePointIndexes)
|
||||
{
|
||||
CyclopsExternalDamageManager damageManager = cyclops.gameObject.RequireComponentInChildren<CyclopsExternalDamageManager>();
|
||||
List<CyclopsDamagePoint> unusedDamagePoints = damageManager.unusedDamagePoints;
|
||||
|
||||
// CyclopsExternalDamageManager.damagePoints is an unchanged list. It will never have items added/removed from it. Since packet.DamagePointIndexes is also an array
|
||||
// generated in an ordered manner, we can match them without worrying about unordered items.
|
||||
if (damagePointIndexes != null && damagePointIndexes.Length > 0)
|
||||
{
|
||||
int packetDamagePointsIndex = 0;
|
||||
|
||||
for (int damagePointsIndex = 0; damagePointsIndex < damageManager.damagePoints.Length; damagePointsIndex++)
|
||||
{
|
||||
// Loop over all of the packet.DamagePointIndexes as long as there's more to match
|
||||
if (packetDamagePointsIndex < damagePointIndexes.Length
|
||||
&& damagePointIndexes[packetDamagePointsIndex] == damagePointsIndex)
|
||||
{
|
||||
if (!damageManager.damagePoints[damagePointsIndex].gameObject.activeSelf)
|
||||
{
|
||||
// Copied from CyclopsExternalDamageManager.CreatePoint(), except without the random index pick.
|
||||
damageManager.damagePoints[damagePointsIndex].gameObject.SetActive(true);
|
||||
damageManager.damagePoints[damagePointsIndex].RestoreHealth();
|
||||
GameObject prefabGo = damageManager.fxPrefabs[UnityEngine.Random.Range(0, damageManager.fxPrefabs.Length - 1)];
|
||||
damageManager.damagePoints[damagePointsIndex].SpawnFx(prefabGo);
|
||||
unusedDamagePoints.Remove(damageManager.damagePoints[damagePointsIndex]);
|
||||
}
|
||||
|
||||
packetDamagePointsIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it's active, but not in the list, it must have been repaired.
|
||||
if (damageManager.damagePoints[damagePointsIndex].gameObject.activeSelf)
|
||||
{
|
||||
RepairDamagePoint(cyclops, damagePointsIndex, 999);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Looks like the list came in unordered. I've uttered "That shouldn't happen" enough to do sanity checks for what should be impossible.
|
||||
if (packetDamagePointsIndex < damagePointIndexes.Length)
|
||||
{
|
||||
Log.Error($"[CyclopsDamageProcessor packet.DamagePointIds did not fully iterate! Id: {damagePointIndexes[packetDamagePointsIndex]} had no matching Id in damageManager.damagePoints, or the order is incorrect!]");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// None should be active.
|
||||
for (int i = 0; i < damageManager.damagePoints.Length; i++)
|
||||
{
|
||||
if (damageManager.damagePoints[i].gameObject.activeSelf)
|
||||
{
|
||||
RepairDamagePoint(cyclops, i, 999);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unusedDamagePoints is checked against damagePoints to determine if there's enough damage points. Failing to set the new list
|
||||
// of unusedDamagePoints will cause random DamagePoints to appear.
|
||||
damageManager.unusedDamagePoints = unusedDamagePoints;
|
||||
// Visual update only to show the water leaking through the window and various hull points based on missing health.
|
||||
damageManager.ToggleLeakPointsBasedOnDamage();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add/remove fires until it matches the <paramref name="roomFires"/> array. Can trigger <see cref="FireDoused"/> packets
|
||||
/// </summary>
|
||||
private void SetActiveRoomFires(SubRoot subRoot, CyclopsFireData[] roomFires)
|
||||
{
|
||||
SubFire subFire = subRoot.gameObject.RequireComponent<SubFire>();
|
||||
Dictionary<CyclopsRooms, SubFire.RoomFire> roomFiresDict = subFire.roomFires;
|
||||
|
||||
if (!subRoot.TryGetIdOrWarn(out NitroxId subRootId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (roomFires != null && roomFires.Length > 0)
|
||||
{
|
||||
// Removing and adding fires will happen in the same loop
|
||||
foreach (KeyValuePair<CyclopsRooms, SubFire.RoomFire> keyValuePair in roomFiresDict)
|
||||
{
|
||||
for (int nodeIndex = 0; nodeIndex < keyValuePair.Value.spawnNodes.Length; nodeIndex++)
|
||||
{
|
||||
CyclopsFireData fireNode = roomFires.SingleOrDefault(x => x.Room == keyValuePair.Key && x.NodeIndex == nodeIndex);
|
||||
|
||||
// If there's a matching node index, add a fire if there isn't one already. Otherwise remove a fire if there is one
|
||||
if (fireNode == null)
|
||||
{
|
||||
if (keyValuePair.Value.spawnNodes[nodeIndex].childCount > 0)
|
||||
{
|
||||
keyValuePair.Value.spawnNodes[nodeIndex].GetComponentInChildren<Fire>().Douse(10000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (keyValuePair.Value.spawnNodes[nodeIndex].childCount < 1)
|
||||
{
|
||||
fires.Create(new CyclopsFireData(fireNode.FireId, subRootId, fireNode.Room, fireNode.NodeIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clear out the fires, there should be none active
|
||||
else
|
||||
{
|
||||
foreach (KeyValuePair<CyclopsRooms, SubFire.RoomFire> keyValuePair in roomFiresDict)
|
||||
{
|
||||
foreach (Transform spawnNode in keyValuePair.Value.spawnNodes)
|
||||
{
|
||||
if (spawnNode.childCount > 0)
|
||||
{
|
||||
spawnNode.GetComponentInChildren<Fire>().Douse(10000);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the health of a <see cref="CyclopsDamagePoint"/>. This can trigger sending <see cref="CyclopsDamagePointRepaired"/> packets
|
||||
/// </summary>
|
||||
/// <param name="repairAmount">The max health of the point is 1. 999 is passed to trigger a full repair of the <see cref="CyclopsDamagePoint"/></param>
|
||||
private void RepairDamagePoint(SubRoot subRoot, int damagePointIndex, float repairAmount)
|
||||
{
|
||||
subRoot.damageManager.damagePoints[damagePointIndex].liveMixin.AddHealth(repairAmount);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel_Subnautica.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
class CyclopsDecoyLaunchProcessor : ClientPacketProcessor<CyclopsDecoyLaunch>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
private readonly Cyclops cyclops;
|
||||
|
||||
public CyclopsDecoyLaunchProcessor(IPacketSender packetSender, Cyclops cyclops)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
this.cyclops = cyclops;
|
||||
}
|
||||
|
||||
public override void Process(CyclopsDecoyLaunch decoyLaunchPacket)
|
||||
{
|
||||
cyclops.LaunchDecoy(decoyLaunchPacket.Id);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel_Subnautica.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class CyclopsFireCreatedProcessor : ClientPacketProcessor<CyclopsFireCreated>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
private readonly Fires fires;
|
||||
|
||||
public CyclopsFireCreatedProcessor(IPacketSender packetSender, Fires fires)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
this.fires = fires;
|
||||
}
|
||||
|
||||
public override void Process(CyclopsFireCreated packet)
|
||||
{
|
||||
fires.Create(packet.FireCreatedData);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel_Subnautica.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class CyclopsFireSuppressionProcessor : ClientPacketProcessor<CyclopsFireSuppression>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
private readonly Cyclops cyclops;
|
||||
|
||||
public CyclopsFireSuppressionProcessor(IPacketSender packetSender, Cyclops cyclops)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
this.cyclops = cyclops;
|
||||
}
|
||||
|
||||
public override void Process(CyclopsFireSuppression fireSuppressionPacket)
|
||||
{
|
||||
cyclops.StartFireSuppression(fireSuppressionPacket.Id);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,19 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.DataStructures.Unity;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
class DebugStartMapProcessor : ClientPacketProcessor<DebugStartMapPacket>
|
||||
{
|
||||
public override void Process(DebugStartMapPacket packet)
|
||||
{
|
||||
foreach (NitroxVector3 position in packet.StartPositions)
|
||||
{
|
||||
GameObject prim = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
||||
prim.transform.position = new Vector3(position.X, position.Y + 10, position.Z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.Helper;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
using static NitroxClient.GameLogic.Helper.TransientLocalObjectManager;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class DeconstructionBeginProcessor : ClientPacketProcessor<DeconstructionBegin>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public DeconstructionBeginProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void Process(DeconstructionBegin packet)
|
||||
{
|
||||
Log.Info($"Received deconstruction packet for id: {packet.Id}");
|
||||
|
||||
GameObject deconstructing = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
|
||||
Constructable constructable = deconstructing.GetComponent<Constructable>();
|
||||
BaseDeconstructable baseDeconstructable = deconstructing.GetComponent<BaseDeconstructable>();
|
||||
|
||||
using (PacketSuppressor<DeconstructionBegin>.Suppress())
|
||||
{
|
||||
if (baseDeconstructable != null)
|
||||
{
|
||||
TransientLocalObjectManager.Add(TransientObjectType.LATEST_DECONSTRUCTED_BASE_PIECE_GUID, packet.Id);
|
||||
baseDeconstructable.Deconstruct();
|
||||
}
|
||||
else if (constructable != null)
|
||||
{
|
||||
constructable.SetState(false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.GameLogic.HUD;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
class DisconnectProcessor : ClientPacketProcessor<Disconnect>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
private readonly PlayerVitalsManager vitalsManager;
|
||||
|
||||
public DisconnectProcessor(PlayerManager remotePlayerManager, PlayerVitalsManager vitalsManager)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
this.vitalsManager = vitalsManager;
|
||||
}
|
||||
|
||||
public override void Process(Disconnect disconnect)
|
||||
{
|
||||
// TODO: don't remove right away... maybe grey out and start
|
||||
// a coroutine to finally remove.
|
||||
vitalsManager.RemoveForPlayer(disconnect.PlayerId);
|
||||
|
||||
Optional<RemotePlayer> remotePlayer = remotePlayerManager.Find(disconnect.PlayerId);
|
||||
if (remotePlayer.HasValue)
|
||||
{
|
||||
remotePlayer.Value.PlayerDisconnectEvent.Trigger(remotePlayer.Value);
|
||||
remotePlayerManager.RemovePlayer(disconnect.PlayerId);
|
||||
Log.Info($"{remotePlayer.Value.PlayerName} disconnected");
|
||||
Log.InGame(Language.main.Get("Nitrox_PlayerDisconnected").Replace("{PLAYER}", remotePlayer.Value.PlayerName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours.Discord;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class DiscordRequestIPProcessor : ClientPacketProcessor<DiscordRequestIP>
|
||||
{
|
||||
public override void Process(DiscordRequestIP packet)
|
||||
{
|
||||
DiscordClient.UpdateIpPort(packet.IpPort);
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class DropSimulationOwnershipProcessor : ClientPacketProcessor<DropSimulationOwnership>
|
||||
{
|
||||
private readonly SimulationOwnership simulationOwnershipManager;
|
||||
|
||||
public DropSimulationOwnershipProcessor(SimulationOwnership simulationOwnershipManager)
|
||||
{
|
||||
this.simulationOwnershipManager = simulationOwnershipManager;
|
||||
}
|
||||
|
||||
public override void Process(DropSimulationOwnership packet)
|
||||
{
|
||||
simulationOwnershipManager.DropSimulationFrom(packet.EntityId);
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.GameLogic.PlayerLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class EntityDestroyedProcessor : ClientPacketProcessor<EntityDestroyed>
|
||||
{
|
||||
public const DamageType DAMAGE_TYPE_RUN_ORIGINAL = (DamageType)100;
|
||||
|
||||
private readonly Entities entities;
|
||||
|
||||
public EntityDestroyedProcessor(Entities entities)
|
||||
{
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public override void Process(EntityDestroyed packet)
|
||||
{
|
||||
entities.RemoveEntity(packet.Id);
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.Id, out GameObject gameObject))
|
||||
{
|
||||
entities.MarkForDeletion(packet.Id);
|
||||
Log.Warn($"[{nameof(EntityDestroyedProcessor)}] Could not find entity with id: {packet.Id} to destroy.");
|
||||
return;
|
||||
}
|
||||
|
||||
using (PacketSuppressor<EntityDestroyed>.Suppress())
|
||||
{
|
||||
// This type of check could get out of control if there are many types with custom destroy logic. If we get a few more, move to separate processors.
|
||||
if (gameObject.TryGetComponent(out Vehicle vehicle))
|
||||
{
|
||||
DestroyVehicle(vehicle);
|
||||
}
|
||||
else if (gameObject.TryGetComponent(out SubRoot subRoot))
|
||||
{
|
||||
DestroySubroot(subRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
Entities.DestroyObject(gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DestroySubroot(SubRoot subRoot)
|
||||
{
|
||||
DamageInfo damageInfo = new() { type = DAMAGE_TYPE_RUN_ORIGINAL };
|
||||
if (subRoot.live.health > 0f)
|
||||
{
|
||||
// oldHPPercent must be in the interval [0; 0.25[ because else, SubRoot.OnTakeDamage will end up in the wrong else condition
|
||||
subRoot.oldHPPercent = 0f;
|
||||
subRoot.live.health = 0f;
|
||||
subRoot.live.NotifyAllAttachedDamageReceivers(damageInfo);
|
||||
subRoot.live.Kill();
|
||||
}
|
||||
|
||||
// We use a specific DamageType so that the Prefix on this method will accept this call
|
||||
subRoot.OnTakeDamage(damageInfo);
|
||||
}
|
||||
|
||||
private void DestroyVehicle(Vehicle vehicle)
|
||||
{
|
||||
if (vehicle.GetPilotingMode()) //Check Local Object Have Player inside
|
||||
{
|
||||
vehicle.OnPilotModeEnd();
|
||||
|
||||
if (!Player.main.ToNormalMode(true))
|
||||
{
|
||||
Player.main.ToNormalMode(false);
|
||||
Player.main.transform.parent = null;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (RemotePlayerIdentifier identifier in vehicle.GetComponentsInChildren<RemotePlayerIdentifier>(true))
|
||||
{
|
||||
identifier.RemotePlayer.ResetStates();
|
||||
}
|
||||
|
||||
if (vehicle.gameObject)
|
||||
{
|
||||
if (vehicle.destructionEffect)
|
||||
{
|
||||
GameObject gameObject = Object.Instantiate(vehicle.destructionEffect);
|
||||
gameObject.transform.position = vehicle.transform.position;
|
||||
gameObject.transform.rotation = vehicle.transform.rotation;
|
||||
}
|
||||
|
||||
Object.Destroy(vehicle.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata;
|
||||
using NitroxClient.GameLogic.Spawning.Metadata.Processor.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class EntityMetadataUpdateProcessor : ClientPacketProcessor<EntityMetadataUpdate>
|
||||
{
|
||||
private readonly EntityMetadataManager entityMetadataManager;
|
||||
|
||||
public EntityMetadataUpdateProcessor(EntityMetadataManager entityMetadataManager)
|
||||
{
|
||||
this.entityMetadataManager = entityMetadataManager;
|
||||
}
|
||||
|
||||
public override void Process(EntityMetadataUpdate update)
|
||||
{
|
||||
if (!NitroxEntity.TryGetObjectFrom(update.Id, out GameObject gameObject))
|
||||
{
|
||||
entityMetadataManager.RegisterNewerMetadata(update.Id, update.NewValue);
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<IEntityMetadataProcessor> metadataProcessor = entityMetadataManager.FromMetaData(update.NewValue);
|
||||
Validate.IsTrue(metadataProcessor.HasValue, $"No processor found for EntityMetadata of type {update.NewValue.GetType()}");
|
||||
|
||||
metadataProcessor.Value.ProcessMetadata(gameObject, update.NewValue);
|
||||
}
|
||||
}
|
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.GameLogic.Helper;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures.GameLogic.Entities;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class EntityReparentedProcessor : ClientPacketProcessor<EntityReparented>
|
||||
{
|
||||
private readonly Entities entities;
|
||||
|
||||
public EntityReparentedProcessor(Entities entities)
|
||||
{
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public override void Process(EntityReparented packet)
|
||||
{
|
||||
Optional<GameObject> entity = NitroxEntity.GetObjectFrom(packet.Id);
|
||||
|
||||
if (!entity.HasValue)
|
||||
{
|
||||
// In some cases, the affected entity may be pending spawning or out of range.
|
||||
// we only require the parent (in this case, the visible entity is undergoing
|
||||
// some change that must be shown, and if not is an error).
|
||||
return;
|
||||
}
|
||||
|
||||
GameObject newParent = NitroxEntity.RequireObjectFrom(packet.NewParentId);
|
||||
|
||||
if (entity.Value.TryGetComponent(out Pickupable pickupable))
|
||||
{
|
||||
WaterParkItem waterParkItem = pickupable.GetComponent<WaterParkItem>();
|
||||
// If the entity is being parented to a WaterPark
|
||||
if (newParent.TryGetComponent(out WaterPark waterPark))
|
||||
{
|
||||
// If the entity is already in a WaterPark
|
||||
if (waterParkItem.currentWaterPark)
|
||||
{
|
||||
waterParkItem.SetWaterPark(waterPark);
|
||||
return;
|
||||
}
|
||||
pickupable.SetVisible(false);
|
||||
pickupable.Activate(false);
|
||||
waterPark.AddItem(pickupable);
|
||||
// The reparenting is automatic here so we don't need to continue
|
||||
return;
|
||||
}
|
||||
// If the entity was parented to a WaterPark but is picked up by someone
|
||||
else if (waterParkItem)
|
||||
{
|
||||
pickupable.Deactivate();
|
||||
waterParkItem.SetWaterPark(null);
|
||||
}
|
||||
}
|
||||
|
||||
using (PacketSuppressor<EntityReparented>.Suppress())
|
||||
{
|
||||
Type entityType = entities.RequireEntityType(packet.Id);
|
||||
|
||||
// Move this to a resolver if there ends up being a lot of custom reparenting logic
|
||||
if (entityType == typeof(InventoryItemEntity))
|
||||
{
|
||||
InventoryItemReparented(entity.Value, newParent);
|
||||
}
|
||||
else
|
||||
{
|
||||
PerformDefaultReparenting(entity.Value, newParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InventoryItemReparented(GameObject entity, GameObject newParent)
|
||||
{
|
||||
Optional<ItemsContainer> opContainer = InventoryContainerHelper.TryGetContainerByOwner(newParent);
|
||||
|
||||
if (!opContainer.HasValue)
|
||||
{
|
||||
Log.Error($"Could not find container field on GameObject {newParent.GetFullHierarchyPath()}");
|
||||
return;
|
||||
}
|
||||
|
||||
Pickupable pickupable = entity.RequireComponent<Pickupable>();
|
||||
|
||||
ItemsContainer container = opContainer.Value;
|
||||
container.UnsafeAdd(new InventoryItem(pickupable));
|
||||
}
|
||||
|
||||
private void PerformDefaultReparenting(GameObject entity, GameObject newParent)
|
||||
{
|
||||
entity.transform.SetParent(newParent.transform, false);
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
using static NitroxModel.Packets.EntityTransformUpdates;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class EntityTransformUpdatesProcessor : ClientPacketProcessor<EntityTransformUpdates>
|
||||
{
|
||||
private readonly SimulationOwnership simulationOwnership;
|
||||
|
||||
public EntityTransformUpdatesProcessor(SimulationOwnership simulationOwnership)
|
||||
{
|
||||
this.simulationOwnership = simulationOwnership;
|
||||
}
|
||||
|
||||
public override void Process(EntityTransformUpdates packet)
|
||||
{
|
||||
foreach (EntityTransformUpdate update in packet.Updates)
|
||||
{
|
||||
// We will cancel any position update attempt at one of our locked entities
|
||||
if (!NitroxEntity.TryGetObjectFrom(update.Id, out GameObject gameObject) ||
|
||||
simulationOwnership.HasAnyLockType(update.Id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
RemotelyControlled remotelyControlled = gameObject.EnsureComponent<RemotelyControlled>();
|
||||
|
||||
Vector3 position = update.Position.ToUnity();
|
||||
Quaternion rotation = update.Rotation.ToUnity();
|
||||
|
||||
if (update is SplineTransformUpdate splineUpdate)
|
||||
{
|
||||
remotelyControlled.UpdateKnownSplineUser(position, rotation, splineUpdate.DestinationPosition.ToUnity(), splineUpdate.DestinationDirection.ToUnity(), splineUpdate.Velocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
remotelyControlled.UpdateOrientation(position, rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,39 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class EscapePodChangedProcessor : ClientPacketProcessor<EscapePodChanged>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
|
||||
public EscapePodChangedProcessor(PlayerManager remotePlayerManager)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
}
|
||||
|
||||
public override void Process(EscapePodChanged packet)
|
||||
{
|
||||
Optional<RemotePlayer> remotePlayer = remotePlayerManager.Find(packet.PlayerId);
|
||||
|
||||
if (remotePlayer.HasValue)
|
||||
{
|
||||
EscapePod escapePod = null;
|
||||
|
||||
if (packet.EscapePodId.HasValue)
|
||||
{
|
||||
GameObject sub = NitroxEntity.RequireObjectFrom(packet.EscapePodId.Value);
|
||||
escapePod = sub.GetComponent<EscapePod>();
|
||||
}
|
||||
|
||||
remotePlayer.Value.SetEscapePod(escapePod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,36 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using NitroxModel_Subnautica.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class ExosuitArmActionProcessor : ClientPacketProcessor<ExosuitArmActionPacket>
|
||||
{
|
||||
public override void Process(ExosuitArmActionPacket packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.ArmId, out GameObject gameObject))
|
||||
{
|
||||
Log.Error("Could not find exosuit arm");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (packet.TechType)
|
||||
{
|
||||
case TechType.ExosuitClawArmModule:
|
||||
ExosuitModuleEvent.UseClaw(gameObject.GetComponent<ExosuitClawArm>(), packet.ArmAction);
|
||||
break;
|
||||
case TechType.ExosuitDrillArmModule:
|
||||
ExosuitModuleEvent.UseDrill(gameObject.GetComponent<ExosuitDrillArm>(), packet.ArmAction);
|
||||
break;
|
||||
case TechType.ExosuitGrapplingArmModule:
|
||||
ExosuitModuleEvent.UseGrappling(gameObject.GetComponent<ExosuitGrapplingArm>(), packet.ArmAction, packet.OpVector?.ToUnity());
|
||||
break;
|
||||
default:
|
||||
Log.Error($"Got an arm tech that is not handled: {packet.TechType} with action: {packet.ArmAction} for id {packet.ArmId}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,28 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using NitroxModel.GameLogic.FMOD;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class FMODAssetProcessor : ClientPacketProcessor<FMODAssetPacket>
|
||||
{
|
||||
private readonly FMODWhitelist fmodWhitelist;
|
||||
|
||||
public FMODAssetProcessor(FMODWhitelist fmodWhitelist)
|
||||
{
|
||||
this.fmodWhitelist = fmodWhitelist;
|
||||
}
|
||||
|
||||
public override void Process(FMODAssetPacket packet)
|
||||
{
|
||||
if (!fmodWhitelist.TryGetSoundData(packet.AssetPath, out SoundData soundData))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(FMODAssetProcessor)}] Whitelist has no item for {packet.AssetPath}.");
|
||||
return;
|
||||
}
|
||||
|
||||
FMODEmitterController.PlayEventOneShot(packet.AssetPath, soundData.Radius, packet.Position.ToUnity(), packet.Volume);
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class FMODCustomEmitterProcessor : ClientPacketProcessor<FMODCustomEmitterPacket>
|
||||
{
|
||||
public override void Process(FMODCustomEmitterPacket packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.Id, out GameObject emitterControllerEntity))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(FMODCustomEmitterProcessor)}] Couldn't find entity {packet.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!emitterControllerEntity.TryGetComponent(out FMODEmitterController fmodEmitterController))
|
||||
{
|
||||
fmodEmitterController = emitterControllerEntity.AddComponent<FMODEmitterController>();
|
||||
fmodEmitterController.LateRegisterEmitter();
|
||||
}
|
||||
|
||||
using (PacketSuppressor<FMODCustomEmitterPacket>.Suppress())
|
||||
using (PacketSuppressor<FMODCustomLoopingEmitterPacket>.Suppress())
|
||||
{
|
||||
if (packet.Play)
|
||||
{
|
||||
fmodEmitterController.PlayCustomEmitter(packet.AssetPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmodEmitterController.StopCustomEmitter(packet.AssetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class FMODCustomLoopingEmitterProcessor : ClientPacketProcessor<FMODCustomLoopingEmitterPacket>
|
||||
{
|
||||
public override void Process(FMODCustomLoopingEmitterPacket packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.Id, out GameObject emitterControllerObject))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(FMODCustomLoopingEmitterProcessor)}] Couldn't find entity {packet.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!emitterControllerObject.TryGetComponent(out FMODEmitterController fmodEmitterController))
|
||||
{
|
||||
fmodEmitterController = emitterControllerObject.AddComponent<FMODEmitterController>();
|
||||
fmodEmitterController.LateRegisterEmitter();
|
||||
}
|
||||
|
||||
fmodEmitterController.PlayCustomLoopingEmitter(packet.AssetPath);
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class FMODEventInstanceProcessor : ClientPacketProcessor<FMODEventInstancePacket>
|
||||
{
|
||||
public override void Process(FMODEventInstancePacket packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.Id, out GameObject emitterControllerObject))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(FMODEventInstanceProcessor)}] Couldn't find entity {packet.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!emitterControllerObject.TryGetComponent(out FMODEmitterController fmodEmitterController))
|
||||
{
|
||||
fmodEmitterController = emitterControllerObject.AddComponent<FMODEmitterController>();
|
||||
fmodEmitterController.LateRegisterEmitter();
|
||||
}
|
||||
|
||||
if (packet.Play)
|
||||
{
|
||||
fmodEmitterController.PlayEventInstance(packet.AssetPath, packet.Volume);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmodEmitterController.StopEventInstance(packet.AssetPath);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class FMODStudioEventEmitterProcessor : ClientPacketProcessor<FMODStudioEmitterPacket>
|
||||
{
|
||||
public override void Process(FMODStudioEmitterPacket packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.Id, out GameObject emitterControllerObject))
|
||||
{
|
||||
Log.ErrorOnce($"[{nameof(FMODStudioEventEmitterProcessor)}] Couldn't find entity {packet.Id}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!emitterControllerObject.TryGetComponent(out FMODEmitterController fmodEmitterController))
|
||||
{
|
||||
fmodEmitterController = emitterControllerObject.AddComponent<FMODEmitterController>();
|
||||
fmodEmitterController.LateRegisterEmitter();
|
||||
}
|
||||
|
||||
using (PacketSuppressor<FMODStudioEmitterPacket>.Suppress())
|
||||
{
|
||||
if (packet.Play)
|
||||
{
|
||||
fmodEmitterController.PlayStudioEmitter(packet.AssetPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
fmodEmitterController.StopStudioEmitter(packet.AssetPath, packet.AllowFadeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class FastCheatChangedProcessor : ClientPacketProcessor<FastCheatChanged>
|
||||
{
|
||||
public override void Process(FastCheatChanged packet)
|
||||
{
|
||||
switch (packet.Cheat)
|
||||
{
|
||||
case FastCheatChanged.FastCheat.HATCH:
|
||||
NoCostConsoleCommand.main.fastHatchCheat = packet.Value;
|
||||
break;
|
||||
|
||||
case FastCheatChanged.FastCheat.GROW:
|
||||
NoCostConsoleCommand.main.fastGrowCheat = packet.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class FireDousedProcessor : ClientPacketProcessor<FireDoused>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public FireDousedProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds and executes <see cref="Fire.Douse(float)"/>. If the fire is extinguished, it will pass a large float to trigger the private
|
||||
/// <see cref="Fire.Extinguish()"/> method.
|
||||
/// </summary>
|
||||
public override void Process(FireDoused packet)
|
||||
{
|
||||
GameObject fireGameObject = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
|
||||
using (PacketSuppressor<FireDoused>.Suppress())
|
||||
{
|
||||
fireGameObject.RequireComponent<Fire>().Douse(packet.DouseAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using FMOD;
|
||||
using FMOD.Studio;
|
||||
using FMODUnity;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.GameLogic.FMOD;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.GameLogic.FMOD;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class FootstepPacketProcessor : ClientPacketProcessor<FootstepPacket>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
private readonly Lazy<FootstepSounds> localFootstepSounds = new(() => Player.mainObject.GetComponent<FootstepSounds>());
|
||||
private PARAMETER_ID fmodIndexSpeed = FMODUWE.invalidParameterId;
|
||||
private readonly float footstepAudioRadius; // To modify this value, modify the last value in the SoundWhitelist_Subnautica.csv file
|
||||
private const float FOOTSTEP_AUDIO_MAX_VOLUME = 0.5f;
|
||||
|
||||
public FootstepPacketProcessor(PlayerManager remotePlayerManager, FMODWhitelist whitelist)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
whitelist.TryGetSoundData("event:/player/footstep_precursor_base", out SoundData soundData);
|
||||
footstepAudioRadius = soundData.Radius;
|
||||
}
|
||||
|
||||
public override void Process(FootstepPacket packet)
|
||||
{
|
||||
Optional<RemotePlayer> player = remotePlayerManager.Find(packet.PlayerID);
|
||||
if (player.HasValue)
|
||||
{
|
||||
FMODAsset asset = packet.AssetIndex switch
|
||||
{
|
||||
FootstepPacket.StepSounds.PRECURSOR => localFootstepSounds.Value.precursorInteriorSound,
|
||||
FootstepPacket.StepSounds.METAL => localFootstepSounds.Value.metalSound,
|
||||
FootstepPacket.StepSounds.LAND => localFootstepSounds.Value.landSound,
|
||||
_ => null
|
||||
};
|
||||
EventInstance evt = FMODUWE.GetEvent(asset);
|
||||
if (evt.isValid())
|
||||
{
|
||||
if (FMODUWE.IsInvalidParameterId(fmodIndexSpeed))
|
||||
{
|
||||
fmodIndexSpeed = FMODUWE.GetEventInstanceParameterIndex(evt, "speed");
|
||||
}
|
||||
ATTRIBUTES_3D attributes = player.Value.Body.To3DAttributes();
|
||||
evt.set3DAttributes(attributes);
|
||||
evt.setParameterValueByIndex(fmodIndexSpeed, player.Value.AnimationController.Velocity.magnitude);
|
||||
evt.setVolume(FMODSystem.CalculateVolume(Player.mainObject.transform.position, player.Value.Body.transform.position, footstepAudioRadius, FOOTSTEP_AUDIO_MAX_VOLUME));
|
||||
evt.start();
|
||||
evt.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class GameModeChangedProcessor : ClientPacketProcessor<GameModeChanged>
|
||||
{
|
||||
private readonly LocalPlayer localPlayer;
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public GameModeChangedProcessor(LocalPlayer localPlayer, PlayerManager playerManager)
|
||||
{
|
||||
this.localPlayer = localPlayer;
|
||||
this.playerManager = playerManager;
|
||||
}
|
||||
|
||||
public override void Process(GameModeChanged packet)
|
||||
{
|
||||
if (packet.AllPlayers || packet.PlayerId == localPlayer.PlayerId)
|
||||
{
|
||||
GameModeUtils.SetGameMode((GameModeOption)(int)packet.GameMode, GameModeOption.None);
|
||||
}
|
||||
if (packet.AllPlayers)
|
||||
{
|
||||
foreach (RemotePlayer remotePlayer in playerManager.GetAll())
|
||||
{
|
||||
remotePlayer.SetGameMode(packet.GameMode);
|
||||
}
|
||||
}
|
||||
else if (playerManager.TryFind(packet.PlayerId, out RemotePlayer remotePlayer))
|
||||
{
|
||||
remotePlayer.SetGameMode(packet.GameMode);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.InitialSync.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class InitialPlayerSyncProcessor : ClientPacketProcessor<InitialPlayerSync>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
private readonly HashSet<IInitialSyncProcessor> processors;
|
||||
private readonly HashSet<Type> alreadyRan = new();
|
||||
private InitialPlayerSync packet;
|
||||
|
||||
private WaitScreen.ManualWaitItem loadingMultiplayerWaitItem;
|
||||
private WaitScreen.ManualWaitItem subWaitScreenItem;
|
||||
|
||||
private int cumulativeProcessorsRan;
|
||||
private int processorsRanLastCycle;
|
||||
|
||||
public InitialPlayerSyncProcessor(IPacketSender packetSender, IEnumerable<IInitialSyncProcessor> processors)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
this.processors = processors.ToSet();
|
||||
}
|
||||
|
||||
public override void Process(InitialPlayerSync packet)
|
||||
{
|
||||
this.packet = packet;
|
||||
loadingMultiplayerWaitItem = WaitScreen.Add(Language.main.Get("Nitrox_SyncingWorld"));
|
||||
cumulativeProcessorsRan = 0;
|
||||
Multiplayer.Main.StartCoroutine(ProcessInitialSyncPacket(this, null));
|
||||
}
|
||||
|
||||
private IEnumerator ProcessInitialSyncPacket(object sender, EventArgs eventArgs)
|
||||
{
|
||||
bool moreProcessorsToRun;
|
||||
do
|
||||
{
|
||||
yield return Multiplayer.Main.StartCoroutine(RunPendingProcessors());
|
||||
|
||||
moreProcessorsToRun = alreadyRan.Count < processors.Count;
|
||||
if (moreProcessorsToRun && processorsRanLastCycle == 0)
|
||||
{
|
||||
throw new Exception($"Detected circular dependencies in initial packet sync between: {GetRemainingProcessorsText()}");
|
||||
}
|
||||
} while (moreProcessorsToRun);
|
||||
|
||||
WaitScreen.Remove(loadingMultiplayerWaitItem);
|
||||
Multiplayer.Main.InitialSyncCompleted = true;
|
||||
|
||||
// When the player finishes loading, we can take back his invincibility
|
||||
Player.main.liveMixin.invincible = false;
|
||||
Player.main.UnfreezeStats();
|
||||
|
||||
packetSender.Send(new PlayerSyncFinished());
|
||||
}
|
||||
|
||||
private IEnumerator RunPendingProcessors()
|
||||
{
|
||||
processorsRanLastCycle = 0;
|
||||
|
||||
foreach (IInitialSyncProcessor processor in processors)
|
||||
{
|
||||
if (IsWaitingToRun(processor.GetType()) && HasDependenciesSatisfied(processor))
|
||||
{
|
||||
loadingMultiplayerWaitItem.SetProgress(cumulativeProcessorsRan, processors.Count);
|
||||
|
||||
alreadyRan.Add(processor.GetType());
|
||||
processorsRanLastCycle++;
|
||||
cumulativeProcessorsRan++;
|
||||
|
||||
Log.Info($"Running {processor.GetType()}");
|
||||
subWaitScreenItem = WaitScreen.Add($"Running {processor.GetType().Name}");
|
||||
yield return Multiplayer.Main.StartCoroutine(processor.Process(packet, subWaitScreenItem));
|
||||
WaitScreen.Remove(subWaitScreenItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasDependenciesSatisfied(IInitialSyncProcessor processor)
|
||||
{
|
||||
foreach (Type dependentType in processor.DependentProcessors)
|
||||
{
|
||||
if (IsWaitingToRun(dependentType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsWaitingToRun(Type processor)
|
||||
{
|
||||
return alreadyRan.Contains(processor) == false;
|
||||
}
|
||||
|
||||
private string GetRemainingProcessorsText()
|
||||
{
|
||||
string remaining = "";
|
||||
|
||||
foreach (IInitialSyncProcessor processor in processors)
|
||||
{
|
||||
if (IsWaitingToRun(processor.GetType()))
|
||||
{
|
||||
remaining += $" {processor.GetType()}";
|
||||
}
|
||||
}
|
||||
|
||||
return remaining;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
class ItemPositionProcessor : ClientPacketProcessor<ItemPosition>
|
||||
{
|
||||
private const float ITEM_TRANSFORM_SMOOTH_PERIOD = 0.25f;
|
||||
|
||||
public override void Process(ItemPosition drop)
|
||||
{
|
||||
Optional<GameObject> opItem = NitroxEntity.GetObjectFrom(drop.Id);
|
||||
|
||||
if (opItem.HasValue)
|
||||
{
|
||||
MovementHelper.MoveRotateGameObject(opItem.Value, drop.Position.ToUnity(), drop.Rotation.ToUnity(), ITEM_TRANSFORM_SMOOTH_PERIOD);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class KnownTechEntryProcessorAdd : ClientPacketProcessor<KnownTechEntryAdd>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public KnownTechEntryProcessorAdd(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void Process(KnownTechEntryAdd packet)
|
||||
{
|
||||
using (PacketSuppressor<KnownTechEntryAdd>.Suppress())
|
||||
{
|
||||
switch (packet.Category)
|
||||
{
|
||||
case KnownTechEntryAdd.EntryCategory.KNOWN:
|
||||
KnownTech.Add(packet.TechType.ToUnity(), packet.Verbose);
|
||||
break;
|
||||
case KnownTechEntryAdd.EntryCategory.ANALYZED:
|
||||
KnownTech.Analyze(packet.TechType.ToUnity(), packet.Verbose);
|
||||
break;
|
||||
default:
|
||||
string categoryName = Enum.GetName(typeof(KnownTechEntryAdd.EntryCategory), packet.Category);
|
||||
Log.Error($"Received an unknown category type for {nameof(KnownTechEntryAdd)} packet: {categoryName}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class LeakRepairedProcessor : ClientPacketProcessor<LeakRepaired>
|
||||
{
|
||||
public override void Process(LeakRepaired packet)
|
||||
{
|
||||
if (NitroxEntity.TryGetComponentFrom(packet.BaseId, out BaseLeakManager baseLeakManager))
|
||||
{
|
||||
baseLeakManager.HealLeakToMax(packet.RelativeCell.ToUnity());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.FMOD;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class MedicalCabinetClickedProcessor : ClientPacketProcessor<MedicalCabinetClicked>
|
||||
{
|
||||
public override void Process(MedicalCabinetClicked packet)
|
||||
{
|
||||
GameObject gameObject = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
MedicalCabinet cabinet = gameObject.RequireComponent<MedicalCabinet>();
|
||||
|
||||
bool medkitPickedUp = !packet.HasMedKit && cabinet.hasMedKit;
|
||||
bool doorChangedState = cabinet.doorOpen != packet.DoorOpen;
|
||||
|
||||
cabinet.hasMedKit = packet.HasMedKit;
|
||||
cabinet.timeSpawnMedKit = packet.NextSpawnTime;
|
||||
|
||||
using (PacketSuppressor<FMODCustomEmitterPacket>.Suppress())
|
||||
using (FMODSystem.SuppressSubnauticaSounds())
|
||||
{
|
||||
if (doorChangedState)
|
||||
{
|
||||
cabinet.Invoke(nameof(MedicalCabinet.ToggleDoorState), 0f);
|
||||
}
|
||||
else if (medkitPickedUp)
|
||||
{
|
||||
cabinet.Invoke(nameof(MedicalCabinet.ToggleDoorState), 2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class MultiplayerSessionPolicyProcessor : ClientPacketProcessor<MultiplayerSessionPolicy>
|
||||
{
|
||||
private readonly IMultiplayerSession multiplayerSession;
|
||||
|
||||
public MultiplayerSessionPolicyProcessor(IMultiplayerSession multiplayerSession)
|
||||
{
|
||||
this.multiplayerSession = multiplayerSession;
|
||||
}
|
||||
|
||||
public override void Process(MultiplayerSessionPolicy packet)
|
||||
{
|
||||
Log.Info("Processing session policy information.");
|
||||
multiplayerSession.ProcessSessionPolicy(packet);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class MultiplayerSessionReservationProcessor : ClientPacketProcessor<MultiplayerSessionReservation>
|
||||
{
|
||||
private readonly IMultiplayerSession multiplayerSession;
|
||||
|
||||
public MultiplayerSessionReservationProcessor(IMultiplayerSession multiplayerSession)
|
||||
{
|
||||
this.multiplayerSession = multiplayerSession;
|
||||
}
|
||||
|
||||
public override void Process(MultiplayerSessionReservation packet)
|
||||
{
|
||||
multiplayerSession.ProcessReservationResponsePacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class MutePlayerProcessor : ClientPacketProcessor<MutePlayer>
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public delegate void PlayerMuted(ushort playerId, bool muted);
|
||||
public PlayerMuted OnPlayerMuted;
|
||||
|
||||
public MutePlayerProcessor(PlayerManager playerManager)
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
}
|
||||
|
||||
public override void Process(MutePlayer packet)
|
||||
{
|
||||
// We only need to notice if that's another player than local player
|
||||
Optional<RemotePlayer> player = playerManager.Find(packet.PlayerId);
|
||||
if (player.HasValue)
|
||||
{
|
||||
player.Value.PlayerContext.IsMuted = packet.Muted;
|
||||
}
|
||||
OnPlayerMuted(packet.PlayerId, packet.Muted);
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class OpenableStateChangedProcessor : ClientPacketProcessor<OpenableStateChanged>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public OpenableStateChangedProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void Process(OpenableStateChanged packet)
|
||||
{
|
||||
GameObject gameObject = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
Openable openable = gameObject.RequireComponent<Openable>();
|
||||
|
||||
using (PacketSuppressor<OpenableStateChanged>.Suppress())
|
||||
{
|
||||
openable.PlayOpenAnimation(packet.IsOpen, packet.Duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PDAEncyclopediaEntryAddProcessor : ClientPacketProcessor<PDAEncyclopediaEntryAdd>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public PDAEncyclopediaEntryAddProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void Process(PDAEncyclopediaEntryAdd packet)
|
||||
{
|
||||
using (PacketSuppressor<PDAEncyclopediaEntryAdd>.Suppress())
|
||||
{
|
||||
PDAEncyclopedia.Add(packet.Key, packet.Verbose);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class PDALogEntryAddProcessor : ClientPacketProcessor<PDALogEntryAdd>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public PDALogEntryAddProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void Process(PDALogEntryAdd packet)
|
||||
{
|
||||
using (PacketSuppressor<PDALogEntryAdd>.Suppress())
|
||||
{
|
||||
PDALog.Add(packet.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PDAScanFinishedProcessor : ClientPacketProcessor<PDAScanFinished>
|
||||
{
|
||||
public override void Process(PDAScanFinished packet)
|
||||
{
|
||||
if (packet.Id != null)
|
||||
{
|
||||
StoryManager.ScanCompleted(packet.Id, packet.Destroy);
|
||||
}
|
||||
if (packet.WasAlreadyResearched)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TechType packetTechType = packet.TechType.ToUnity();
|
||||
if (packet.FullyResearched)
|
||||
{
|
||||
PDAScanner.partial.RemoveAllFast(packetTechType, static (item, techType) => item.techType == techType);
|
||||
PDAScanner.complete.Add(packetTechType);
|
||||
return;
|
||||
}
|
||||
if (PDAScanner.GetPartialEntryByKey(packetTechType, out PDAScanner.Entry entry))
|
||||
{
|
||||
entry.unlocked = packet.UnlockedAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
PDAScanner.Add(packetTechType, packet.UnlockedAmount);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.DataStructures.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PermsChangedProcessor : ClientPacketProcessor<PermsChanged>
|
||||
{
|
||||
private LocalPlayer localPlayer;
|
||||
|
||||
public delegate void PermissionsChanged(Perms perms);
|
||||
public PermissionsChanged OnPermissionsChanged;
|
||||
|
||||
public PermsChangedProcessor(LocalPlayer localPlayer)
|
||||
{
|
||||
this.localPlayer = localPlayer;
|
||||
}
|
||||
|
||||
public override void Process(PermsChanged packet)
|
||||
{
|
||||
localPlayer.Permissions = packet.NewPerms;
|
||||
OnPermissionsChanged(packet.NewPerms);
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel;
|
||||
using NitroxModel.Packets;
|
||||
using Story;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlaySunbeamEventProcessor : ClientPacketProcessor<PlaySunbeamEvent>
|
||||
{
|
||||
public override void Process(PlaySunbeamEvent packet)
|
||||
{
|
||||
// TODO: Look into compound goals and OnUnlock goals to bring back the necessary ones
|
||||
int beginIndex = PlaySunbeamEvent.SunbeamGoals.GetIndex(packet.EventKey);
|
||||
if (beginIndex == -1)
|
||||
{
|
||||
Log.Error($"Couldn't find the corresponding sunbeam event in {nameof(PlaySunbeamEvent.SunbeamGoals)} for key {packet.EventKey}");
|
||||
return;
|
||||
}
|
||||
for (int i = beginIndex; i < PlaySunbeamEvent.SunbeamGoals.Length; i++)
|
||||
{
|
||||
StoryGoalManager.main.completedGoals.Remove(PlaySunbeamEvent.SunbeamGoals[i]);
|
||||
}
|
||||
// Same execution as for StoryGoalCustomEventHandler commands
|
||||
StoryGoalManager.main.OnGoalComplete(packet.EventKey);
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.MonoBehaviours.CinematicController;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerCinematicControllerCallProcessor : ClientPacketProcessor<PlayerCinematicControllerCall>
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public PlayerCinematicControllerCallProcessor(PlayerManager playerManager)
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
}
|
||||
|
||||
public override void Process(PlayerCinematicControllerCall packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.ControllerID, out GameObject entity))
|
||||
{
|
||||
return; // Entity can be not spawned yet bc async.
|
||||
}
|
||||
|
||||
if (!entity.TryGetComponent(out MultiplayerCinematicReference reference))
|
||||
{
|
||||
Log.Warn($"Couldn't find {nameof(MultiplayerCinematicReference)} on {entity.name}:{packet.ControllerID}");
|
||||
return;
|
||||
}
|
||||
|
||||
Optional<RemotePlayer> opPlayer = playerManager.Find(packet.PlayerId);
|
||||
Validate.IsPresent(opPlayer);
|
||||
|
||||
if (packet.StartPlaying)
|
||||
{
|
||||
reference.CallStartCinematicMode(packet.Key, packet.ControllerNameHash, opPlayer.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
reference.CallCinematicModeEnd(packet.Key, packet.ControllerNameHash, opPlayer.Value);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,26 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerDeathProcessor : ClientPacketProcessor<PlayerDeathEvent>
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public PlayerDeathProcessor(PlayerManager playerManager)
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
}
|
||||
|
||||
public override void Process(PlayerDeathEvent playerDeath)
|
||||
{
|
||||
RemotePlayer player = Validate.IsPresent(playerManager.Find(playerDeath.PlayerId));
|
||||
Log.Debug($"{player.PlayerName} died");
|
||||
Log.InGame(Language.main.Get("Nitrox_PlayerDied").Replace("{PLAYER}", player.PlayerName));
|
||||
player.PlayerDeathEvent.Trigger(player);
|
||||
|
||||
// TODO: Add any death related triggers (i.e. scoreboard updates, rewards, etc.)
|
||||
}
|
||||
}
|
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerHeldItemChangedProcessor : ClientPacketProcessor<PlayerHeldItemChanged>
|
||||
{
|
||||
private int defaultLayer;
|
||||
private int viewModelLayer;
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public PlayerHeldItemChangedProcessor(PlayerManager playerManager)
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
|
||||
if (NitroxEnvironment.IsNormal)
|
||||
{
|
||||
SetupLayers();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupLayers()
|
||||
{
|
||||
defaultLayer = LayerMask.NameToLayer("Default");
|
||||
viewModelLayer = LayerMask.NameToLayer("Viewmodel");
|
||||
}
|
||||
|
||||
public override void Process(PlayerHeldItemChanged packet)
|
||||
{
|
||||
Optional<RemotePlayer> opPlayer = playerManager.Find(packet.PlayerId);
|
||||
Validate.IsPresent(opPlayer);
|
||||
|
||||
if (!NitroxEntity.TryGetObjectFrom(packet.ItemId, out GameObject item))
|
||||
{
|
||||
return; // Item can be not spawned yet bc async.
|
||||
}
|
||||
|
||||
Pickupable pickupable = item.GetComponent<Pickupable>();
|
||||
Validate.IsTrue(pickupable);
|
||||
|
||||
Validate.NotNull(pickupable.inventoryItem);
|
||||
|
||||
ItemsContainer inventory = opPlayer.Value.Inventory;
|
||||
PlayerTool tool = item.GetComponent<PlayerTool>();
|
||||
|
||||
// Copied from QuickSlots
|
||||
switch (packet.Type)
|
||||
{
|
||||
case PlayerHeldItemChanged.ChangeType.DRAW_AS_TOOL:
|
||||
Validate.IsTrue(tool);
|
||||
ModelPlug.PlugIntoSocket(tool, opPlayer.Value.ItemAttachPoint);
|
||||
Utils.SetLayerRecursively(item, viewModelLayer);
|
||||
foreach (Animator componentsInChild in tool.GetComponentsInChildren<Animator>())
|
||||
{
|
||||
componentsInChild.cullingMode = AnimatorCullingMode.AlwaysAnimate;
|
||||
}
|
||||
if (tool.mainCollider)
|
||||
{
|
||||
tool.mainCollider.enabled = false;
|
||||
}
|
||||
tool.GetComponent<Rigidbody>().isKinematic = true;
|
||||
item.SetActive(true);
|
||||
tool.SetHandIKTargetsEnabled(true);
|
||||
SafeAnimator.SetBool(opPlayer.Value.ArmsController.GetComponent<Animator>(), $"holding_{tool.animToolName}", true);
|
||||
opPlayer.Value.AnimationController["using_tool_first"] = packet.IsFirstTime == null;
|
||||
|
||||
if (item.TryGetComponent(out FPModel fpModelDraw)) //FPModel needs to be updated
|
||||
{
|
||||
fpModelDraw.OnEquip(null, null);
|
||||
}
|
||||
break;
|
||||
|
||||
case PlayerHeldItemChanged.ChangeType.HOLSTER_AS_TOOL:
|
||||
Validate.IsTrue(tool);
|
||||
item.SetActive(false);
|
||||
Utils.SetLayerRecursively(item, defaultLayer);
|
||||
if (tool.mainCollider)
|
||||
{
|
||||
tool.mainCollider.enabled = true;
|
||||
}
|
||||
tool.GetComponent<Rigidbody>().isKinematic = false;
|
||||
pickupable.inventoryItem.item.Reparent(inventory.tr);
|
||||
foreach (Animator componentsInChild in tool.GetComponentsInChildren<Animator>())
|
||||
{
|
||||
componentsInChild.cullingMode = AnimatorCullingMode.CullUpdateTransforms;
|
||||
}
|
||||
SafeAnimator.SetBool(opPlayer.Value.ArmsController.GetComponent<Animator>(), $"holding_{tool.animToolName}", false);
|
||||
opPlayer.Value.AnimationController["using_tool_first"] = false;
|
||||
|
||||
if (item.TryGetComponent(out FPModel fpModelHolster)) //FPModel needs to be updated
|
||||
{
|
||||
fpModelHolster.OnUnequip(null, null);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case PlayerHeldItemChanged.ChangeType.DRAW_AS_ITEM:
|
||||
pickupable.inventoryItem.item.Reparent(opPlayer.Value.ItemAttachPoint);
|
||||
pickupable.inventoryItem.item.SetVisible(true);
|
||||
Utils.SetLayerRecursively(pickupable.inventoryItem.item.gameObject, viewModelLayer);
|
||||
break;
|
||||
|
||||
case PlayerHeldItemChanged.ChangeType.HOLSTER_AS_ITEM:
|
||||
pickupable.inventoryItem.item.Reparent(inventory.tr);
|
||||
pickupable.inventoryItem.item.SetVisible(false);
|
||||
Utils.SetLayerRecursively(pickupable.inventoryItem.item.gameObject, defaultLayer);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(packet.Type));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerInCyclopsMovementProcessor : ClientPacketProcessor<PlayerInCyclopsMovement>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
|
||||
public PlayerInCyclopsMovementProcessor(PlayerManager remotePlayerManager)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
}
|
||||
|
||||
public override void Process(PlayerInCyclopsMovement movement)
|
||||
{
|
||||
if (remotePlayerManager.TryFind(movement.PlayerId, out RemotePlayer remotePlayer) && remotePlayer.Pawn != null)
|
||||
{
|
||||
remotePlayer.UpdatePositionInCyclops(movement.LocalPosition.ToUnity(), movement.LocalRotation.ToUnity());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
using System.Collections;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using UWE;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerJoinedMultiplayerSessionProcessor : ClientPacketProcessor<PlayerJoinedMultiplayerSession>
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
private readonly Entities entities;
|
||||
|
||||
public PlayerJoinedMultiplayerSessionProcessor(PlayerManager playerManager, Entities entities)
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
this.entities = entities;
|
||||
}
|
||||
|
||||
public override void Process(PlayerJoinedMultiplayerSession packet)
|
||||
{
|
||||
CoroutineHost.StartCoroutine(SpawnRemotePlayer(packet));
|
||||
}
|
||||
|
||||
private IEnumerator SpawnRemotePlayer(PlayerJoinedMultiplayerSession packet)
|
||||
{
|
||||
playerManager.Create(packet.PlayerContext);
|
||||
yield return entities.SpawnEntityAsync(packet.PlayerWorldEntity, true, true);
|
||||
|
||||
Log.Info($"{packet.PlayerContext.PlayerName} joined the game");
|
||||
Log.InGame(Language.main.Get("Nitrox_PlayerJoined").Replace("{PLAYER}", packet.PlayerContext.PlayerName));
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours.Gui.Modals;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class UserKickedProcessor : ClientPacketProcessor<PlayerKicked>
|
||||
{
|
||||
private readonly IMultiplayerSession session;
|
||||
|
||||
public UserKickedProcessor(IMultiplayerSession session)
|
||||
{
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public override void Process(PlayerKicked packet)
|
||||
{
|
||||
string message = Language.main.Get("Nitrox_PlayerKicked");
|
||||
|
||||
if (!string.IsNullOrEmpty(packet.Reason))
|
||||
{
|
||||
message += $"\n {packet.Reason}";
|
||||
}
|
||||
|
||||
session.Disconnect();
|
||||
Modal.Get<KickedModal>()?.Show(message);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerMovementProcessor : ClientPacketProcessor<PlayerMovement>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
|
||||
public PlayerMovementProcessor(PlayerManager remotePlayerManager)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
}
|
||||
|
||||
public override void Process(PlayerMovement movement)
|
||||
{
|
||||
if (remotePlayerManager.TryFind(movement.PlayerId, out RemotePlayer remotePlayer))
|
||||
{
|
||||
remotePlayer.UpdatePosition(movement.Position.ToUnity(),
|
||||
movement.Velocity.ToUnity(),
|
||||
movement.BodyRotation.ToUnity(),
|
||||
movement.AimingRotation.ToUnity());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours.Gui.HUD;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerStatsProcessor : ClientPacketProcessor<PlayerStats>
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public PlayerStatsProcessor(PlayerManager playerManager)
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
}
|
||||
|
||||
public override void Process(PlayerStats playerStats)
|
||||
{
|
||||
if (playerManager.TryFind(playerStats.PlayerId, out RemotePlayer remotePlayer))
|
||||
{
|
||||
RemotePlayerVitals vitals = remotePlayer.vitals;
|
||||
vitals.SetOxygen(playerStats.Oxygen, playerStats.MaxOxygen);
|
||||
vitals.SetHealth(playerStats.Health);
|
||||
vitals.SetFood(playerStats.Food);
|
||||
vitals.SetWater(playerStats.Water);
|
||||
remotePlayer.UpdateHealthAndInfection(playerStats.Health, playerStats.InfectionAmount);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,43 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UWE;
|
||||
using Terrain = NitroxClient.GameLogic.Terrain;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PlayerTeleportedProcessor : ClientPacketProcessor<PlayerTeleported>
|
||||
{
|
||||
public override void Process(PlayerTeleported packet)
|
||||
{
|
||||
Player.main.OnPlayerPositionCheat();
|
||||
|
||||
Vehicle currentVehicle = Player.main.currentMountedVehicle;
|
||||
if (currentVehicle)
|
||||
{
|
||||
currentVehicle.TeleportVehicle(packet.DestinationTo.ToUnity(), currentVehicle.transform.rotation);
|
||||
Player.main.WaitForTeleportation();
|
||||
return;
|
||||
}
|
||||
|
||||
Player.main.SetPosition(packet.DestinationTo.ToUnity());
|
||||
|
||||
if (packet.SubRootID.HasValue && NitroxEntity.TryGetComponentFrom(packet.SubRootID.Value, out SubRoot subRoot))
|
||||
{
|
||||
Player.main.SetCurrentSub(subRoot, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Freeze the player while it's loading its new position
|
||||
Player.main.cinematicModeActive = true;
|
||||
Player.main.WaitForTeleportation();
|
||||
|
||||
CoroutineHost.StartCoroutine(Terrain.WaitForWorldLoad().OnYieldError(e =>
|
||||
{
|
||||
Player.main.cinematicModeActive = false;
|
||||
Log.Warn($"Something wrong happened while waiting for the terrain to load.\n{e}");
|
||||
}));
|
||||
}
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class PvPAttackProcessor : ClientPacketProcessor<PvPAttack>
|
||||
{
|
||||
public override void Process(PvPAttack packet)
|
||||
{
|
||||
if (Player.main && Player.main.liveMixin)
|
||||
{
|
||||
Player.main.liveMixin.TakeDamage(packet.Damage);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,14 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
using Story;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class RadioPlayPendingMessageProcessor : ClientPacketProcessor<RadioPlayPendingMessage>
|
||||
{
|
||||
public override void Process(RadioPlayPendingMessage packet)
|
||||
{
|
||||
StoryGoalManager.main.ExecutePendingRadioMessage();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,13 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class RangedAttackLastTargetUpdateProcessor : ClientPacketProcessor<RangedAttackLastTargetUpdate>
|
||||
{
|
||||
public override void Process(RangedAttackLastTargetUpdate packet)
|
||||
{
|
||||
AI.RangedAttackLastTargetUpdate(packet.CreatureId, packet.TargetId, packet.AttackTypeIndex, packet.State);
|
||||
}
|
||||
}
|
@@ -0,0 +1,71 @@
|
||||
using System.Collections;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UWE;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class RemoveCreatureCorpseProcessor : ClientPacketProcessor<RemoveCreatureCorpse>
|
||||
{
|
||||
private readonly Entities entities;
|
||||
private readonly LiveMixinManager liveMixinManager;
|
||||
private readonly SimulationOwnership simulationOwnership;
|
||||
|
||||
public RemoveCreatureCorpseProcessor(Entities entities, LiveMixinManager liveMixinManager, SimulationOwnership simulationOwnership)
|
||||
{
|
||||
this.entities = entities;
|
||||
this.liveMixinManager = liveMixinManager;
|
||||
this.simulationOwnership = simulationOwnership;
|
||||
}
|
||||
|
||||
public override void Process(RemoveCreatureCorpse packet)
|
||||
{
|
||||
entities.RemoveEntity(packet.CreatureId);
|
||||
if (!NitroxEntity.TryGetComponentFrom(packet.CreatureId, out CreatureDeath creatureDeath))
|
||||
{
|
||||
entities.MarkForDeletion(packet.CreatureId);
|
||||
Log.Warn($"[{nameof(RemoveCreatureCorpseProcessor)}] Could not find entity with id: {packet.CreatureId} to remove corpse from.");
|
||||
return;
|
||||
}
|
||||
|
||||
creatureDeath.transform.localPosition = packet.DeathPosition.ToUnity();
|
||||
creatureDeath.transform.localRotation = packet.DeathRotation.ToUnity();
|
||||
CoroutineHost.StartCoroutine(SimplerOnKillAsync(creatureDeath, packet.CreatureId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls only some parts from <see cref="CreatureDeath.OnKillAsync"/> to avoid sending packets from it
|
||||
/// or already synced behaviour (like spawning another respawner from the remote clients)
|
||||
/// </summary>
|
||||
public IEnumerator SimplerOnKillAsync(CreatureDeath creatureDeath, NitroxId creatureId)
|
||||
{
|
||||
// Ensure we don't broadcast anything from this kill event
|
||||
simulationOwnership.StopSimulatingEntity(creatureId);
|
||||
|
||||
// Remove the position broadcasting stuff from it
|
||||
EntityPositionBroadcaster.RemoveEntityMovementControl(creatureDeath.gameObject, creatureId);
|
||||
|
||||
// Receiving this packet means the creature is dead
|
||||
liveMixinManager.SyncRemoteHealth(creatureDeath.liveMixin, 0);
|
||||
|
||||
// To avoid SpawnRespawner to be called
|
||||
creatureDeath.respawn = false;
|
||||
creatureDeath.hasSpawnedRespawner = true;
|
||||
|
||||
// To avoid the cooked data section
|
||||
bool lastDamageWasHeat = creatureDeath.lastDamageWasHeat;
|
||||
creatureDeath.lastDamageWasHeat = false;
|
||||
|
||||
using (PacketSuppressor<EntityMetadataUpdate>.Suppress())
|
||||
{
|
||||
yield return creatureDeath.OnKillAsync();
|
||||
}
|
||||
|
||||
// Restore the field in case it was useful
|
||||
creatureDeath.lastDamageWasHeat = lastDamageWasHeat;
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel_Subnautica.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class RocketLaunchProcessor : ClientPacketProcessor<RocketLaunch>
|
||||
{
|
||||
private readonly Rockets rockets;
|
||||
|
||||
public RocketLaunchProcessor(Rockets rockets)
|
||||
{
|
||||
this.rockets = rockets;
|
||||
}
|
||||
|
||||
public override void Process(RocketLaunch rocketLaunch)
|
||||
{
|
||||
rockets.RocketLaunch(rocketLaunch.RocketId);
|
||||
}
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
using System.Linq;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel.Packets;
|
||||
using Story;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class ScheduleProcessor : ClientPacketProcessor<Schedule>
|
||||
{
|
||||
public override void Process(Schedule schedulePacket)
|
||||
{
|
||||
ScheduledGoal goal = new()
|
||||
{
|
||||
goalKey = schedulePacket.Key,
|
||||
goalType = (Story.GoalType)schedulePacket.Type,
|
||||
timeExecute = schedulePacket.TimeExecute
|
||||
};
|
||||
if (ShouldSchedule(goal))
|
||||
{
|
||||
StoryGoalScheduler.main.schedule.Add(goal);
|
||||
}
|
||||
Log.Debug($"Processed a Schedule packet [Key: {goal.goalKey}, Type: {goal.goalType}, TimeExecute: {goal.timeExecute}]");
|
||||
}
|
||||
|
||||
private bool ShouldSchedule(ScheduledGoal goal)
|
||||
{
|
||||
return goal.timeExecute >= DayNightCycle.main.timePassedAsDouble && !IsAlreadyKnown(goal.goalKey);
|
||||
}
|
||||
|
||||
private bool IsAlreadyKnown(string goalKey)
|
||||
{
|
||||
return StoryGoalScheduler.main.schedule.Any(g => g.goalKey == goalKey) || // Scheduled
|
||||
StoryGoalManager.main.completedGoals.Contains(goalKey); // Completed
|
||||
}
|
||||
}
|
@@ -0,0 +1,55 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.PlayerLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SeaDragonAttackTargetProcessor : ClientPacketProcessor<SeaDragonAttackTarget>
|
||||
{
|
||||
public override void Process(SeaDragonAttackTarget packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragonMeleeAttack seaDragonMeleeAttack) ||
|
||||
!NitroxEntity.TryGetObjectFrom(packet.TargetId, out GameObject target))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
seaDragonMeleeAttack.seaDragon.Aggression.Value = packet.Aggression;
|
||||
if (target.GetComponent<SubControl>())
|
||||
{
|
||||
// SeaDragonMeleeAttack.OnTouchFront's useful part about Cyclops attack
|
||||
seaDragonMeleeAttack.animator.SetTrigger("shove");
|
||||
seaDragonMeleeAttack.SendMessage("OnMeleeAttack", target, SendMessageOptions.DontRequireReceiver);
|
||||
seaDragonMeleeAttack.timeLastBite = Time.time;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// SeaDragonMeleeAttack.OnTouchFront's useful part about local player attack
|
||||
Collider collider;
|
||||
if (target.TryGetComponent(out RemotePlayerIdentifier remotePlayerIdentifier))
|
||||
{
|
||||
collider = remotePlayerIdentifier.RemotePlayer.Collider;
|
||||
}
|
||||
else if (target.GetComponent<Player>())
|
||||
{
|
||||
collider = Player.mainCollider;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
seaDragonMeleeAttack.timeLastBite = Time.time;
|
||||
if (seaDragonMeleeAttack.attackSound)
|
||||
{
|
||||
using (PacketSuppressor<FMODAssetPacket>.Suppress())
|
||||
{
|
||||
Utils.PlayEnvSound(seaDragonMeleeAttack.attackSound, collider.transform.position, 20f);
|
||||
}
|
||||
}
|
||||
seaDragonMeleeAttack.OnTouch(collider);
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SeaDragonGrabExosuitProcessor : ClientPacketProcessor<SeaDragonGrabExosuit>
|
||||
{
|
||||
public override void Process(SeaDragonGrabExosuit packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragon seaDragon) ||
|
||||
!NitroxEntity.TryGetComponentFrom(packet.TargetId, out Exosuit exosuit))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (PacketSuppressor<SeaDragonGrabExosuit>.Suppress())
|
||||
{
|
||||
seaDragon.GrabExosuit(exosuit);
|
||||
seaDragon.CancelInvoke(nameof(SeaDragon.DamageExosuit));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SeaDragonSwatAttackProcessor : ClientPacketProcessor<SeaDragonSwatAttack>
|
||||
{
|
||||
public override void Process(SeaDragonSwatAttack packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetComponentFrom(packet.SeaDragonId, out SeaDragonMeleeAttack seaDragonMeleeAttack) ||
|
||||
!NitroxEntity.TryGetObjectFrom(packet.TargetId, out GameObject targetObject))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (PacketSuppressor<SeaDragonSwatAttack>.Suppress())
|
||||
{
|
||||
seaDragonMeleeAttack.seaDragon.Aggression.Value = packet.Aggression;
|
||||
seaDragonMeleeAttack.SwatAttack(targetObject, packet.IsRightHand);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SeaTreaderChunkPickedUpProcessor : ClientPacketProcessor<SeaTreaderChunkPickedUp>
|
||||
{
|
||||
public override void Process(SeaTreaderChunkPickedUp packet)
|
||||
{
|
||||
if (NitroxEntity.TryGetComponentFrom(packet.ChunkId, out SinkingGroundChunk sinkingGroundChunk))
|
||||
{
|
||||
GameObject.Destroy(sinkingGroundChunk.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,22 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SeaTreaderSpawnedChunkProcessor : ClientPacketProcessor<SeaTreaderSpawnedChunk>
|
||||
{
|
||||
public override void Process(SeaTreaderSpawnedChunk packet)
|
||||
{
|
||||
if (NitroxEntity.TryGetComponentFrom(packet.CreatureId, out SeaTreader seaTreader) &&
|
||||
seaTreader.TryGetComponentInChildren(out SeaTreaderSounds seaTreaderSounds))
|
||||
{
|
||||
GameObject chunkObject = GameObjectHelper.InstantiateWithId(seaTreaderSounds.stepChunkPrefab, packet.ChunkId);
|
||||
chunkObject.transform.position = packet.Position.ToUnity();
|
||||
chunkObject.transform.rotation = packet.Rotation.ToUnity();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class SeamothModuleActionProcessor : ClientPacketProcessor<SeamothModulesAction>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public SeamothModuleActionProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
public override void Process(SeamothModulesAction packet)
|
||||
{
|
||||
using (PacketSuppressor<SeamothModulesAction>.Suppress())
|
||||
{
|
||||
GameObject _gameObject = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
SeaMoth seamoth = _gameObject.GetComponent<SeaMoth>();
|
||||
if (seamoth != null)
|
||||
{
|
||||
TechType techType = packet.TechType.ToUnity();
|
||||
|
||||
if (techType == TechType.SeamothElectricalDefense)
|
||||
{
|
||||
float[] chargearray = seamoth.quickSlotCharge;
|
||||
float charge = chargearray[packet.SlotID];
|
||||
float slotCharge = seamoth.GetSlotCharge(packet.SlotID);
|
||||
GameObject gameObject = global::Utils.SpawnZeroedAt(seamoth.seamothElectricalDefensePrefab, seamoth.transform, false);
|
||||
ElectricalDefense component = gameObject.GetComponent<ElectricalDefense>();
|
||||
component.charge = charge;
|
||||
component.chargeScalar = slotCharge;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours.Gui.Modals;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class ServerStoppedProcessor : ClientPacketProcessor<ServerStopped>
|
||||
{
|
||||
private readonly IClient client;
|
||||
|
||||
public ServerStoppedProcessor(IClient client)
|
||||
{
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public override void Process(ServerStopped packet)
|
||||
{
|
||||
// We can send the stop instruction right now instead of waiting for the timeout
|
||||
client.Stop();
|
||||
Modal.Get<ServerStoppedModal>()?.Show();
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.GameLogic.PlayerLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SetIntroCinematicModeProcessor : ClientPacketProcessor<SetIntroCinematicMode>
|
||||
{
|
||||
private readonly PlayerManager playerManager;
|
||||
private readonly PlayerCinematics playerCinematics;
|
||||
private readonly LocalPlayer localPlayer;
|
||||
|
||||
public SetIntroCinematicModeProcessor(PlayerManager playerManager, PlayerCinematics playerCinematics, LocalPlayer localPlayer)
|
||||
{
|
||||
this.playerManager = playerManager;
|
||||
this.playerCinematics = playerCinematics;
|
||||
this.localPlayer = localPlayer;
|
||||
}
|
||||
|
||||
public override void Process(SetIntroCinematicMode packet)
|
||||
{
|
||||
if (localPlayer.PlayerId == packet.PlayerId)
|
||||
{
|
||||
if (packet.PartnerId.HasValue)
|
||||
{
|
||||
playerCinematics.IntroCinematicPartnerId = packet.PartnerId;
|
||||
}
|
||||
|
||||
localPlayer.IntroCinematicMode = packet.Mode;
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerManager.TryFind(packet.PlayerId, out RemotePlayer remotePlayer))
|
||||
{
|
||||
remotePlayer.PlayerContext.IntroCinematicMode = packet.Mode;
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Debug($"SetIntroCinematicMode couldn't find Player with id {packet.PlayerId}. This is normal if player has not yet officially joined.");
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SimulationOwnershipChangeProcessor : ClientPacketProcessor<SimulationOwnershipChange>
|
||||
{
|
||||
private readonly SimulationOwnership simulationOwnershipManager;
|
||||
|
||||
public SimulationOwnershipChangeProcessor(SimulationOwnership simulationOwnershipManager)
|
||||
{
|
||||
this.simulationOwnershipManager = simulationOwnershipManager;
|
||||
}
|
||||
|
||||
public override void Process(SimulationOwnershipChange simulationOwnershipChange)
|
||||
{
|
||||
foreach (SimulatedEntity simulatedEntity in simulationOwnershipChange.Entities)
|
||||
{
|
||||
simulationOwnershipManager.TreatSimulatedEntity(simulatedEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,53 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class SimulationOwnershipResponseProcessor : ClientPacketProcessor<SimulationOwnershipResponse>
|
||||
{
|
||||
private readonly IMultiplayerSession multiplayerSession;
|
||||
private readonly SimulationOwnership simulationOwnershipManager;
|
||||
|
||||
public SimulationOwnershipResponseProcessor(IMultiplayerSession multiplayerSession, SimulationOwnership simulationOwnershipManager)
|
||||
{
|
||||
this.multiplayerSession = multiplayerSession;
|
||||
this.simulationOwnershipManager = simulationOwnershipManager;
|
||||
}
|
||||
|
||||
public override void Process(SimulationOwnershipResponse response)
|
||||
{
|
||||
/*
|
||||
* For now, we expect the simulation lock callback to setup entity broadcasting as
|
||||
* most items that are requesting an exclusive lock have custom broadcast code, ex:
|
||||
* vehicles like the cyclops. However, we may one day want to add a watcher here
|
||||
* to ensure broadcast one day, ex:
|
||||
*
|
||||
* EntityPositionBroadcaster.WatchEntity(simulatedEntity.Id, gameObject.Value);
|
||||
*
|
||||
*/
|
||||
simulationOwnershipManager.ReceivedSimulationLockResponse(response.Id, response.LockAcquired, response.LockType);
|
||||
|
||||
if (response.LockAcquired)
|
||||
{
|
||||
RemoveRemoteController(response.Id);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveRemoteController(NitroxId id)
|
||||
{
|
||||
Optional<GameObject> gameObject = NitroxEntity.GetObjectFrom(id);
|
||||
|
||||
if (gameObject.HasValue)
|
||||
{
|
||||
RemotelyControlled remotelyControlled = gameObject.Value.GetComponent<RemotelyControlled>();
|
||||
Object.Destroy(remotelyControlled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,40 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class SpawnEntitiesProcessor : ClientPacketProcessor<SpawnEntities>
|
||||
{
|
||||
private readonly Entities entities;
|
||||
private readonly SimulationOwnership simulationOwnership;
|
||||
|
||||
public SpawnEntitiesProcessor(Entities entities, SimulationOwnership simulationOwnership)
|
||||
{
|
||||
this.entities = entities;
|
||||
this.simulationOwnership = simulationOwnership;
|
||||
}
|
||||
|
||||
public override void Process(SpawnEntities packet)
|
||||
{
|
||||
if (packet.ForceRespawn)
|
||||
{
|
||||
entities.CleanupExistingEntities(packet.Entities);
|
||||
}
|
||||
|
||||
if (packet.Entities.Count > 0)
|
||||
{
|
||||
if (packet.Simulations != null)
|
||||
{
|
||||
foreach (SimulatedEntity simulatedEntity in packet.Simulations)
|
||||
{
|
||||
simulationOwnership.RegisterNewerSimulation(simulatedEntity.Id, simulatedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
// Packet processing is done in the main thread so there's no issue calling this
|
||||
entities.EnqueueEntitiesToSpawn(packet.Entities);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class StasisSphereHitProcessor : ClientPacketProcessor<StasisSphereHit>
|
||||
{
|
||||
private readonly BulletManager bulletManager;
|
||||
|
||||
public StasisSphereHitProcessor(BulletManager bulletManager)
|
||||
{
|
||||
this.bulletManager = bulletManager;
|
||||
}
|
||||
|
||||
public override void Process(StasisSphereHit packet)
|
||||
{
|
||||
bulletManager.StasisSphereHit(packet.PlayerId, packet.Position.ToUnity(), packet.Rotation.ToUnity(), packet.ChargeNormalized, packet.Consumption);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class StasisSphereShotProcessor : ClientPacketProcessor<StasisSphereShot>
|
||||
{
|
||||
private readonly BulletManager bulletManager;
|
||||
|
||||
public StasisSphereShotProcessor(BulletManager bulletManager)
|
||||
{
|
||||
this.bulletManager = bulletManager;
|
||||
}
|
||||
|
||||
public override void Process(StasisSphereShot packet)
|
||||
{
|
||||
bulletManager.ShootStasisSphere(packet.PlayerId, packet.Position.ToUnity(), packet.Rotation.ToUnity(), packet.Speed, packet.LifeTime, packet.ChargeNormalized);
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxModel;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
using Story;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class StoryGoalExecutedClientProcessor : ClientPacketProcessor<StoryGoalExecuted>
|
||||
{
|
||||
private readonly IPacketSender packetSender;
|
||||
|
||||
public StoryGoalExecutedClientProcessor(IPacketSender packetSender)
|
||||
{
|
||||
this.packetSender = packetSender;
|
||||
}
|
||||
|
||||
public override void Process(StoryGoalExecuted packet)
|
||||
{
|
||||
StoryGoalScheduler.main.schedule.RemoveAllFast(packet.Key, static (goal, packetGoalKey) => goal.goalKey == packetGoalKey);
|
||||
|
||||
using (PacketSuppressor<StoryGoalExecuted>.Suppress())
|
||||
using (PacketSuppressor<PDALogEntryAdd>.Suppress())
|
||||
using (PacketSuppressor<KnownTechEntryAdd>.Suppress()) // StoryGoalManager => OnGoalUnlockTracker => UnlockBlueprintData => KnownTech.Add
|
||||
using (PacketSuppressor<PDAEncyclopediaEntryAdd>.Suppress())
|
||||
{
|
||||
StoryGoal.Execute(packet.Key, packet.Type.ToUnity());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.DataStructures.Util;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
public class SubRootChangedProcessor : ClientPacketProcessor<SubRootChanged>
|
||||
{
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
|
||||
public SubRootChangedProcessor(PlayerManager remotePlayerManager)
|
||||
{
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
}
|
||||
|
||||
public override void Process(SubRootChanged packet)
|
||||
{
|
||||
Optional<RemotePlayer> remotePlayer = remotePlayerManager.Find(packet.PlayerId);
|
||||
|
||||
if (remotePlayer.HasValue)
|
||||
{
|
||||
SubRoot subRoot = null;
|
||||
|
||||
if (packet.SubRootId.HasValue)
|
||||
{
|
||||
GameObject sub = NitroxEntity.RequireObjectFrom(packet.SubRootId.Value);
|
||||
subRoot = sub.GetComponent<SubRoot>();
|
||||
}
|
||||
|
||||
remotePlayer.Value.SetSubRoot(subRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class TimeChangeProcessor : ClientPacketProcessor<TimeChange>
|
||||
{
|
||||
private readonly TimeManager timeManager;
|
||||
|
||||
public TimeChangeProcessor(TimeManager timeManager)
|
||||
{
|
||||
this.timeManager = timeManager;
|
||||
}
|
||||
|
||||
public override void Process(TimeChange timeChangePacket)
|
||||
{
|
||||
timeManager.ProcessUpdate(timeChangePacket);
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic.FMOD;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.GameLogic.FMOD;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class ToggleLightsProcessor : ClientPacketProcessor<NitroxModel.Packets.ToggleLights>
|
||||
{
|
||||
private readonly FMODWhitelist fmodWhitelist;
|
||||
|
||||
public ToggleLightsProcessor(FMODWhitelist fmodWhitelist)
|
||||
{
|
||||
this.fmodWhitelist = fmodWhitelist;
|
||||
}
|
||||
|
||||
public override void Process(NitroxModel.Packets.ToggleLights packet)
|
||||
{
|
||||
GameObject gameObject = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
ToggleLights toggleLights = gameObject.RequireComponent<ToggleLights>();
|
||||
|
||||
if (packet.IsOn == toggleLights.GetLightsActive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (PacketSuppressor<NitroxModel.Packets.ToggleLights>.Suppress())
|
||||
using (FMODSystem.SuppressSendingSounds())
|
||||
{
|
||||
using (FMODSystem.SuppressSubnauticaSounds())
|
||||
{
|
||||
toggleLights.SetLightsActive(packet.IsOn);
|
||||
}
|
||||
|
||||
FMODAsset soundAsset;
|
||||
|
||||
if (packet.IsOn)
|
||||
{
|
||||
soundAsset = toggleLights.lightsOnSound ? toggleLights.lightsOnSound.asset : toggleLights.onSound;
|
||||
}
|
||||
else
|
||||
{
|
||||
soundAsset = toggleLights.lightsOffSound ? toggleLights.lightsOffSound.asset : toggleLights.offSound;
|
||||
}
|
||||
|
||||
if (soundAsset && fmodWhitelist.TryGetSoundData(soundAsset.path, out SoundData soundData))
|
||||
{
|
||||
FMODEmitterController.PlayEventOneShot(soundAsset, soundData.Radius, toggleLights.transform.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class TorpedoHitProcessor : ClientPacketProcessor<TorpedoHit>
|
||||
{
|
||||
private readonly BulletManager bulletManager;
|
||||
|
||||
public TorpedoHitProcessor(BulletManager bulletManager)
|
||||
{
|
||||
this.bulletManager = bulletManager;
|
||||
}
|
||||
|
||||
public override void Process(TorpedoHit packet)
|
||||
{
|
||||
bulletManager.TorpedoHit(packet.BulletId, packet.Position.ToUnity(), packet.Rotation.ToUnity());
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class TorpedoShotProcessor : ClientPacketProcessor<TorpedoShot>
|
||||
{
|
||||
private readonly BulletManager bulletManager;
|
||||
|
||||
public TorpedoShotProcessor(BulletManager bulletManager)
|
||||
{
|
||||
this.bulletManager = bulletManager;
|
||||
}
|
||||
|
||||
public override void Process(TorpedoShot packet)
|
||||
{
|
||||
bulletManager.ShootSeamothTorpedo(packet.BulletId, packet.TechType.ToUnity(), packet.Position.ToUnity(), packet.Rotation.ToUnity(), packet.Speed, packet.LifeTime);
|
||||
}
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxModel.Packets;
|
||||
using NitroxModel_Subnautica.DataStructures;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class TorpedoTargetAcquiredProcessor : ClientPacketProcessor<TorpedoTargetAcquired>
|
||||
{
|
||||
private readonly BulletManager bulletManager;
|
||||
|
||||
public TorpedoTargetAcquiredProcessor(BulletManager bulletManager)
|
||||
{
|
||||
this.bulletManager = bulletManager;
|
||||
}
|
||||
|
||||
public override void Process(TorpedoTargetAcquired packet)
|
||||
{
|
||||
bulletManager.TorpedoTargetAcquired(packet.BulletId, packet.TargetId, packet.Position.ToUnity(), packet.Rotation.ToUnity());
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
using System.Collections;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.MonoBehaviours.Vehicles;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.DataStructures;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class VehicleDockingProcessor : ClientPacketProcessor<VehicleDocking>
|
||||
{
|
||||
private readonly Vehicles vehicles;
|
||||
|
||||
public VehicleDockingProcessor(Vehicles vehicles)
|
||||
{
|
||||
this.vehicles = vehicles;
|
||||
}
|
||||
|
||||
public override void Process(VehicleDocking packet)
|
||||
{
|
||||
if (!NitroxEntity.TryGetComponentFrom(packet.VehicleId, out Vehicle vehicle))
|
||||
{
|
||||
Log.Error($"[{nameof(VehicleDockingProcessor)}] could not find Vehicle component on {packet.VehicleId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NitroxEntity.TryGetComponentFrom(packet.DockId, out VehicleDockingBay dockingBay))
|
||||
{
|
||||
Log.Error($"[{nameof(VehicleDockingProcessor)}] could not find VehicleDockingBay component on {packet.DockId}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (vehicle.TryGetComponent(out VehicleMovementReplicator vehicleMovementReplicator))
|
||||
{
|
||||
vehicleMovementReplicator.enabled = false;
|
||||
Log.Debug($"[{nameof(VehicleDockingProcessor)}] Disabled VehicleMovementReplicator on {packet.VehicleId}");
|
||||
}
|
||||
|
||||
vehicle.StartCoroutine(DelayAnimationAndDisablePiloting(vehicle, vehicleMovementReplicator, dockingBay, packet.VehicleId, packet.PlayerId));
|
||||
}
|
||||
|
||||
private IEnumerator DelayAnimationAndDisablePiloting(Vehicle vehicle, VehicleMovementReplicator vehicleMovementReplicator, VehicleDockingBay vehicleDockingBay, NitroxId vehicleId, ushort playerId)
|
||||
{
|
||||
// Consider the vehicle movement latency (we don't teleport the vehicle to the docking position)
|
||||
if (vehicleMovementReplicator)
|
||||
{
|
||||
// NB: We don't have a lifetime ahead of us
|
||||
float waitTime = Mathf.Clamp(vehicleMovementReplicator.maxAllowedLatency, 0f, 2f);
|
||||
yield return new WaitForSeconds(waitTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
yield return Yielders.WaitFor1Second;
|
||||
}
|
||||
|
||||
// DockVehicle sets the rigid body kinematic of the vehicle to true, we don't want that behaviour
|
||||
// Therefore disable kinematic (again) to remove the bouncing behavior
|
||||
DockRemoteVehicle(vehicleDockingBay, vehicle);
|
||||
vehicle.useRigidbody.isKinematic = false;
|
||||
|
||||
yield return Yielders.WaitFor2Seconds;
|
||||
vehicles.SetOnPilotMode(vehicleId, playerId, false);
|
||||
}
|
||||
|
||||
/// Copy of <see cref="VehicleDockingBay.DockVehicle"/> without the player centric bits
|
||||
private void DockRemoteVehicle(VehicleDockingBay bay, Vehicle vehicle)
|
||||
{
|
||||
bay.dockedVehicle = vehicle;
|
||||
LargeWorldStreamer.main.cellManager.UnregisterEntity(bay.dockedVehicle.gameObject);
|
||||
bay.dockedVehicle.transform.parent = bay.GetSubRoot().transform;
|
||||
vehicle.docked = true;
|
||||
bay.vehicle_docked_param = true;
|
||||
SkyEnvironmentChanged.Broadcast(vehicle.gameObject, bay.subRoot);
|
||||
bay.GetSubRoot().BroadcastMessage("UnlockDoors", SendMessageOptions.DontRequireReceiver);
|
||||
|
||||
// We are only actually adding the health if we have a lock on the vehicle so we're fine to keep this routine going on.
|
||||
// If vehicle ownership changes then it'll still be fine because the verification will still be on the vehicle ownership.
|
||||
bay.CancelInvoke(nameof(VehicleDockingBay.RepairVehicle));
|
||||
bay.InvokeRepeating(nameof(VehicleDockingBay.RepairVehicle), 0.0f, 5f);
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class VehicleMovementsProcessor : ClientPacketProcessor<VehicleMovements>
|
||||
{
|
||||
public override void Process(VehicleMovements packet)
|
||||
{
|
||||
if (!MovementBroadcaster.Instance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (MovementData movementData in packet.Data)
|
||||
{
|
||||
if (MovementBroadcaster.Instance.Replicators.TryGetValue(movementData.Id, out MovementReplicator movementReplicator))
|
||||
{
|
||||
movementReplicator.AddSnapshot(movementData, (float)packet.RealTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class VehicleOnPilotModeChangedProcessor : ClientPacketProcessor<VehicleOnPilotModeChanged>
|
||||
{
|
||||
private readonly Vehicles vehicles;
|
||||
private readonly PlayerManager playerManager;
|
||||
|
||||
public VehicleOnPilotModeChangedProcessor(Vehicles vehicles, PlayerManager playerManager)
|
||||
{
|
||||
this.vehicles = vehicles;
|
||||
this.playerManager = playerManager;
|
||||
}
|
||||
|
||||
public override void Process(VehicleOnPilotModeChanged packet)
|
||||
{
|
||||
if (NitroxEntity.TryGetObjectFrom(packet.VehicleId, out GameObject gameObject))
|
||||
{
|
||||
// If the vehicle is docked, then we will manually set the piloting mode
|
||||
// once the animations complete. This prevents weird behaviour such as the
|
||||
// player existing the vehicle while it is about to dock (the event fires
|
||||
// before the animation completes on the remote player.)
|
||||
if (gameObject.TryGetComponent(out Vehicle vehicle) && vehicle.docked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
vehicles.SetOnPilotMode(gameObject, packet.PlayerId, packet.IsPiloting);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
using System.Collections;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxClient.Unity.Helper;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors;
|
||||
|
||||
public class VehicleUndockingProcessor : ClientPacketProcessor<VehicleUndocking>
|
||||
{
|
||||
private readonly Vehicles vehicles;
|
||||
private readonly PlayerManager remotePlayerManager;
|
||||
|
||||
public VehicleUndockingProcessor(Vehicles vehicles, PlayerManager remotePlayerManager)
|
||||
{
|
||||
this.vehicles = vehicles;
|
||||
this.remotePlayerManager = remotePlayerManager;
|
||||
}
|
||||
|
||||
public override void Process(VehicleUndocking packet)
|
||||
{
|
||||
GameObject vehicleGo = NitroxEntity.RequireObjectFrom(packet.VehicleId);
|
||||
GameObject vehicleDockingBayGo = NitroxEntity.RequireObjectFrom(packet.DockId);
|
||||
|
||||
Vehicle vehicle = vehicleGo.RequireComponent<Vehicle>();
|
||||
VehicleDockingBay vehicleDockingBay = vehicleDockingBayGo.RequireComponent<VehicleDockingBay>();
|
||||
|
||||
using (PacketSuppressor<VehicleUndocking>.Suppress())
|
||||
{
|
||||
if (packet.UndockingStart)
|
||||
{
|
||||
StartVehicleUndocking(packet, vehicleGo, vehicle, vehicleDockingBay);
|
||||
}
|
||||
else
|
||||
{
|
||||
FinishVehicleUndocking(packet, vehicle, vehicleDockingBay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void StartVehicleUndocking(VehicleUndocking packet, GameObject vehicleGo, Vehicle vehicle, VehicleDockingBay vehicleDockingBay)
|
||||
{
|
||||
vehicleDockingBay.subRoot.BroadcastMessage("OnLaunchBayOpening", SendMessageOptions.DontRequireReceiver);
|
||||
SkyEnvironmentChanged.Broadcast(vehicleGo, (GameObject)null);
|
||||
|
||||
if (remotePlayerManager.TryFind(packet.PlayerId, out RemotePlayer player))
|
||||
{
|
||||
// It can happen that the player turns in circles around himself in the vehicle. This stops it.
|
||||
player.RigidBody.angularVelocity = Vector3.zero;
|
||||
vehicles.SetOnPilotMode(packet.VehicleId, packet.PlayerId, true);
|
||||
}
|
||||
vehicleDockingBay.StartCoroutine(StartUndockingAnimation(vehicleDockingBay));
|
||||
|
||||
if (vehicle.TryGetComponent(out MovementReplicator vehicleMovementReplicator))
|
||||
{
|
||||
vehicleMovementReplicator.ClearBuffer();
|
||||
Log.Debug($"[{nameof(VehicleDockingProcessor)}] Clear MovementReplicator on {packet.VehicleId}");
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerator StartUndockingAnimation(VehicleDockingBay vehicleDockingBay)
|
||||
{
|
||||
yield return Yielders.WaitFor2Seconds;
|
||||
vehicleDockingBay.vehicle_docked_param = false;
|
||||
}
|
||||
|
||||
private void FinishVehicleUndocking(VehicleUndocking packet, Vehicle vehicle, VehicleDockingBay vehicleDockingBay)
|
||||
{
|
||||
if (vehicleDockingBay.GetSubRoot().isCyclops)
|
||||
{
|
||||
vehicleDockingBay.SetVehicleUndocked();
|
||||
}
|
||||
vehicleDockingBay.dockedVehicle = null;
|
||||
vehicleDockingBay.CancelInvoke(nameof(VehicleDockingBay.RepairVehicle));
|
||||
vehicle.docked = false;
|
||||
if (remotePlayerManager.TryFind(packet.PlayerId, out RemotePlayer player))
|
||||
{
|
||||
// Sometimes the player is not set accordingly which stretches the player's model instead of putting them in place
|
||||
// after undocking. This fixes it (the player rigid body seems to not be set right sometimes)
|
||||
player.SetSubRoot(null);
|
||||
player.SetVehicle(null);
|
||||
player.SetVehicle(vehicle);
|
||||
}
|
||||
vehicles.SetOnPilotMode(packet.VehicleId, packet.PlayerId, true);
|
||||
|
||||
if (vehicle.TryGetComponent(out MovementReplicator vehicleMovementReplicator))
|
||||
{
|
||||
vehicleMovementReplicator.enabled = true;
|
||||
Log.Debug($"[{nameof(VehicleDockingProcessor)}] Enabled MovementReplicator on {packet.VehicleId}");
|
||||
}
|
||||
|
||||
Log.Debug("Set vehicle undocking complete");
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
using NitroxClient.Communication.Abstract;
|
||||
using NitroxClient.Communication.Packets.Processors.Abstract;
|
||||
using NitroxClient.GameLogic;
|
||||
using NitroxClient.MonoBehaviours;
|
||||
using NitroxModel.Packets;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NitroxClient.Communication.Packets.Processors
|
||||
{
|
||||
class WeldActionProcessor : ClientPacketProcessor<WeldAction>
|
||||
{
|
||||
private IMultiplayerSession multiplayerSession;
|
||||
private SimulationOwnership simulationOwnership;
|
||||
|
||||
public WeldActionProcessor(IMultiplayerSession multiplayerSession, SimulationOwnership simulationOwnership)
|
||||
{
|
||||
this.multiplayerSession = multiplayerSession;
|
||||
this.simulationOwnership = simulationOwnership;
|
||||
}
|
||||
|
||||
public override void Process(WeldAction packet)
|
||||
{
|
||||
GameObject gameObject = NitroxEntity.RequireObjectFrom(packet.Id);
|
||||
|
||||
if (!simulationOwnership.HasAnyLockType(packet.Id))
|
||||
{
|
||||
Log.Error($"Got WeldAction packet for {packet.Id} but did not find the lock corresponding to it");
|
||||
return;
|
||||
}
|
||||
|
||||
LiveMixin liveMixin = gameObject.GetComponent<LiveMixin>();
|
||||
if (!liveMixin)
|
||||
{
|
||||
Log.Error($"Did not find LiveMixin for GameObject {packet.Id} even though it was welded.");
|
||||
return;
|
||||
}
|
||||
// If we add other player sounds/animations, this is the place to do it for welding
|
||||
liveMixin.AddHealth(packet.HealthAdded);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user