Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Movements overhaul #2189

Merged
merged 20 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
3e7c40e
WIP
tornac1234 Sep 22, 2024
67dbc24
Changed movement replicator's buffer to be a LinkedList (very good op…
tornac1234 Oct 26, 2024
7d56989
Huge improvements to get a smooth movements for seamoths and exosuits…
tornac1234 Oct 27, 2024
e3c364f
Reimplement channels into LiteNetLib
tornac1234 Oct 30, 2024
e762c9c
First attempt at implementing a variable latency adaptor
tornac1234 Oct 30, 2024
ee9b937
Fix channels (again), add two settings for better control of movement…
tornac1234 Oct 30, 2024
f8569e0
Deprecate the current vehicle animation system and replace it by a ne…
tornac1234 Oct 31, 2024
fa4b1ae
Fix seamoth enter sound playing all over the map, cyclops driver not …
tornac1234 Nov 1, 2024
8852d26
Restore driver state of other players when connecting to a server
tornac1234 Nov 1, 2024
e5bc3a8
Fix remotely driven exosuits' animations
tornac1234 Nov 2, 2024
0d4b2d3
Fix a possible divide by zero from TimeManager.DeltaTime
tornac1234 Nov 2, 2024
5eed7ed
Refactor docking code to bring it up to new standard
Jannify Oct 28, 2024
a4c41ef
Decouple docking patches from Vehicles.cs
Jannify Nov 2, 2024
f145902
Supress MovementReplicator during (un)docking
Jannify Nov 2, 2024
d9ed3db
Fix docking processor
Jannify Nov 2, 2024
8f38ff0
Few corrections for docking and simulation ownership
tornac1234 Nov 3, 2024
cbdad29
Refactors and little corrections here and there
tornac1234 Nov 10, 2024
3211798
Add a movement broadcast rate limiter
tornac1234 Nov 10, 2024
b6b86ca
Fix bugs: not being able to drive a vehicle, rate limiter entries not…
tornac1234 Nov 11, 2024
7d32fe7
Fix a remove while enumerating in dictionary
tornac1234 Nov 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ event:/sub/seamoth/crush_depth_warning;false;false;0
event:/sub/seamoth/depth_update;false;false;0
event:/sub/seamoth/dock;false;false;0
event:/sub/seamoth/dock_seamoth_cyclops;false;false;0
event:/sub/seamoth/enter_seamoth;false;false;0
event:/sub/seamoth/enter_seamoth;false;false;50
event:/sub/seamoth/impact_solid_hard;false;false;0
event:/sub/seamoth/impact_solid_medium;false;false;0
event:/sub/seamoth/impact_solid_soft;false;false;0
Expand Down
1 change: 1 addition & 0 deletions Nitrox.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002EMemberReordering_002EMigrations_002ECSharpFileLayoutPatternRemoveIsAttributeUpgrade/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAlwaysTreatStructAsNotReorderableMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ public LiteNetLibClient(PacketReceiver packetReceiver, INetworkDebugger networkD
listener.PeerDisconnectedEvent += Disconnected;
listener.NetworkReceiveEvent += ReceivedNetworkData;


client = new NetManager(listener)
{
UpdateTime = 15,
ChannelsCount = (byte)typeof(Packet.UdpChannelId).GetEnumValues().Length,
#if DEBUG
DisconnectTimeout = 300000 //Disables Timeout (for 5 min) for debug purpose (like if you jump though the server code)
#endif
Expand Down Expand Up @@ -64,7 +66,7 @@ public void Send(Packet packet)
dataWriter.Put(packetData);

networkDebugger?.PacketSent(packet, dataWriter.Length);
client.SendToAll(dataWriter, NitroxDeliveryMethod.ToLiteNetLib(packet.DeliveryMethod));
client.SendToAll(dataWriter, (byte)packet.UdpChannel, NitroxDeliveryMethod.ToLiteNetLib(packet.DeliveryMethod));
}

public void Stop()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
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)
public SpawnEntitiesProcessor(Entities entities, SimulationOwnership simulationOwnership)
{
this.entities = entities;
this.simulationOwnership = simulationOwnership;
}

public override void Process(SpawnEntities packet)
Expand All @@ -22,6 +25,14 @@ public override void Process(SpawnEntities packet)

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);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,56 +1,84 @@
using System.Collections;
using NitroxClient.Communication.Abstract;
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
namespace NitroxClient.Communication.Packets.Processors;

public class VehicleDockingProcessor : ClientPacketProcessor<VehicleDocking>
{
public class VehicleDockingProcessor : ClientPacketProcessor<VehicleDocking>
private readonly Vehicles vehicles;

public VehicleDockingProcessor(Vehicles vehicles)
{
this.vehicles = vehicles;
}

public override void Process(VehicleDocking packet)
{
private readonly IPacketSender packetSender;
private readonly Vehicles vehicles;
if (!NitroxEntity.TryGetComponentFrom(packet.VehicleId, out Vehicle vehicle))
{
Log.Error($"[{nameof(VehicleDockingProcessor)}] could not find Vehicle component on {packet.VehicleId}");
return;
}

public VehicleDockingProcessor(IPacketSender packetSender, Vehicles vehicles)
if (!NitroxEntity.TryGetComponentFrom(packet.DockId, out VehicleDockingBay dockingBay))
{
this.packetSender = packetSender;
this.vehicles = vehicles;
Log.Error($"[{nameof(VehicleDockingProcessor)}] could not find VehicleDockingBay component on {packet.DockId}");
return;
}

public override void Process(VehicleDocking packet)
if (vehicle.TryGetComponent(out VehicleMovementReplicator vehicleMovementReplicator))
{
GameObject vehicleGo = NitroxEntity.RequireObjectFrom(packet.VehicleId);
GameObject vehicleDockingBayGo = NitroxEntity.RequireObjectFrom(packet.DockId);

Vehicle vehicle = vehicleGo.RequireComponent<Vehicle>();
VehicleDockingBay vehicleDockingBay = vehicleDockingBayGo.RequireComponent<VehicleDockingBay>();

using (PacketSuppressor<VehicleDocking>.Suppress())
{
Log.Debug($"Set vehicle docked for {vehicleDockingBay.gameObject.name}");
vehicle.GetComponent<MultiplayerVehicleControl>().SetPositionVelocityRotation(vehicle.transform.position, Vector3.zero, vehicle.transform.rotation, Vector3.zero);
vehicle.GetComponent<MultiplayerVehicleControl>().Exit();
}
vehicle.StartCoroutine(DelayAnimationAndDisablePiloting(vehicle, vehicleDockingBay, packet.VehicleId, packet.PlayerId));
vehicleMovementReplicator.enabled = false;
Log.Debug($"[{nameof(VehicleDockingProcessor)}] Disabled VehicleMovementReplicator on {packet.VehicleId}");
}

IEnumerator DelayAnimationAndDisablePiloting(Vehicle vehicle, VehicleDockingBay vehicleDockingBay, NitroxId vehicleId, ushort playerId)
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
vehicleDockingBay.DockVehicle(vehicle);
vehicle.useRigidbody.isKinematic = false;
yield return Yielders.WaitFor2Seconds;
vehicles.SetOnPilotMode(vehicleId, playerId, false);
if (!vehicle.docked)
{
Log.Error($"Vehicle {vehicleId} not docked after docking process");
}
}

// 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);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
using NitroxClient.Communication.Abstract;
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
namespace NitroxClient.Communication.Packets.Processors;

public class VehicleOnPilotModeChangedProcessor : ClientPacketProcessor<VehicleOnPilotModeChanged>
{
public class VehicleOnPilotModeChangedProcessor : ClientPacketProcessor<VehicleOnPilotModeChanged>
{
private readonly IPacketSender packetSender;
private readonly Vehicles vehicles;
private readonly Vehicles vehicles;
private readonly PlayerManager playerManager;

public VehicleOnPilotModeChangedProcessor(IPacketSender packetSender, Vehicles vehicles)
{
this.packetSender = packetSender;
this.vehicles = vehicles;
}
public VehicleOnPilotModeChangedProcessor(Vehicles vehicles, PlayerManager playerManager)
{
this.vehicles = vehicles;
this.playerManager = playerManager;
}

public override void Process(VehicleOnPilotModeChanged packet)
public override void Process(VehicleOnPilotModeChanged packet)
{
if (NitroxEntity.TryGetObjectFrom(packet.VehicleId, out GameObject gameObject))
{
GameObject vehicleGo = NitroxEntity.RequireObjectFrom(packet.VehicleId);
Vehicle vehicle = vehicleGo.RequireComponent<Vehicle>();

// 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 (!vehicle.docked)
if (gameObject.TryGetComponent(out Vehicle vehicle) && vehicle.docked)
{
vehicles.SetOnPilotMode(packet.VehicleId, packet.PlayerId, packet.IsPiloting);
return;
}

vehicles.SetOnPilotMode(gameObject, packet.PlayerId, packet.IsPiloting);
}
}
}
Loading