From a60d423acc7a09a6c4da04eb9a61e908c7a1780d Mon Sep 17 00:00:00 2001 From: killzoms Date: Sun, 13 Aug 2023 09:01:40 -0400 Subject: [PATCH 01/11] overhaul movment --- .../Processors/PlayerMovementProcessor.cs | 11 +-- .../Processors/VehicleDockingProcessor.cs | 4 +- .../Processors/VehicleUndockingProcessor.cs | 4 +- .../PlayerPositionInitialSyncProcessor.cs | 5 -- NitroxClient/GameLogic/LocalPlayer.cs | 4 +- NitroxClient/GameLogic/RemotePlayer.cs | 45 +++++++----- NitroxClient/GameLogic/Vehicles.cs | 9 ++- .../{GameLogic => Helpers}/MovementHelper.cs | 6 +- .../MonoBehaviours/AnimationController.cs | 8 +-- .../MonoBehaviours/MovementController.cs | 69 +++++++++++++++++++ .../MonoBehaviours/MultiplayerExosuit.cs | 3 +- .../MultiplayerVehicleControl.cs | 37 ++++------ .../PlayerMovementBroadcaster.cs | 34 +++------ .../GameLogic/ExoSuitMovementData.cs | 6 +- .../Helper/VehicleMovementFactory.cs | 6 +- .../GameLogic/BasicVehicleMovementData.cs | 6 +- .../GameLogic/VehicleMovementData.cs | 22 +++--- .../DataStructures/Unity/NitroxTransform.cs | 24 +++++-- NitroxModel/Packets/Movement.cs | 3 +- NitroxModel/Packets/PlayerMovement.cs | 6 +- NitroxModel/Packets/VehicleMovement.cs | 4 +- .../Dynamic/FMOD_CustomEmitter_Start_Patch.cs | 4 +- .../VehicleMovementPacketProcessor.cs | 3 +- .../Processors/VehicleUndockingProcessor.cs | 1 + 24 files changed, 181 insertions(+), 143 deletions(-) rename NitroxClient/{GameLogic => Helpers}/MovementHelper.cs (94%) create mode 100644 NitroxClient/MonoBehaviours/MovementController.cs diff --git a/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs b/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs index 896f965556..6dc6082d8c 100644 --- a/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs +++ b/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using NitroxClient.Communication.Packets.Processors.Abstract; using NitroxClient.GameLogic; using NitroxClient.MonoBehaviours; @@ -26,14 +26,7 @@ public override void Process(PlayerMovement movement) return; } - Multiplayer.Main.StartCoroutine(QueueForFixedUpdate(remotePlayer.Value, movement)); - } - - private IEnumerator QueueForFixedUpdate(RemotePlayer player, PlayerMovement movement) - { - yield return Yielders.WaitForFixedUpdate; - player.UpdatePosition(movement.Position.ToUnity(), - movement.Velocity.ToUnity(), + remotePlayer.Value.UpdatePosition(movement.Position.ToUnity(), movement.BodyRotation.ToUnity(), movement.AimingRotation.ToUnity()); } diff --git a/NitroxClient/Communication/Packets/Processors/VehicleDockingProcessor.cs b/NitroxClient/Communication/Packets/Processors/VehicleDockingProcessor.cs index 5031f2f62b..9134402c0e 100644 --- a/NitroxClient/Communication/Packets/Processors/VehicleDockingProcessor.cs +++ b/NitroxClient/Communication/Packets/Processors/VehicleDockingProcessor.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using NitroxClient.Communication.Abstract; using NitroxClient.Communication.Packets.Processors.Abstract; using NitroxClient.GameLogic; @@ -32,7 +32,7 @@ public override void Process(VehicleDocking packet) using (PacketSuppressor.Suppress()) { Log.Debug($"Set vehicle docked for {vehicleDockingBay.gameObject.name}"); - vehicle.GetComponent().SetPositionVelocityRotation(vehicle.transform.position, Vector3.zero, vehicle.transform.rotation, Vector3.zero); + vehicle.GetComponent().SetPositionRotation(vehicle.transform.position, vehicle.transform.rotation); vehicle.GetComponent().Exit(); } vehicle.StartCoroutine(DelayAnimationAndDisablePiloting(vehicle, vehicleDockingBay, packet.VehicleId, packet.PlayerId)); diff --git a/NitroxClient/Communication/Packets/Processors/VehicleUndockingProcessor.cs b/NitroxClient/Communication/Packets/Processors/VehicleUndockingProcessor.cs index 2f216ab825..998f4cea52 100644 --- a/NitroxClient/Communication/Packets/Processors/VehicleUndockingProcessor.cs +++ b/NitroxClient/Communication/Packets/Processors/VehicleUndockingProcessor.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using NitroxClient.Communication.Abstract; using NitroxClient.Communication.Packets.Processors.Abstract; using NitroxClient.GameLogic; @@ -56,7 +56,7 @@ private void StartVehicleUndocking(VehicleUndocking packet, GameObject vehicleGo vehicle.mainAnimator.SetBool("player_in", true); playerInstance.Attach(vehicle.playerPosition.transform); // It can happen that the player turns in circles around himself in the vehicle. This stops it. - playerInstance.RigidBody.angularVelocity = Vector3.zero; + // playerInstance.RigidBody.angularVelocity = Vector3.zero; // May not happen anymore needs verifying playerInstance.ArmsController.SetWorldIKTarget(vehicle.leftHandPlug, vehicle.rightHandPlug); playerInstance.AnimationController["in_seamoth"] = vehicle is SeaMoth; playerInstance.AnimationController["in_exosuit"] = playerInstance.AnimationController["using_mechsuit"] = vehicle is Exosuit; diff --git a/NitroxClient/GameLogic/InitialSync/PlayerPositionInitialSyncProcessor.cs b/NitroxClient/GameLogic/InitialSync/PlayerPositionInitialSyncProcessor.cs index 416d42b2f4..4a38a80146 100644 --- a/NitroxClient/GameLogic/InitialSync/PlayerPositionInitialSyncProcessor.cs +++ b/NitroxClient/GameLogic/InitialSync/PlayerPositionInitialSyncProcessor.cs @@ -79,11 +79,6 @@ public override IEnumerator Process(InitialPlayerSync packet, WaitScreen.ManualW yield break; } - Transform rootTransform = subRoot.transform; - Quaternion vehicleAngle = rootTransform.rotation; - // "position" is a relative position and "positionInVehicle" an absolute position - Vector3 positionInVehicle = vehicleAngle * position + rootTransform.position; - Player.main.SetPosition(positionInVehicle, rotation * vehicleAngle); Player.main.cinematicModeActive = false; Player.main.UpdateIsUnderwater(); } diff --git a/NitroxClient/GameLogic/LocalPlayer.cs b/NitroxClient/GameLogic/LocalPlayer.cs index 780e381fdd..f3f6d4c0c4 100644 --- a/NitroxClient/GameLogic/LocalPlayer.cs +++ b/NitroxClient/GameLogic/LocalPlayer.cs @@ -1,4 +1,4 @@ -using System; +using System; using NitroxClient.Communication.Abstract; using NitroxClient.GameLogic.PlayerLogic.PlayerModel; using NitroxClient.GameLogic.PlayerLogic.PlayerModel.Abstract; @@ -58,7 +58,7 @@ public void BroadcastLocation(Vector3 location, Vector3 velocity, Quaternion bod } else { - movement = new PlayerMovement(multiplayerSession.Reservation.PlayerId, location.ToDto(), velocity.ToDto(), bodyRotation.ToDto(), aimingRotation.ToDto()); + movement = new PlayerMovement(multiplayerSession.Reservation.PlayerId, location.ToDto(), bodyRotation.ToDto(), aimingRotation.ToDto()); } packetSender.Send(movement); diff --git a/NitroxClient/GameLogic/RemotePlayer.cs b/NitroxClient/GameLogic/RemotePlayer.cs index f2a53fcbff..4c0d52cbb3 100644 --- a/NitroxClient/GameLogic/RemotePlayer.cs +++ b/NitroxClient/GameLogic/RemotePlayer.cs @@ -28,6 +28,7 @@ public class RemotePlayer : INitroxPlayer public AnimationController AnimationController { get; private set; } public ItemsContainer Inventory { get; private set; } public Transform ItemAttachPoint { get; private set; } + public MovementController MovementController { get; private set; } public ushort PlayerId => PlayerContext.PlayerId; public string PlayerName => PlayerContext.PlayerName; @@ -56,6 +57,9 @@ public void InitializeGameObject(GameObject playerBody) RigidBody = Body.AddComponent(); RigidBody.useGravity = false; RigidBody.interpolation = RigidbodyInterpolation.Interpolate; + RigidBody.isKinematic = true; + MovementController = Body.EnsureComponent(); + MovementController.AfterUpdate += OnUpdate; NitroxEntity.SetNewId(Body, PlayerContext.PlayerNitroxId); @@ -101,27 +105,27 @@ public void Detach() SkyEnvironmentChanged.Broadcast(Body, (GameObject)null); } - public void UpdatePosition(Vector3 position, Vector3 velocity, Quaternion bodyRotation, Quaternion aimingRotation) + public void UpdatePosition(Vector3 position, Quaternion bodyRotation, Quaternion aimingRotation) { Body.SetActive(true); - - // When receiving movement packets, a player can not be controlling a vehicle (they can walk through subroots though). SetVehicle(null); SetPilotingChair(null); - // If in a subroot the position will be relative to the subroot - if (SubRoot && !SubRoot.isBase) - { - Quaternion vehicleAngle = SubRoot.transform.rotation; - position = vehicleAngle * position; - position += SubRoot.transform.position; - bodyRotation = vehicleAngle * bodyRotation; - aimingRotation = vehicleAngle * aimingRotation; - } - RigidBody.velocity = AnimationController.Velocity = MovementHelper.GetCorrectedVelocity(position, velocity, Body, Time.fixedDeltaTime * (PlayerMovementBroadcaster.LOCATION_BROADCAST_TICK_SKIPS + 1)); - RigidBody.angularVelocity = MovementHelper.GetCorrectedAngularVelocity(bodyRotation, Vector3.zero, Body, Time.fixedDeltaTime * (PlayerMovementBroadcaster.LOCATION_BROADCAST_TICK_SKIPS + 1)); + + MovementController.enabled = true; + + MovementController.TargetPosition = position; + MovementController.TargetRotation = bodyRotation; AnimationController.AimingRotation = aimingRotation; - AnimationController.UpdatePlayerAnimations = true; + } + + private void OnUpdate() + { + if (!Vehicle && !PilotingChair) + { + AnimationController.Velocity = MovementController.Velocity; + AnimationController.UpdatePlayerAnimations = true; + } } public void SetPilotingChair(PilotingChair newPilotingChair) @@ -129,6 +133,7 @@ public void SetPilotingChair(PilotingChair newPilotingChair) if (PilotingChair != newPilotingChair) { PilotingChair = newPilotingChair; + bool isInPilotingChair = newPilotingChair != null; MultiplayerCyclops mpCyclops = null; @@ -162,7 +167,9 @@ public void SetPilotingChair(PilotingChair newPilotingChair) } } - RigidBody.isKinematic = AnimationController["cyclops_steering"] = newPilotingChair != null; + RigidBody.isKinematic = AnimationController["cyclops_steering"] = isInPilotingChair; + RigidBody.interpolation = isInPilotingChair ? RigidbodyInterpolation.None : RigidbodyInterpolation.Interpolate; + MovementController.enabled = !isInPilotingChair; } } @@ -235,10 +242,12 @@ public void SetVehicle(Vehicle newVehicle) } } - RigidBody.isKinematic = newVehicle; - Vehicle = newVehicle; + RigidBody.interpolation = Vehicle ? RigidbodyInterpolation.None : RigidbodyInterpolation.Interpolate; + RigidBody.isKinematic = Vehicle; + MovementController.enabled = !Vehicle; + AnimationController["in_seamoth"] = newVehicle is SeaMoth; AnimationController["in_exosuit"] = AnimationController["using_mechsuit"] = newVehicle is Exosuit; } diff --git a/NitroxClient/GameLogic/Vehicles.cs b/NitroxClient/GameLogic/Vehicles.cs index ea0fd0d530..d45d21002e 100644 --- a/NitroxClient/GameLogic/Vehicles.cs +++ b/NitroxClient/GameLogic/Vehicles.cs @@ -82,11 +82,9 @@ public void UpdateVehiclePosition(VehicleMovementData vehicleModel, Optional()); + PilotingChair pilotingChair = subRoot.AliveOrNull()?.GetComponentInChildren(); + playerInstance.SetPilotingChair(pilotingChair); playerInstance.AnimationController.UpdatePlayerAnimations = false; } } diff --git a/NitroxClient/GameLogic/MovementHelper.cs b/NitroxClient/Helpers/MovementHelper.cs similarity index 94% rename from NitroxClient/GameLogic/MovementHelper.cs rename to NitroxClient/Helpers/MovementHelper.cs index 3e7e1433a0..ac54f81a9f 100644 --- a/NitroxClient/GameLogic/MovementHelper.cs +++ b/NitroxClient/Helpers/MovementHelper.cs @@ -1,6 +1,6 @@ -using UnityEngine; +using UnityEngine; -namespace NitroxClient.GameLogic +namespace NitroxClient.Helpers { public static class MovementHelper { @@ -69,7 +69,7 @@ public static Vector3 GetCorrectedAngularVelocity(Quaternion remoteRotation, Vec // Here I drop down to 0.9f times the desired movement, // since we'd rather undershoot and ease into the correct angle // than overshoot and oscillate around it in the event of errors. - return (.9f * Mathf.Deg2Rad * angle / correctionTime) * axis + angularVelocty; + return .9f * Mathf.Deg2Rad * angle / correctionTime * axis + angularVelocty; } } } diff --git a/NitroxClient/MonoBehaviours/AnimationController.cs b/NitroxClient/MonoBehaviours/AnimationController.cs index 09fde7a211..da17a645ec 100644 --- a/NitroxClient/MonoBehaviours/AnimationController.cs +++ b/NitroxClient/MonoBehaviours/AnimationController.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; namespace NitroxClient.MonoBehaviours { @@ -23,13 +23,13 @@ public void Awake() this["is_underwater"] = true; } - public void FixedUpdate() + public void Update() { if (UpdatePlayerAnimations) { Vector3 rotationCorrectedVelocity = gameObject.transform.rotation.GetInverse() * Velocity; - smoothedVelocity = UWE.Utils.SlerpVector(smoothedVelocity, rotationCorrectedVelocity, Vector3.Normalize(rotationCorrectedVelocity - smoothedVelocity) * SMOOTHING_SPEED * Time.fixedDeltaTime); + smoothedVelocity = UWE.Utils.SlerpVector(smoothedVelocity, rotationCorrectedVelocity, Vector3.Normalize(rotationCorrectedVelocity - smoothedVelocity) * SMOOTHING_SPEED * Time.deltaTime); animator.SetFloat("move_speed", smoothedVelocity.magnitude); animator.SetFloat("move_speed_x", smoothedVelocity.x); @@ -43,7 +43,7 @@ public void FixedUpdate() } viewPitch = -viewPitch; - smoothViewPitch = Mathf.Lerp(smoothViewPitch, viewPitch, 4f * Time.fixedDeltaTime); + smoothViewPitch = Mathf.Lerp(smoothViewPitch, viewPitch, 4f * Time.deltaTime); animator.SetFloat("view_pitch", smoothViewPitch); } } diff --git a/NitroxClient/MonoBehaviours/MovementController.cs b/NitroxClient/MonoBehaviours/MovementController.cs new file mode 100644 index 0000000000..3b26d2adaf --- /dev/null +++ b/NitroxClient/MonoBehaviours/MovementController.cs @@ -0,0 +1,69 @@ +using NitroxClient.GameLogic; +using Serilog.Events; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace NitroxClient.MonoBehaviours +{ + public class MovementController : MonoBehaviour + { + public float Scalar { get; set; } = 1f; + public Vector3 TargetPosition { get; set; } + public Quaternion TargetRotation { get; set; } + public Transform TargetTransform { get; set; } + + public event Action BeforeUpdate = () => {}; + public event Action BeforeFixedUpdate = () => {}; + public event Action AfterUpdate = () => {}; + public event Action AfterFixedUpdate = () => {}; + + private Rigidbody rigidbody; + public Vector3 Velocity; + + private void Start() + { + rigidbody = GetComponent(); + } + + private void Update() + { + BeforeUpdate(); + if (!rigidbody) + { + transform.position = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, Scalar * Time.fixedDeltaTime); + transform.rotation = Quaternion.Lerp(transform.rotation, TargetRotation, Scalar * Time.deltaTime); + } + AfterUpdate(); + } + + private void FixedUpdate() + { + BeforeFixedUpdate(); + if (rigidbody) + { + float timing = Scalar * Time.fixedDeltaTime; + Vector3 newPos = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, timing); + Quaternion newRot = Quaternion.Lerp(transform.rotation, TargetRotation, timing); + + if (rigidbody.isKinematic) + { + rigidbody.MovePosition(newPos); + rigidbody.MoveRotation(newRot); + } + else + { + rigidbody.velocity = Velocity; + + Quaternion delta = TargetRotation * transform.rotation.GetInverse(); + delta.ToAngleAxis(out float angle, out Vector3 axis); + rigidbody.angularVelocity = Mathf.Deg2Rad * angle / timing * axis; + } + } + AfterFixedUpdate(); + } + } +} diff --git a/NitroxClient/MonoBehaviours/MultiplayerExosuit.cs b/NitroxClient/MonoBehaviours/MultiplayerExosuit.cs index 1ca49d1ad2..ea8f493e08 100644 --- a/NitroxClient/MonoBehaviours/MultiplayerExosuit.cs +++ b/NitroxClient/MonoBehaviours/MultiplayerExosuit.cs @@ -1,4 +1,4 @@ -using NitroxClient.Unity.Smoothing; +using NitroxClient.Unity.Smoothing; using UnityEngine; namespace NitroxClient.MonoBehaviours @@ -15,7 +15,6 @@ protected override void Awake() WheelYawSetter = value => exosuit.steeringWheelYaw = value; WheelPitchSetter = value => exosuit.steeringWheelPitch = value; base.Awake(); - SmoothRotation = new ExosuitSmoothRotation(gameObject.transform.rotation); } internal override void Enter() diff --git a/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs b/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs index f0bd70e127..ee4095aa52 100644 --- a/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs +++ b/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs @@ -1,4 +1,4 @@ -using System; +using System; using NitroxClient.GameLogic; using NitroxClient.Unity.Smoothing; using UnityEngine; @@ -7,28 +7,22 @@ namespace NitroxClient.MonoBehaviours { public abstract class MultiplayerVehicleControl : MonoBehaviour { - private Rigidbody rigidbody; + private MovementController movementController; protected readonly SmoothParameter SmoothYaw = new SmoothParameter(); protected readonly SmoothParameter SmoothPitch = new SmoothParameter(); protected readonly SmoothVector SmoothLeftArm = new SmoothVector(); protected readonly SmoothVector SmoothRightArm = new SmoothVector(); - protected SmoothVector SmoothPosition; - protected SmoothVector SmoothVelocity; - protected SmoothRotation SmoothRotation; - protected SmoothVector SmoothAngularVelocity; protected Action WheelYawSetter; protected Action WheelPitchSetter; protected virtual void Awake() { - rigidbody = gameObject.GetComponent(); + movementController = gameObject.EnsureComponent(); + // For now, we assume the set position and rotation is equal to the server one. - // Default velocities are probably empty, but set them anyway. - SmoothPosition = new SmoothVector(gameObject.transform.position); - SmoothVelocity = new SmoothVector(rigidbody.velocity); - SmoothRotation = new SmoothRotation(gameObject.transform.rotation); - SmoothAngularVelocity = new SmoothVector(rigidbody.angularVelocity); + movementController.TargetPosition = transform.position; + movementController.TargetRotation = transform.rotation; } protected virtual void FixedUpdate() @@ -36,25 +30,16 @@ protected virtual void FixedUpdate() SmoothYaw.FixedUpdate(); SmoothPitch.FixedUpdate(); - SmoothPosition.FixedUpdate(); - SmoothVelocity.FixedUpdate(); - rigidbody.isKinematic = false; // we should maybe find a way to remove UWE's FreezeRigidBodyWhenFar component...tried removing it but caused a bunch of issues. - rigidbody.velocity = MovementHelper.GetCorrectedVelocity(SmoothPosition.Current, SmoothVelocity.Current, gameObject, Time.fixedDeltaTime); - SmoothRotation.FixedUpdate(); - SmoothAngularVelocity.FixedUpdate(); - rigidbody.angularVelocity = MovementHelper.GetCorrectedAngularVelocity(SmoothRotation.Current, SmoothAngularVelocity.Current, gameObject, Time.fixedDeltaTime); - + WheelYawSetter(SmoothYaw.SmoothValue); WheelPitchSetter(SmoothPitch.SmoothValue); } - internal void SetPositionVelocityRotation(Vector3 remotePosition, Vector3 remoteVelocity, Quaternion remoteRotation, Vector3 remoteAngularVelocity) + internal void SetPositionRotation(Vector3 remotePosition, Quaternion remoteRotation) { gameObject.SetActive(true); - SmoothPosition.Target = remotePosition; - SmoothVelocity.Target = remoteVelocity; - SmoothRotation.Target = remoteRotation; - SmoothAngularVelocity.Target = remoteAngularVelocity; + movementController.TargetPosition = remotePosition; + movementController.TargetRotation = remoteRotation; } internal virtual void SetSteeringWheel(float yaw, float pitch) @@ -71,11 +56,13 @@ internal virtual void SetArmPositions(Vector3 leftArmPosition, Vector3 rightArmP internal virtual void Enter() { + movementController.enabled = true; enabled = true; } public virtual void Exit() { + movementController.enabled = false; enabled = false; } diff --git a/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs b/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs index d2e02aea98..e5145de510 100644 --- a/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs +++ b/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs @@ -12,13 +12,13 @@ namespace NitroxClient.MonoBehaviours; public class PlayerMovementBroadcaster : MonoBehaviour { /// - /// Amount of physics updates to skip for sending location broadcasts. + /// Amount of time to skip for sending location broadcasts. /// TODO: Allow servers to set this value for clients. With many clients connected to the server, a higher value can be preferred. /// - public const int LOCATION_BROADCAST_TICK_SKIPS = 1; + public const float LOCATION_BROADCAST_TIME = 0.04f; private LocalPlayer localPlayer; - private int locationBroadcastSkipThreshold = LOCATION_BROADCAST_TICK_SKIPS; + private float nextLocationBroadcast; public void Awake() { @@ -27,13 +27,10 @@ public void Awake() public void FixedUpdate() { - // Throttle location broadcasts to not run on every physics tick. - if (locationBroadcastSkipThreshold-- > 0) + if (Time.fixedTime >= nextLocationBroadcast) { - return; + nextLocationBroadcast = Time.fixedTime + LOCATION_BROADCAST_TIME; } - // Reset skip threshold. - locationBroadcastSkipThreshold = LOCATION_BROADCAST_TICK_SKIPS; // Freecam does disable main camera control // But it's also disabled when driving the cyclops through a cyclops camera (content.activeSelf is only true when controlling through a cyclops camera) @@ -51,24 +48,11 @@ public void FixedUpdate() Quaternion aimingRotation = Player.main.camRoot.GetAimingTransform().rotation; Optional vehicle = GetVehicleMovement(); - SubRoot subRoot = Player.main.GetCurrentSub(); - - // If in a subroot the position will be relative to the subroot - if (subRoot && !subRoot.isBase) + if (Player.main.isPiloting) { - // Rotate relative player position relative to the subroot (else there are problems with respawning) - Transform subRootTransform = subRoot.transform; - Quaternion undoVehicleAngle = subRootTransform.rotation.GetInverse(); - currentPosition = currentPosition - subRootTransform.position; - currentPosition = undoVehicleAngle * currentPosition; - bodyRotation = undoVehicleAngle * bodyRotation; - aimingRotation = undoVehicleAngle * aimingRotation; - - if (Player.main.isPiloting && subRoot.isCyclops) - { - // In case you're driving the cyclops, the currentPosition is the real position of the player, so we need to send it to the server - vehicle.Value.DriverPosition = currentPosition.ToDto(); - } + // In case you're driving a vehicle, the currentPosition is the real position of the player, so we need to send it to the server + vehicle.Value.DriverPosition = currentPosition.ToDto(); + vehicle.Value.DriverRotation = Player.main.transform.rotation.ToDto(); } localPlayer.BroadcastLocation(currentPosition, playerVelocity, bodyRotation, aimingRotation, vehicle); diff --git a/NitroxModel-Subnautica/DataStructures/GameLogic/ExoSuitMovementData.cs b/NitroxModel-Subnautica/DataStructures/GameLogic/ExoSuitMovementData.cs index 30c2439329..4a85767bad 100644 --- a/NitroxModel-Subnautica/DataStructures/GameLogic/ExoSuitMovementData.cs +++ b/NitroxModel-Subnautica/DataStructures/GameLogic/ExoSuitMovementData.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.Serialization; using BinaryPack.Attributes; using NitroxModel.DataStructures; @@ -23,8 +23,8 @@ protected ExosuitMovementData() // Constructor for serialization. Has to be "protected" for json serialization. } - public ExosuitMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation, NitroxVector3 velocity, NitroxVector3 angularVelocity, float steeringWheelYaw, float steeringWheelPitch, bool appliedThrottle, NitroxVector3 leftAimTarget, NitroxVector3 rightAimTarget, NitroxVector3? driverPosition = null) - : base(techType, id, position, rotation, velocity, angularVelocity, steeringWheelYaw, steeringWheelPitch, appliedThrottle, driverPosition) + public ExosuitMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation, float steeringWheelYaw, float steeringWheelPitch, bool appliedThrottle, NitroxVector3 leftAimTarget, NitroxVector3 rightAimTarget, NitroxVector3 driverPosition = default, NitroxQuaternion driverRotation = default) + : base(techType, id, position, rotation, steeringWheelYaw, steeringWheelPitch, appliedThrottle, driverPosition, driverRotation) { LeftAimTarget = leftAimTarget; RightAimTarget = rightAimTarget; diff --git a/NitroxModel-Subnautica/Helper/VehicleMovementFactory.cs b/NitroxModel-Subnautica/Helper/VehicleMovementFactory.cs index e075a9bc2f..9f0a28189c 100644 --- a/NitroxModel-Subnautica/Helper/VehicleMovementFactory.cs +++ b/NitroxModel-Subnautica/Helper/VehicleMovementFactory.cs @@ -1,4 +1,4 @@ -using NitroxModel.DataStructures; +using NitroxModel.DataStructures; using NitroxModel.DataStructures.GameLogic; using NitroxModel_Subnautica.DataStructures; using NitroxModel_Subnautica.DataStructures.GameLogic; @@ -13,9 +13,9 @@ public static VehicleMovementData GetVehicleMovementData(TechType techType, Nitr switch (techType) { case TechType.Exosuit: - return new ExosuitMovementData(techType.ToDto(), id, position.ToDto(), rotation.ToDto(), velocity.ToDto(), angularVelocity.ToDto(), steeringWheelYaw, steeringWheelPitch, appliedThrottle, leftAimTarget.ToDto(), rightAimTarget.ToDto()); + return new ExosuitMovementData(techType.ToDto(), id, position.ToDto(), rotation.ToDto(), steeringWheelYaw, steeringWheelPitch, appliedThrottle, leftAimTarget.ToDto(), rightAimTarget.ToDto()); default: - return new BasicVehicleMovementData(techType.ToDto(), id, position.ToDto(), rotation.ToDto(), velocity.ToDto(), angularVelocity.ToDto(), steeringWheelYaw, steeringWheelPitch, appliedThrottle); + return new BasicVehicleMovementData(techType.ToDto(), id, position.ToDto(), rotation.ToDto(), steeringWheelYaw, steeringWheelPitch, appliedThrottle); } } } diff --git a/NitroxModel/DataStructures/GameLogic/BasicVehicleMovementData.cs b/NitroxModel/DataStructures/GameLogic/BasicVehicleMovementData.cs index aa073a2f40..6f83cb9b47 100644 --- a/NitroxModel/DataStructures/GameLogic/BasicVehicleMovementData.cs +++ b/NitroxModel/DataStructures/GameLogic/BasicVehicleMovementData.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.Serialization; using NitroxModel.DataStructures.Unity; @@ -11,6 +11,6 @@ public class BasicVehicleMovementData : VehicleMovementData public BasicVehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation) : base(techType, id, position, rotation) { } - public BasicVehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation, NitroxVector3 velocity, NitroxVector3 angularVelocity, float steeringWheelYaw, float steeringWheelPitch, bool appliedThrottle, NitroxVector3? driverPosition = null) : - base(techType, id, position, rotation, velocity, angularVelocity, steeringWheelYaw, steeringWheelPitch, appliedThrottle, driverPosition) { } + public BasicVehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation, float steeringWheelYaw, float steeringWheelPitch, bool appliedThrottle, NitroxVector3 driverPosition = default, NitroxQuaternion driverRotation = default) : + base(techType, id, position, rotation, steeringWheelYaw, steeringWheelPitch, appliedThrottle, driverPosition, driverRotation) { } } diff --git a/NitroxModel/DataStructures/GameLogic/VehicleMovementData.cs b/NitroxModel/DataStructures/GameLogic/VehicleMovementData.cs index 959aeb9afe..161092be16 100644 --- a/NitroxModel/DataStructures/GameLogic/VehicleMovementData.cs +++ b/NitroxModel/DataStructures/GameLogic/VehicleMovementData.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.Serialization; using BinaryPack.Attributes; using NitroxModel.DataStructures.Unity; @@ -21,12 +21,6 @@ public abstract class VehicleMovementData [DataMember(Order = 4)] public NitroxQuaternion Rotation { get; } - [DataMember(Order = 5)] - public NitroxVector3 Velocity { get; } - - [DataMember(Order = 6)] - public NitroxVector3 AngularVelocity { get; } - [DataMember(Order = 7)] public float SteeringWheelYaw { get; } @@ -37,7 +31,10 @@ public abstract class VehicleMovementData public bool AppliedThrottle { get; } [DataMember(Order = 10)] - public NitroxVector3? DriverPosition { get; set; } + public NitroxVector3 DriverPosition { get; set; } + + [DataMember(Order = 11)] + public NitroxQuaternion DriverRotation { get; set; } [IgnoreConstructor] protected VehicleMovementData() @@ -45,18 +42,17 @@ protected VehicleMovementData() // Constructor for serialization. Has to be "protected" for json serialization. } - public VehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation, NitroxVector3 velocity, NitroxVector3 angularVelocity, float steeringWheelYaw, float steeringWheelPitch, bool appliedThrottle, NitroxVector3? driverPosition = null) + public VehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation, float steeringWheelYaw, float steeringWheelPitch, bool appliedThrottle, NitroxVector3 driverPosition = default, NitroxQuaternion driverRotation = default) { TechType = techType; Id = id; Position = position; Rotation = rotation; - Velocity = velocity; - AngularVelocity = angularVelocity; SteeringWheelYaw = steeringWheelYaw; SteeringWheelPitch = steeringWheelPitch; AppliedThrottle = appliedThrottle; DriverPosition = driverPosition; + DriverRotation = driverRotation; } public VehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 position, NitroxQuaternion rotation) @@ -65,8 +61,6 @@ public VehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 p Id = id; Position = position; Rotation = rotation; - Velocity = NitroxVector3.Zero; - AngularVelocity = NitroxVector3.Zero; SteeringWheelYaw = 0f; SteeringWheelPitch = 0f; AppliedThrottle = false; @@ -74,7 +68,7 @@ public VehicleMovementData(NitroxTechType techType, NitroxId id, NitroxVector3 p public override string ToString() { - return $"[VehicleMovementData - TechType: {TechType}, Id: {Id}, Position: {Position}, Rotation: {Rotation}, Velocity: {Velocity}, AngularVelocity: {AngularVelocity}, SteeringWheelYaw: {SteeringWheelYaw}, SteeringWheelPitch: {SteeringWheelPitch}, AppliedThrottle: {AppliedThrottle}]"; + return $"[VehicleMovementData - TechType: {TechType}, Id: {Id}, Position: {Position}, Rotation: {Rotation}, SteeringWheelYaw: {SteeringWheelYaw}, SteeringWheelPitch: {SteeringWheelPitch}, AppliedThrottle: {AppliedThrottle}, DriverPosition: {DriverPosition}]"; } } } diff --git a/NitroxModel/DataStructures/Unity/NitroxTransform.cs b/NitroxModel/DataStructures/Unity/NitroxTransform.cs index 259e3301bc..88bab69cee 100644 --- a/NitroxModel/DataStructures/Unity/NitroxTransform.cs +++ b/NitroxModel/DataStructures/Unity/NitroxTransform.cs @@ -23,7 +23,7 @@ public Matrix4x4 LocalToWorldMatrix { get { - Matrix4x4 cachedMatrix = Matrix4x4Extension.Compose(LocalPosition, LocalRotation, LocalScale); + Matrix4x4 cachedMatrix = Matrix4x4Extension.Compose(LocalPosition, LocalRotation, LocalScale); // its not cached yet return Parent != null ? cachedMatrix * Parent.LocalToWorldMatrix : cachedMatrix; } @@ -36,13 +36,11 @@ public NitroxVector3 Position { get { - Matrix4x4 matrix = Parent?.LocalToWorldMatrix ?? Matrix4x4.Identity; - return matrix.Transform(LocalPosition); + return TransformPoint(LocalPosition); } set { - Matrix4x4 matrix = Parent != null ? Matrix4x4Extension.Compose(value, LocalRotation, LocalScale) * Parent.LocalToWorldMatrix.Invert() : Matrix4x4Extension.Compose(value, LocalRotation, LocalScale); - LocalPosition = (NitroxVector3)matrix.Translation; + LocalPosition = InverseTransformPoint(value); } } @@ -58,7 +56,7 @@ public NitroxQuaternion Rotation } set { - Matrix4x4 matrix = Parent != null ? Matrix4x4Extension.Compose(LocalPosition, value, LocalScale) * Parent.LocalToWorldMatrix.Invert() : Matrix4x4Extension.Compose(LocalPosition, value, LocalScale); + Matrix4x4 matrix = Parent != null ? Matrix4x4.CreateFromQuaternion((Quaternion)value) * Parent.LocalToWorldMatrix.Invert() : Matrix4x4Extension.Compose(LocalPosition, value, LocalScale); Matrix4x4.Decompose(matrix, out Vector3 _, out Quaternion rotation, out Vector3 _); LocalRotation = (NitroxQuaternion)rotation; @@ -91,6 +89,20 @@ public NitroxTransform(NitroxVector3 localPosition, NitroxQuaternion localRotati LocalScale = scale; } + public NitroxVector3 InverseTransformPoint(NitroxVector3 point) + { + Matrix4x4 pointMatrix = Parent != null ? Matrix4x4.CreateTranslation((Vector3)point) * Parent.LocalToWorldMatrix.Invert() : Matrix4x4.CreateTranslation((Vector3)point); + + return (NitroxVector3)pointMatrix.Translation; + } + + public NitroxVector3 TransformPoint(NitroxVector3 localPoint) + { + Matrix4x4 pointMatrix = Parent != null ? Matrix4x4.CreateTranslation((Vector3)localPoint) * Parent.LocalToWorldMatrix : Matrix4x4.CreateTranslation((Vector3)localPoint); + + return (NitroxVector3)pointMatrix.Translation; + } + public override string ToString() { return $"(Position: {Position}, LocalPosition: {LocalPosition}, Rotation: {Rotation}, LocalRotation: {LocalRotation}, LocalScale: {LocalScale})"; diff --git a/NitroxModel/Packets/Movement.cs b/NitroxModel/Packets/Movement.cs index 12b4ad05a2..03c1a46b49 100644 --- a/NitroxModel/Packets/Movement.cs +++ b/NitroxModel/Packets/Movement.cs @@ -1,4 +1,4 @@ -using System; +using System; using NitroxModel.DataStructures.Unity; namespace NitroxModel.Packets; @@ -8,7 +8,6 @@ public abstract class Movement : Packet { public abstract ushort PlayerId { get; } public abstract NitroxVector3 Position { get; } - public abstract NitroxVector3 Velocity { get; } public abstract NitroxQuaternion BodyRotation { get; } public abstract NitroxQuaternion AimingRotation { get; } } diff --git a/NitroxModel/Packets/PlayerMovement.cs b/NitroxModel/Packets/PlayerMovement.cs index 094ae31784..965d042eb7 100644 --- a/NitroxModel/Packets/PlayerMovement.cs +++ b/NitroxModel/Packets/PlayerMovement.cs @@ -1,4 +1,4 @@ -using System; +using System; using NitroxModel.DataStructures.Unity; using NitroxModel.Networking; @@ -9,15 +9,13 @@ public class PlayerMovement : Movement { public override ushort PlayerId { get; } public override NitroxVector3 Position { get; } - public override NitroxVector3 Velocity { get; } public override NitroxQuaternion BodyRotation { get; } public override NitroxQuaternion AimingRotation { get; } - public PlayerMovement(ushort playerId, NitroxVector3 position, NitroxVector3 velocity, NitroxQuaternion bodyRotation, NitroxQuaternion aimingRotation) + public PlayerMovement(ushort playerId, NitroxVector3 position, NitroxQuaternion bodyRotation, NitroxQuaternion aimingRotation) { PlayerId = playerId; Position = position; - Velocity = velocity; BodyRotation = bodyRotation; AimingRotation = aimingRotation; DeliveryMethod = NitroxDeliveryMethod.DeliveryMethod.UNRELIABLE_SEQUENCED; diff --git a/NitroxModel/Packets/VehicleMovement.cs b/NitroxModel/Packets/VehicleMovement.cs index 5f1a9498ee..3ea1d356aa 100644 --- a/NitroxModel/Packets/VehicleMovement.cs +++ b/NitroxModel/Packets/VehicleMovement.cs @@ -1,4 +1,4 @@ -using System; +using System; using BinaryPack.Attributes; using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.Unity; @@ -15,8 +15,6 @@ public class VehicleMovement : Movement [IgnoredMember] public override NitroxVector3 Position => VehicleMovementData.Position; [IgnoredMember] - public override NitroxVector3 Velocity => VehicleMovementData.Velocity; - [IgnoredMember] public override NitroxQuaternion BodyRotation => VehicleMovementData.Rotation; [IgnoredMember] public override NitroxQuaternion AimingRotation => VehicleMovementData.Rotation; diff --git a/NitroxPatcher/Patches/Dynamic/FMOD_CustomEmitter_Start_Patch.cs b/NitroxPatcher/Patches/Dynamic/FMOD_CustomEmitter_Start_Patch.cs index d1d991328d..c22dc75eec 100644 --- a/NitroxPatcher/Patches/Dynamic/FMOD_CustomEmitter_Start_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/FMOD_CustomEmitter_Start_Patch.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using FMOD.Studio; using NitroxClient.GameLogic.FMOD; using NitroxClient.MonoBehaviours; @@ -25,7 +25,7 @@ public static void Prefix(FMOD_CustomEmitter __instance) return; } - if (!__instance.TryGetComponentInParent(out NitroxEntity entity)) + if (!__instance.transform.TryGetComponentInAscendance(10, out NitroxEntity entity)) { Log.Warn($"[FMOD_CustomEmitter_Start_Patch] - No NitroxEntity for \"{__instance.asset.path}\" found!"); return; diff --git a/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs b/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs index 9e0fd1de1e..6a22c3c9de 100644 --- a/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs +++ b/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs @@ -31,7 +31,8 @@ public override void Process(VehicleMovement packet, Player player) if (player.Id == packet.PlayerId) { - player.Position = packet.VehicleMovementData.DriverPosition ?? packet.Position; + player.Position = packet.VehicleMovementData.DriverPosition; + player.Rotation = packet.VehicleMovementData.DriverRotation; ; } playerManager.SendPacketToOtherPlayers(packet, player); diff --git a/NitroxServer/Communication/Packets/Processors/VehicleUndockingProcessor.cs b/NitroxServer/Communication/Packets/Processors/VehicleUndockingProcessor.cs index 6b2e4cce9e..1d558abfc3 100644 --- a/NitroxServer/Communication/Packets/Processors/VehicleUndockingProcessor.cs +++ b/NitroxServer/Communication/Packets/Processors/VehicleUndockingProcessor.cs @@ -36,6 +36,7 @@ public override void Process(VehicleUndocking packet, Player player) return; } + vehicle.Value.ParentId = null; parent.Value.ChildEntities.Remove(vehicle.Value); playerManager.SendPacketToOtherPlayers(packet, player); From c16442b2b46e82aebdebcee30f04915ef712af12 Mon Sep 17 00:00:00 2001 From: killzoms Date: Tue, 15 Aug 2023 12:57:04 -0400 Subject: [PATCH 02/11] fix null ref --- NitroxClient/GameLogic/RemotePlayer.cs | 6 +++--- NitroxClient/MonoBehaviours/MovementController.cs | 5 +++-- NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/NitroxClient/GameLogic/RemotePlayer.cs b/NitroxClient/GameLogic/RemotePlayer.cs index 4c0d52cbb3..f0d266a59e 100644 --- a/NitroxClient/GameLogic/RemotePlayer.cs +++ b/NitroxClient/GameLogic/RemotePlayer.cs @@ -111,7 +111,7 @@ public void UpdatePosition(Vector3 position, Quaternion bodyRotation, Quaternion SetVehicle(null); SetPilotingChair(null); - MovementController.enabled = true; + MovementController.IsMoving = true; MovementController.TargetPosition = position; MovementController.TargetRotation = bodyRotation; @@ -169,7 +169,7 @@ public void SetPilotingChair(PilotingChair newPilotingChair) RigidBody.isKinematic = AnimationController["cyclops_steering"] = isInPilotingChair; RigidBody.interpolation = isInPilotingChair ? RigidbodyInterpolation.None : RigidbodyInterpolation.Interpolate; - MovementController.enabled = !isInPilotingChair; + MovementController.IsMoving = !isInPilotingChair; } } @@ -246,7 +246,7 @@ public void SetVehicle(Vehicle newVehicle) RigidBody.interpolation = Vehicle ? RigidbodyInterpolation.None : RigidbodyInterpolation.Interpolate; RigidBody.isKinematic = Vehicle; - MovementController.enabled = !Vehicle; + MovementController.IsMoving = !Vehicle; AnimationController["in_seamoth"] = newVehicle is SeaMoth; AnimationController["in_exosuit"] = AnimationController["using_mechsuit"] = newVehicle is Exosuit; diff --git a/NitroxClient/MonoBehaviours/MovementController.cs b/NitroxClient/MonoBehaviours/MovementController.cs index 3b26d2adaf..27c310c928 100644 --- a/NitroxClient/MonoBehaviours/MovementController.cs +++ b/NitroxClient/MonoBehaviours/MovementController.cs @@ -15,6 +15,7 @@ public class MovementController : MonoBehaviour public Vector3 TargetPosition { get; set; } public Quaternion TargetRotation { get; set; } public Transform TargetTransform { get; set; } + public bool IsMoving { get; set; } public event Action BeforeUpdate = () => {}; public event Action BeforeFixedUpdate = () => {}; @@ -34,7 +35,7 @@ private void Update() BeforeUpdate(); if (!rigidbody) { - transform.position = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, Scalar * Time.fixedDeltaTime); + transform.position = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, Scalar * Time.deltaTime); transform.rotation = Quaternion.Lerp(transform.rotation, TargetRotation, Scalar * Time.deltaTime); } AfterUpdate(); @@ -60,7 +61,7 @@ private void FixedUpdate() Quaternion delta = TargetRotation * transform.rotation.GetInverse(); delta.ToAngleAxis(out float angle, out Vector3 axis); - rigidbody.angularVelocity = Mathf.Deg2Rad * angle / timing * axis; + rigidbody.angularVelocity = .9f * Mathf.Deg2Rad * angle / timing * axis; } } AfterFixedUpdate(); diff --git a/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs b/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs index ee4095aa52..4517d1eac3 100644 --- a/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs +++ b/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs @@ -56,13 +56,13 @@ internal virtual void SetArmPositions(Vector3 leftArmPosition, Vector3 rightArmP internal virtual void Enter() { - movementController.enabled = true; + movementController.IsMoving = true; enabled = true; } public virtual void Exit() { - movementController.enabled = false; + movementController.IsMoving = false; enabled = false; } From 2da9191544eecdb90af7dcfd8458ae631246fdbe Mon Sep 17 00:00:00 2001 From: killzoms Date: Tue, 15 Aug 2023 12:57:27 -0400 Subject: [PATCH 03/11] Spawning Overhaul --- .../PlaceholderGroupWorldEntitySpawner.cs | 69 +++++++---- .../Entities/SubnauticaUwePrefabFactory.cs | 109 +++++++++++++++++- .../GameLogic/Entities/NitroxEntitySlot.cs | 29 +++++ .../Entities/PlaceholderGroupWorldEntity.cs | 32 +---- .../Entities/PrefabPlaceholderEntity.cs | 7 +- .../GameLogic/Entities/UwePrefab.cs | 11 +- .../GameLogic/Entities/UwePrefabFactory.cs | 4 +- .../GameLogic/Entities/WorldEntity.cs | 1 - .../DataStructures/GameLogic/Entity.cs | 13 ++- .../Helper/DeterministicGenerator.cs | 4 +- .../Spawning/CrashFishBootstrapper.cs | 2 +- .../Entities/Spawning/ReefbackBootstrapper.cs | 2 +- .../SubnauticaEntitySpawnPointFactory.cs | 7 +- .../Parsers/PrefabPlaceholderGroupsParser.cs | 28 ++--- NitroxServer/GameLogic/Entities/EntityData.cs | 5 +- .../GameLogic/Entities/NitroxEntitySlot.cs | 15 --- .../Entities/Spawning/BatchEntitySpawner.cs | 96 ++++----------- .../Entities/Spawning/EntitySpawnPoint.cs | 17 ++- .../Entities/Spawning/IEntityBootstrapper.cs | 2 +- NitroxServer/GameLogic/StoryManager.cs | 1 - .../Resources/PrefabPlaceholderAsset.cs | 5 +- 21 files changed, 273 insertions(+), 186 deletions(-) create mode 100644 NitroxModel/DataStructures/GameLogic/Entities/NitroxEntitySlot.cs rename {NitroxServer => NitroxModel}/Helper/DeterministicGenerator.cs (94%) delete mode 100644 NitroxServer/GameLogic/Entities/NitroxEntitySlot.cs diff --git a/NitroxClient/GameLogic/Spawning/WorldEntities/PlaceholderGroupWorldEntitySpawner.cs b/NitroxClient/GameLogic/Spawning/WorldEntities/PlaceholderGroupWorldEntitySpawner.cs index 1e0b04226e..12a67004ca 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntities/PlaceholderGroupWorldEntitySpawner.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntities/PlaceholderGroupWorldEntitySpawner.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using System.Linq; using NitroxClient.GameLogic.Spawning.Metadata; @@ -44,33 +45,42 @@ public IEnumerator SpawnAsync(WorldEntity entity, Optional parent, E // Spawning PrefabPlaceholders as siblings to the group PrefabPlaceholdersGroup prefabPlaceholderGroup = prefabPlaceholderGroupGameObject.Value.GetComponent(); - foreach (PrefabChildEntity placeholderSlot in placeholderGroupEntity.ChildEntities.Cast()) + foreach (Entity placeholderEntity in placeholderGroupEntity.ChildEntities) { - if (placeholderSlot.ChildEntities.Count == 0) //Entity was a slot not spawned, picked up, or removed + TaskResult> childResult = new(); + Entity slotEntity; + if (placeholderEntity is PrefabChildEntity) { - continue; - } + PrefabChildEntity placeholderSlot = (PrefabChildEntity)placeholderEntity; + if (placeholderSlot.ChildEntities.Count == 0) //Entity was a slot not spawned, picked up, or removed + { + continue; + } - PrefabPlaceholder prefabPlaceholder = prefabPlaceholderGroup.prefabPlaceholders[placeholderSlot.ComponentIndex]; + PrefabPlaceholder prefabPlaceholder = prefabPlaceholderGroup.prefabPlaceholders[placeholderSlot.ComponentIndex]; - TaskResult> childResult = new(); + slotEntity = placeholderSlot.ChildEntities[0]; - Entity slotEntity = placeholderSlot.ChildEntities[0]; + switch (slotEntity) + { + case PrefabPlaceholderEntity placeholder: + yield return SpawnChildPlaceholder(prefabPlaceholder, placeholder, childResult); + break; + case WorldEntity worldEntity: + yield return SpawnWorldEntityChild(worldEntity, cellRoot, Optional.Of(prefabPlaceholder.transform.parent.gameObject), childResult); + break; + default: + Log.Debug(placeholderSlot.ChildEntities.Count > 0 ? $"Unhandled child type {placeholderSlot.ChildEntities[0]}" : "Child was null"); + break; + } - switch (slotEntity) + yield return SpawnChildren(slotEntity, childResult.value, cellRoot); + } + else { - case PrefabPlaceholderEntity placeholder: - yield return SpawnChildPlaceholder(prefabPlaceholder, placeholder, childResult); - break; - case WorldEntity worldEntity: - yield return SpawnWorldEntityChild(worldEntity, cellRoot, Optional.Of(prefabPlaceholder.transform.parent.gameObject), childResult); - break; - default: - Log.Debug(placeholderSlot.ChildEntities.Count > 0 ? $"Unhandled child type {placeholderSlot.ChildEntities[0]}" : "Child was null"); - break; + yield return SpawnChildren(placeholderEntity, prefabPlaceholderGroupGameObject, cellRoot); } - yield return SpawnChildren(slotEntity, childResult.value, cellRoot); } } @@ -85,9 +95,10 @@ private IEnumerator SpawnChildPlaceholder(PrefabPlaceholder prefabPlaceholder, P } GameObject gameObject = goResult.value; - gameObject.transform.SetParent(prefabPlaceholder.transform.parent, false); gameObject.transform.localPosition = prefabPlaceholder.transform.localPosition; gameObject.transform.localRotation = prefabPlaceholder.transform.localRotation; + gameObject.transform.SetParent(prefabPlaceholder.transform.parent, false); + gameObject.transform.localScale = prefabPlaceholder.transform.localScale; NitroxEntity.SetNewId(gameObject, entity.Id); @@ -104,10 +115,22 @@ private IEnumerator SpawnWorldEntityChild(WorldEntity worldEntity, EntityCell ce if (worldEntityResult.value.HasValue) { - EntityMetadataProcessor.ApplyMetadata(worldEntityResult.value.Value, worldEntity.Metadata); - - worldEntityResult.value.Value.transform.localPosition = worldEntity.Transform.LocalPosition.ToUnity(); - worldEntityResult.value.Value.transform.localRotation = worldEntity.Transform.LocalRotation.ToUnity(); + GameObject spawnedEntity = worldEntityResult.value.Value; + EntityMetadataProcessor.ApplyMetadata(spawnedEntity, worldEntity.Metadata); + + spawnedEntity.transform.localPosition = worldEntity.Transform.LocalPosition.ToUnity(); + spawnedEntity.transform.localRotation = worldEntity.Transform.LocalRotation.ToUnity(); + spawnedEntity.transform.SetParent(parent.Value.transform, false); + spawnedEntity.transform.localScale = worldEntity.Transform.LocalScale.ToUnity(); + + LargeWorldEntity component = spawnedEntity.GetComponent(); + component.cellLevel = (LargeWorldEntity.CellLevel)worldEntity.Level; + bool active = false; + if (LargeWorldStreamer.main != null) + { + active = LargeWorldStreamer.main.cellManager.RegisterEntity(component); + } + spawnedEntity.SetActive(active); } } diff --git a/NitroxModel-Subnautica/DataStructures/GameLogic/Entities/SubnauticaUwePrefabFactory.cs b/NitroxModel-Subnautica/DataStructures/GameLogic/Entities/SubnauticaUwePrefabFactory.cs index 05d2a6cc31..a3789e26a4 100644 --- a/NitroxModel-Subnautica/DataStructures/GameLogic/Entities/SubnauticaUwePrefabFactory.cs +++ b/NitroxModel-Subnautica/DataStructures/GameLogic/Entities/SubnauticaUwePrefabFactory.cs @@ -1,9 +1,14 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Threading; +using Discord; using LitJson; +using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.GameLogic.Entities; +using NitroxModel.DataStructures.Util; +using NitroxModel.Helper; +using NitroxModel.Logger; using static LootDistributionData; namespace NitroxModel_Subnautica.DataStructures.GameLogic.Entities @@ -41,6 +46,108 @@ public override List GetPossiblePrefabs(string biome) return prefabs; } + public override UwePrefab GetPrefabForSlot(NitroxEntitySlot entitySlot, bool filterKnown, DeterministicGenerator deterministicGenerator, UweWorldEntityFactory worldEntityFactory) + { + UwePrefab result = null; + + BiomeType biomeType = (BiomeType)Enum.Parse(typeof(BiomeType), entitySlot.BiomeType); + + if (lootDistributionData.GetBiomeLoot(biomeType, out DstData data)) + { + Dictionary srcDistribution = lootDistributionData.srcDistribution; + float num = 0; + float num2 = 0; + List prefabs = new List(); + + for (int i = 0; i < data.prefabs.Count; i++) + { + LootDistributionData.PrefabData prefab = data.prefabs[i]; + if (string.Equals(prefab.classId, "None") || !srcDistribution.TryGetValue(prefab.classId, out _)) + { + continue; + } + Optional worldEntity = worldEntityFactory.From(prefab.classId); + if (!worldEntity.HasValue) + { + Log.Error($"Missing world entity info for prefab '{prefab.classId}'"); + } + else + { + UweWorldEntity info = worldEntity.Value; + if (!entitySlot.IsTypeAllowed(info.SlotType)) + { + continue; + } + + float adjustedProbability = prefab.probability / entitySlot.Density; + if (adjustedProbability <= 0f) + { + continue; + } + + NitroxTechType techType = info.TechType; + bool isFragment = false; // till we load PDA Data assume everything is not a fragment + if (filterKnown) + { + // Load PDA Data to filter + /* + * if (isFragment && PDAData.ContainsCompleteEntry(techType)) + * { + * num2 += adjustedProbability; + * continue; + * } + */ + } + + prefabs.Add(new UwePrefab(prefab.classId, adjustedProbability, prefab.count, isFragment)); + if (isFragment) + { + num += adjustedProbability; + } + } + } + + bool flag2 = num2 > 0f && num > 0f; + float num4 = (flag2 ? ((num2 + num) / num) : 1f); + float num5 = 0f; + + for (int i = 0; i < prefabs.Count; i++) + { + UwePrefab prefab = prefabs[i]; + if (flag2 && prefab.IsFragment) + { + float newProbability = prefab.Probability * num4; + prefabs[i] = new UwePrefab(prefab.ClassId, newProbability, prefab.Count, prefab.IsFragment); + } + num5 += prefabs[i].Probability; + } + + UwePrefab spawnedPrefab = null; + if (num5 > 0f) + { + float num6 = (float)deterministicGenerator.NextDouble(); + if (num5 > 1f) + { + num6 *= num5; + } + float num7 = 0f; + for (int k = 0; k < prefabs.Count; k++) + { + UwePrefab possiblePrefab = prefabs[k]; + num7 += possiblePrefab.Probability; + if (num7 >= num6) + { + spawnedPrefab = possiblePrefab; + break; + } + } + } + + result = spawnedPrefab; + } + return result; + } + private LootDistributionData GetLootDistributionData(string lootDistributionJson) { ForceCultureOverride(); diff --git a/NitroxModel/DataStructures/GameLogic/Entities/NitroxEntitySlot.cs b/NitroxModel/DataStructures/GameLogic/Entities/NitroxEntitySlot.cs new file mode 100644 index 0000000000..33efda6181 --- /dev/null +++ b/NitroxModel/DataStructures/GameLogic/Entities/NitroxEntitySlot.cs @@ -0,0 +1,29 @@ +using System.Linq; + +namespace NitroxModel.DataStructures.GameLogic.Entities +{ + public class NitroxEntitySlot + { + public string[] AllowedTypes; + public string BiomeType; + public float Density; + + public NitroxEntitySlot(string biomeType, string[] allowedTypes, float density) + { + BiomeType = biomeType; + AllowedTypes = allowedTypes; + Density = density; + } + + public bool IsTypeAllowed(string type) + { + return AllowedTypes.Contains(type); + } + + public struct Filler + { + public string ClassId; + public int Count; + } + } +} diff --git a/NitroxModel/DataStructures/GameLogic/Entities/PlaceholderGroupWorldEntity.cs b/NitroxModel/DataStructures/GameLogic/Entities/PlaceholderGroupWorldEntity.cs index f74d22b4a0..cbcda861ae 100644 --- a/NitroxModel/DataStructures/GameLogic/Entities/PlaceholderGroupWorldEntity.cs +++ b/NitroxModel/DataStructures/GameLogic/Entities/PlaceholderGroupWorldEntity.cs @@ -17,36 +17,12 @@ protected PlaceholderGroupWorldEntity() // Constructor for serialization. Has to be "protected" for json serialization. } - public PlaceholderGroupWorldEntity(WorldEntity worldEntity, List prefabPlaceholders) - { - Id = worldEntity.Id; - TechType = worldEntity.TechType; - Metadata = worldEntity.Metadata; - ParentId = worldEntity.ParentId; - Transform = worldEntity.Transform; - Level = worldEntity.Level; - ClassId = worldEntity.ClassId; - SpawnedByServer = worldEntity.SpawnedByServer; - WaterParkId = worldEntity.WaterParkId; - ExistsInGlobalRoot = worldEntity.ExistsInGlobalRoot; - ChildEntities = prefabPlaceholders; - } + public PlaceholderGroupWorldEntity(WorldEntity worldEntity, List prefabPlaceholders) : base(worldEntity.Transform, worldEntity.Level, worldEntity.ClassId, worldEntity.SpawnedByServer, worldEntity.WaterParkId, worldEntity.ExistsInGlobalRoot, worldEntity.Id, worldEntity.TechType, worldEntity.Metadata, worldEntity.ParentId, prefabPlaceholders) + {} /// Used for deserialization - public PlaceholderGroupWorldEntity(NitroxTransform transform, int level, string classId, bool spawnedByServer, NitroxId waterParkId, bool existsInGlobalRoot, NitroxId id, NitroxTechType techType, EntityMetadata metadata, NitroxId parentId, List childEntities) - { - Transform = transform; - Level = level; - ClassId = classId; - SpawnedByServer = spawnedByServer; - WaterParkId = waterParkId; - ExistsInGlobalRoot = existsInGlobalRoot; - Id = id; - TechType = techType; - Metadata = metadata; - ParentId = parentId; - ChildEntities = childEntities; - } + public PlaceholderGroupWorldEntity(NitroxTransform transform, int level, string classId, bool spawnedByServer, NitroxId waterParkId, bool existsInGlobalRoot, NitroxId id, NitroxTechType techType, EntityMetadata metadata, NitroxId parentId, List childEntities) : base(transform, level, classId, spawnedByServer, waterParkId, existsInGlobalRoot, id, techType, metadata, parentId, childEntities) + {} public override string ToString() { diff --git a/NitroxModel/DataStructures/GameLogic/Entities/PrefabPlaceholderEntity.cs b/NitroxModel/DataStructures/GameLogic/Entities/PrefabPlaceholderEntity.cs index 92291e75f5..501b394e51 100644 --- a/NitroxModel/DataStructures/GameLogic/Entities/PrefabPlaceholderEntity.cs +++ b/NitroxModel/DataStructures/GameLogic/Entities/PrefabPlaceholderEntity.cs @@ -19,15 +19,12 @@ protected PrefabPlaceholderEntity() // Constructor for serialization. Has to be "protected" for json serialization. } - public PrefabPlaceholderEntity(NitroxId id, NitroxTechType techType, NitroxId parentId) + public PrefabPlaceholderEntity(NitroxId id, NitroxTechType techType, NitroxId parentId) : base(id, techType, null, parentId) { - Id = id; - TechType = techType; - ParentId = parentId; ChildEntities = new List(); } - public PrefabPlaceholderEntity(NitroxId id, string classId, NitroxTechType techType, NitroxId parentId, List childEntities) + public PrefabPlaceholderEntity(NitroxId id, string classId, NitroxTechType techType, NitroxId parentId, List childEntities) : base(id, techType, null, parentId, childEntities) { Id = id; ClassId = classId; diff --git a/NitroxModel/DataStructures/GameLogic/Entities/UwePrefab.cs b/NitroxModel/DataStructures/GameLogic/Entities/UwePrefab.cs index 2936c39d51..66f9a43fb9 100644 --- a/NitroxModel/DataStructures/GameLogic/Entities/UwePrefab.cs +++ b/NitroxModel/DataStructures/GameLogic/Entities/UwePrefab.cs @@ -1,16 +1,25 @@ -namespace NitroxModel.DataStructures.GameLogic.Entities +namespace NitroxModel.DataStructures.GameLogic.Entities { public class UwePrefab { public string ClassId { get; } public float Probability { get; } public int Count { get; } + public bool IsFragment { get; } public UwePrefab(string classId, float probability, int count) { ClassId = classId; Probability = probability; Count = count; + IsFragment = true; + } + public UwePrefab(string classId, float probability, int count, bool isFragment) + { + ClassId = classId; + Probability = probability; + Count = count; + IsFragment = isFragment; } } } diff --git a/NitroxModel/DataStructures/GameLogic/Entities/UwePrefabFactory.cs b/NitroxModel/DataStructures/GameLogic/Entities/UwePrefabFactory.cs index 4b6f5cfe30..742072f302 100644 --- a/NitroxModel/DataStructures/GameLogic/Entities/UwePrefabFactory.cs +++ b/NitroxModel/DataStructures/GameLogic/Entities/UwePrefabFactory.cs @@ -1,9 +1,11 @@ -using System.Collections.Generic; +using NitroxModel.Helper; +using System.Collections.Generic; namespace NitroxModel.DataStructures.GameLogic.Entities { public abstract class UwePrefabFactory { public abstract List GetPossiblePrefabs(string biomeType); + public abstract UwePrefab GetPrefabForSlot(NitroxEntitySlot entitySlot, bool filterKnown, DeterministicGenerator deterministicGenerator, UweWorldEntityFactory worldEntityFactory); } } diff --git a/NitroxModel/DataStructures/GameLogic/Entities/WorldEntity.cs b/NitroxModel/DataStructures/GameLogic/Entities/WorldEntity.cs index c0ac903bf6..ba89c7503b 100644 --- a/NitroxModel/DataStructures/GameLogic/Entities/WorldEntity.cs +++ b/NitroxModel/DataStructures/GameLogic/Entities/WorldEntity.cs @@ -71,7 +71,6 @@ public WorldEntity(NitroxVector3 localPosition, NitroxQuaternion localRotation, if (parentEntity != null) { ParentId = parentEntity.Id; - if (parentEntity is WorldEntity weParent) { Transform.SetParent(weParent.Transform, false); diff --git a/NitroxModel/DataStructures/GameLogic/Entity.cs b/NitroxModel/DataStructures/GameLogic/Entity.cs index 56e8772d79..19e3e9e477 100644 --- a/NitroxModel/DataStructures/GameLogic/Entity.cs +++ b/NitroxModel/DataStructures/GameLogic/Entity.cs @@ -32,7 +32,6 @@ public abstract class Entity [DataMember(Order = 4)] public NitroxId ParentId { get; set; } - [DataMember(Order = 5)] public List ChildEntities { get; set; } = new List(); [IgnoreConstructor] @@ -41,6 +40,18 @@ protected Entity() // Constructor for serialization. Has to be "protected" for json serialization. } + public Entity(NitroxId id, NitroxTechType techType, EntityMetadata metadata, NitroxId parentId) + { + Id = id; + TechType = techType; + Metadata = metadata; + ParentId = parentId; + } + public Entity(NitroxId id, NitroxTechType techType, EntityMetadata metadata, NitroxId parentId, List childEntities) : this(id, techType, metadata, parentId) + { + ChildEntities = childEntities; + } + public override string ToString() { return $"[Entity id: {Id} techType: {TechType} Metadata: {Metadata} ParentId: {ParentId} ChildEntities: {string.Join(",\n ", ChildEntities)}]"; diff --git a/NitroxServer/Helper/DeterministicGenerator.cs b/NitroxModel/Helper/DeterministicGenerator.cs similarity index 94% rename from NitroxServer/Helper/DeterministicGenerator.cs rename to NitroxModel/Helper/DeterministicGenerator.cs index efa20bdb1e..39eebb5288 100644 --- a/NitroxServer/Helper/DeterministicGenerator.cs +++ b/NitroxModel/Helper/DeterministicGenerator.cs @@ -1,7 +1,7 @@ -using System; +using System; using NitroxModel.DataStructures; -namespace NitroxServer.Helper +namespace NitroxModel.Helper { public class DeterministicGenerator { diff --git a/NitroxServer-Subnautica/GameLogic/Entities/Spawning/CrashFishBootstrapper.cs b/NitroxServer-Subnautica/GameLogic/Entities/Spawning/CrashFishBootstrapper.cs index 630510be5c..3c816066b9 100644 --- a/NitroxServer-Subnautica/GameLogic/Entities/Spawning/CrashFishBootstrapper.cs +++ b/NitroxServer-Subnautica/GameLogic/Entities/Spawning/CrashFishBootstrapper.cs @@ -3,7 +3,7 @@ using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel_Subnautica.DataStructures; using NitroxServer.GameLogic.Entities.Spawning; -using NitroxServer.Helper; +using NitroxModel.Helper; using NitroxModel.DataStructures.GameLogic; namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning.EntityBootstrappers; diff --git a/NitroxServer-Subnautica/GameLogic/Entities/Spawning/ReefbackBootstrapper.cs b/NitroxServer-Subnautica/GameLogic/Entities/Spawning/ReefbackBootstrapper.cs index 3eb7d56b2f..0529e53b59 100644 --- a/NitroxServer-Subnautica/GameLogic/Entities/Spawning/ReefbackBootstrapper.cs +++ b/NitroxServer-Subnautica/GameLogic/Entities/Spawning/ReefbackBootstrapper.cs @@ -3,7 +3,7 @@ using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel_Subnautica.DataStructures; using NitroxServer.GameLogic.Entities.Spawning; -using NitroxServer.Helper; +using NitroxModel.Helper; using static NitroxServer_Subnautica.GameLogic.Entities.Spawning.EntityBootstrappers.ReefbackSpawnData; namespace NitroxServer_Subnautica.GameLogic.Entities.Spawning.EntityBootstrappers diff --git a/NitroxServer-Subnautica/GameLogic/Entities/Spawning/SubnauticaEntitySpawnPointFactory.cs b/NitroxServer-Subnautica/GameLogic/Entities/Spawning/SubnauticaEntitySpawnPointFactory.cs index fc53fd299a..edcd4ef7ea 100644 --- a/NitroxServer-Subnautica/GameLogic/Entities/Spawning/SubnauticaEntitySpawnPointFactory.cs +++ b/NitroxServer-Subnautica/GameLogic/Entities/Spawning/SubnauticaEntitySpawnPointFactory.cs @@ -1,6 +1,7 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel.DataStructures.Unity; using NitroxModel_Subnautica.DataStructures; using NitroxServer.GameLogic.Entities.Spawning; @@ -26,9 +27,7 @@ public override List From(AbsoluteEntityCell absoluteEntityCel EntitySpawnPoint entitySpawnPoint = new EntitySpawnPoint(absoluteEntityCell, entitySlotData.localPosition.ToDto(), entitySlotData.localRotation.ToDto(), - stringSlotTypes, - entitySlotData.density, - entitySlotData.biomeType.ToString()); + new NitroxEntitySlot(entitySlotData.biomeType.ToString(), stringSlotTypes.ToArray(), entitySlotData.density)); HandleParenting(spawnPoints, entitySpawnPoint, gameObject); diff --git a/NitroxServer-Subnautica/Resources/Parsers/PrefabPlaceholderGroupsParser.cs b/NitroxServer-Subnautica/Resources/Parsers/PrefabPlaceholderGroupsParser.cs index b37710c1cf..367c895403 100644 --- a/NitroxServer-Subnautica/Resources/Parsers/PrefabPlaceholderGroupsParser.cs +++ b/NitroxServer-Subnautica/Resources/Parsers/PrefabPlaceholderGroupsParser.cs @@ -10,8 +10,9 @@ using AssetsTools.NET.Extra; using NitroxModel.DataStructures.GameLogic; using NitroxServer_Subnautica.Resources.Parsers.Helper; -using NitroxServer.GameLogic.Entities; using NitroxServer.Resources; +using NitroxModel.DataStructures.GameLogic.Entities; +using NitroxModel_Subnautica.DataStructures; namespace NitroxServer_Subnautica.Resources.Parsers; @@ -218,8 +219,14 @@ private PrefabPlaceholdersGroupAsset GetAndCachePrefabPlaceholdersGroupGroup(Ass for (int index = 0; index < prefabPlaceholdersOnGroup.Count; index++) { AssetTypeValueField prefabPlaceholderPtr = prefabPlaceholdersOnGroup[index]; - AssetTypeValueField prefabPlaceholder = amInst.GetExtAsset(assetFileInst, prefabPlaceholderPtr).baseField; - prefabPlaceholders[index] = GetAndCachePrefabPlaceholderAsset(amInst, prefabPlaceholder["prefabClassId"].AsString); + AssetExternal prefabPlaceholder = amInst.GetExtAsset(assetFileInst, prefabPlaceholderPtr); + PrefabPlaceholderAsset prefabPlaceholderAsset = GetPrefabPlaceholderAsset(amInst, prefabPlaceholder.baseField["prefabClassId"].AsString); + + AssetTypeValueField transformComponent = amInst.GetTransformComponent(assetFileInst, amInst.GetExtAsset(assetFileInst, prefabPlaceholder.baseField["m_GameObject"]).baseField); + prefabPlaceholderAsset.LocalPosition = transformComponent["m_LocalPosition"].AsNitroxVector3(); + prefabPlaceholderAsset.LocalRotation = transformComponent["m_LocalRotation"].AsNitroxQuaternion(); + + prefabPlaceholders[index] = prefabPlaceholderAsset; } NitroxTechType nitroxTechType = null; @@ -238,16 +245,11 @@ private PrefabPlaceholdersGroupAsset GetAndCachePrefabPlaceholdersGroupGroup(Ass return prefabPlaceholdersGroup; } - private PrefabPlaceholderAsset GetAndCachePrefabPlaceholderAsset(AssetsBundleManager amInst, string classId) + private PrefabPlaceholderAsset GetPrefabPlaceholderAsset(AssetsBundleManager amInst, string classId) { - if (!string.IsNullOrEmpty(classId) && prefabPlaceholderByClassId.TryGetValue(classId, out PrefabPlaceholderAsset cachedPrefabPlaceholder)) - { - return cachedPrefabPlaceholder; - } - if (string.IsNullOrEmpty(classId) || !addressableCatalog.TryGetValue(classId, out string[] assetPaths)) { - Log.Error($"Could get PrefabPlaceholder with classId: {classId}"); + Log.Error($"Could not get PrefabPlaceholder with classId: {classId}"); return null; } @@ -268,12 +270,10 @@ private PrefabPlaceholderAsset GetAndCachePrefabPlaceholderAsset(AssetsBundleMan allowedTypes.Add(((EntitySlot.Type)allowedType.AsInt).ToString()); } - nitroxEntitySlot = new NitroxEntitySlot(biomeType, allowedTypes.ToArray()); + nitroxEntitySlot = new NitroxEntitySlot(biomeType, allowedTypes.ToArray(), 1f); } - PrefabPlaceholderAsset prefabPlaceholderAsset = new(classId, nitroxEntitySlot); - prefabPlaceholderByClassId[classId] = prefabPlaceholderAsset; - return prefabPlaceholderAsset; + return new(classId, nitroxEntitySlot); } public void Dispose() diff --git a/NitroxServer/GameLogic/Entities/EntityData.cs b/NitroxServer/GameLogic/Entities/EntityData.cs index bca55f2d0f..1e3dfd3f01 100644 --- a/NitroxServer/GameLogic/Entities/EntityData.cs +++ b/NitroxServer/GameLogic/Entities/EntityData.cs @@ -25,7 +25,10 @@ private void ProtoAfterDeserialization() // TODO: Rework system to no longer persist children entities because they are duplicates. foreach (Entity entity in Entities) { - entity.ChildEntities.Clear(); + if (entity.ChildEntities == null) + { + entity.ChildEntities = new List(); + } } foreach (Entity entity in Entities) diff --git a/NitroxServer/GameLogic/Entities/NitroxEntitySlot.cs b/NitroxServer/GameLogic/Entities/NitroxEntitySlot.cs deleted file mode 100644 index 5464f96532..0000000000 --- a/NitroxServer/GameLogic/Entities/NitroxEntitySlot.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace NitroxServer.GameLogic.Entities -{ - public class NitroxEntitySlot - { - public string[] AllowedTypes; - - public string BiomeType; - - public NitroxEntitySlot(string biomeType, string[] allowedTypes) - { - BiomeType = biomeType; - AllowedTypes = allowedTypes; - } - } -} diff --git a/NitroxServer/GameLogic/Entities/Spawning/BatchEntitySpawner.cs b/NitroxServer/GameLogic/Entities/Spawning/BatchEntitySpawner.cs index 273ef63d28..c4747d2abe 100644 --- a/NitroxServer/GameLogic/Entities/Spawning/BatchEntitySpawner.cs +++ b/NitroxServer/GameLogic/Entities/Spawning/BatchEntitySpawner.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; +using System.Xml.Linq; using NitroxModel.DataStructures; using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel.DataStructures.Unity; using NitroxModel.DataStructures.Util; -using NitroxServer.Helper; +using NitroxModel.Helper; using NitroxServer.Resources; using NitroxServer.Serialization; @@ -119,38 +121,9 @@ public List LoadUnspawnedEntities(NitroxInt3 batchId, bool fullCacheCrea return entities; } - private IEnumerable SpawnEntitiesUsingRandomDistribution(EntitySpawnPoint entitySpawnPoint, List prefabs, DeterministicGenerator deterministicBatchGenerator, Entity parentEntity = null) + private IEnumerable SpawnEntitiesUsingRandomDistribution(EntitySpawnPoint entitySpawnPoint, DeterministicGenerator deterministicBatchGenerator, Entity parentEntity = null) { - List allowedPrefabs = FilterAllowedPrefabs(prefabs, entitySpawnPoint); - - float rollingProbabilityDensity = allowedPrefabs.Sum(prefab => prefab.Probability / entitySpawnPoint.Density); - - if (rollingProbabilityDensity <= 0) - { - yield break; - } - - float randomNumber = (float)deterministicBatchGenerator.NextDouble(); - if (rollingProbabilityDensity > 1f) - { - randomNumber *= rollingProbabilityDensity; - } - - float rollingProbability = 0; - - UwePrefab selectedPrefab = allowedPrefabs.FirstOrDefault(prefab => - { - if (Math.Abs(prefab.Probability) < 0.0001) - { - return false; - } - - float probabilityDensity = prefab.Probability / entitySpawnPoint.Density; - - rollingProbability += probabilityDensity; - - return rollingProbability >= randomNumber; - }); + UwePrefab selectedPrefab = prefabFactory.GetPrefabForSlot(entitySpawnPoint.EntitySlot, true, deterministicBatchGenerator, worldEntityFactory); if (selectedPrefab == null) { @@ -180,26 +153,6 @@ private IEnumerable SpawnEntitiesUsingRandomDistribution(EntitySpawnPoin } } - private List FilterAllowedPrefabs(List prefabs, EntitySpawnPoint entitySpawnPoint) - { - List allowedPrefabs = new List(); - - foreach (UwePrefab prefab in prefabs) - { - if (prefab.ClassId != "None") - { - Optional uweWorldEntity = worldEntityFactory.From(prefab.ClassId); - - if (uweWorldEntity.HasValue && entitySpawnPoint.AllowedTypes.Contains(uweWorldEntity.Value.SlotType)) - { - allowedPrefabs.Add(prefab); - } - } - } - - return allowedPrefabs; - } - private IEnumerable SpawnEntitiesStaticly(EntitySpawnPoint entitySpawnPoint, DeterministicGenerator deterministicBatchGenerator, WorldEntity parentEntity = null) { Optional uweWorldEntity = worldEntityFactory.From(entitySpawnPoint.ClassId); @@ -223,6 +176,7 @@ private IEnumerable SpawnEntitiesStaticly(EntitySpawnPoint entitySpawnPo private IEnumerable CreateEntityWithChildren(EntitySpawnPoint entitySpawnPoint, NitroxVector3 scale, NitroxTechType techType, int cellLevel, string classId, DeterministicGenerator deterministicBatchGenerator, Entity parentEntity = null) { WorldEntity spawnedEntity; + NitroxId newId = deterministicBatchGenerator.NextId(); if (classId == CellRootEntity.CLASS_ID) { @@ -233,7 +187,7 @@ private IEnumerable CreateEntityWithChildren(EntitySpawnPoint entitySpaw cellLevel, classId, true, - deterministicBatchGenerator.NextId(), + newId, false, null); } @@ -246,7 +200,7 @@ private IEnumerable CreateEntityWithChildren(EntitySpawnPoint entitySpaw cellLevel, classId, true, - deterministicBatchGenerator.NextId(), + newId, parentEntity, false, null); @@ -254,7 +208,7 @@ private IEnumerable CreateEntityWithChildren(EntitySpawnPoint entitySpaw if (!TryCreatePrefabPlaceholdersGroupWithChildren(ref spawnedEntity, classId, deterministicBatchGenerator)) { - spawnedEntity.ChildEntities = SpawnEntities(entitySpawnPoint.Children, deterministicBatchGenerator, spawnedEntity); + SpawnEntities(entitySpawnPoint.Children, deterministicBatchGenerator, spawnedEntity); } if (customBootstrappersByTechType.TryGetValue(techType, out IEntityBootstrapper bootstrapper)) @@ -262,6 +216,11 @@ private IEnumerable CreateEntityWithChildren(EntitySpawnPoint entitySpaw bootstrapper.Prepare(spawnedEntity, deterministicBatchGenerator); } + if (parentEntity != null) + { + parentEntity.ChildEntities.Add(spawnedEntity); + } + yield return spawnedEntity; if (parentEntity == null) // Ensures children are only returned at the top level @@ -296,19 +255,14 @@ private List SpawnEntities(List entitySpawnPoints, Det List entities = new List(); foreach (EntitySpawnPoint esp in entitySpawnPoints) { - if (esp.Density > 0) - { - List prefabs = prefabFactory.GetPossiblePrefabs(esp.BiomeType); - - if (prefabs.Count > 0) + if (esp.EntitySlot != null) { - entities.AddRange(SpawnEntitiesUsingRandomDistribution(esp, prefabs, deterministicBatchGenerator, parentEntity)); + entities.AddRange(SpawnEntitiesUsingRandomDistribution(esp, deterministicBatchGenerator, parentEntity)); } else if (esp.ClassId != null) { entities.AddRange(SpawnEntitiesStaticly(esp, deterministicBatchGenerator, parentEntity)); } - } } return entities; @@ -336,37 +290,31 @@ private bool TryCreatePrefabPlaceholdersGroupWithChildren(ref WorldEntity entity PrefabChildEntity prefabChild = new(deterministicBatchGenerator.NextId(), null, NitroxTechType.None, i, null, entity.Id); placeholders.Add(prefabChild); - if (placeholder.EntitySlot == null) { - prefabChild.ChildEntities.Add(new PrefabPlaceholderEntity(deterministicBatchGenerator.NextId(), group.TechType, prefabChild.Id)); + NitroxId id = deterministicBatchGenerator.NextId(); + prefabChild.ChildEntities.Add(new PrefabPlaceholderEntity(id, group.TechType, prefabChild.Id)); } else { - Entity entitySlotNullableEntity = SpawnEntitySlotEntities(placeholder.EntitySlot, deterministicBatchGenerator, entity.AbsoluteEntityCell, prefabChild); - - if (entitySlotNullableEntity != null) - { - prefabChild.ChildEntities.Add(entitySlotNullableEntity); - } + SpawnEntitySlotEntities(placeholder.EntitySlot, deterministicBatchGenerator, entity.AbsoluteEntityCell, placeholder, prefabChild); } } return true; } - private Entity SpawnEntitySlotEntities(NitroxEntitySlot entitySlot, DeterministicGenerator deterministicBatchGenerator, AbsoluteEntityCell cell, PrefabChildEntity parentEntity) + private Entity SpawnEntitySlotEntities(NitroxEntitySlot entitySlot, DeterministicGenerator deterministicBatchGenerator, AbsoluteEntityCell cell, PrefabPlaceholderAsset placeholder, PrefabChildEntity parentEntity) { List prefabs = prefabFactory.GetPossiblePrefabs(entitySlot.BiomeType); List entities = new(); if (prefabs.Count > 0) { - EntitySpawnPoint entitySpawnPoint = new EntitySpawnPoint(cell, NitroxVector3.Zero, NitroxQuaternion.Identity, entitySlot.AllowedTypes.ToList(), 1f, entitySlot.BiomeType); - entities.AddRange(SpawnEntitiesUsingRandomDistribution(entitySpawnPoint, prefabs, deterministicBatchGenerator, parentEntity)); + EntitySpawnPoint entitySpawnPoint = new EntitySpawnPoint(cell, placeholder.LocalPosition, placeholder.LocalRotation, entitySlot); + entities.AddRange(SpawnEntitiesUsingRandomDistribution(entitySpawnPoint, deterministicBatchGenerator, parentEntity)); } return entities.FirstOrDefault(); } - } diff --git a/NitroxServer/GameLogic/Entities/Spawning/EntitySpawnPoint.cs b/NitroxServer/GameLogic/Entities/Spawning/EntitySpawnPoint.cs index d8b05bf123..3817c07607 100644 --- a/NitroxServer/GameLogic/Entities/Spawning/EntitySpawnPoint.cs +++ b/NitroxServer/GameLogic/Entities/Spawning/EntitySpawnPoint.cs @@ -1,5 +1,6 @@ -using System.Collections.Generic; +using System.Collections.Generic; using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel.DataStructures.Unity; namespace NitroxServer.GameLogic.Entities.Spawning @@ -13,34 +14,30 @@ public class EntitySpawnPoint public NitroxQuaternion LocalRotation; public AbsoluteEntityCell AbsoluteEntityCell { get; } public NitroxVector3 Scale { get; } + public NitroxEntitySlot EntitySlot { get; } public string ClassId { get; } - public string BiomeType { get; } - public float Density { get; } public bool CanSpawnCreature { get; private set; } - public List AllowedTypes { get; } public EntitySpawnPoint Parent { get; set; } - public EntitySpawnPoint(AbsoluteEntityCell absoluteEntityCell, NitroxVector3 localPosition, NitroxQuaternion localRotation, List allowedTypes, float density, string biomeType) + public EntitySpawnPoint(AbsoluteEntityCell absoluteEntityCell, NitroxVector3 localPosition, NitroxQuaternion localRotation, NitroxEntitySlot entitySlot) { AbsoluteEntityCell = absoluteEntityCell; LocalPosition = localPosition; LocalRotation = localRotation; - BiomeType = biomeType; - Density = density; - AllowedTypes = allowedTypes; + EntitySlot = entitySlot; } public EntitySpawnPoint(AbsoluteEntityCell absoluteEntityCell, NitroxVector3 localPosition, NitroxQuaternion localRotation, NitroxVector3 scale, string classId) { AbsoluteEntityCell = absoluteEntityCell; ClassId = classId; - Density = 1; LocalPosition = localPosition; Scale = scale; LocalRotation = localRotation; + EntitySlot = null; } - public override string ToString() => $"[EntitySpawnPoint - {AbsoluteEntityCell}, Local Position: {LocalPosition}, Local Rotation: {LocalRotation}, Scale: {Scale}, Class Id: {ClassId}, Biome Type: {BiomeType}, Density: {Density}, Can Spawn Creature: {CanSpawnCreature}]"; + public override string ToString() => $"[EntitySpawnPoint - {AbsoluteEntityCell}, Local Position: {LocalPosition}, Local Rotation: {LocalRotation}, Scale: {Scale}, Class Id: {ClassId}, Entity Slot: {EntitySlot}, Can Spawn Creature: {CanSpawnCreature}]"; } } diff --git a/NitroxServer/GameLogic/Entities/Spawning/IEntityBootstrapper.cs b/NitroxServer/GameLogic/Entities/Spawning/IEntityBootstrapper.cs index f85c11daa5..54a693038f 100644 --- a/NitroxServer/GameLogic/Entities/Spawning/IEntityBootstrapper.cs +++ b/NitroxServer/GameLogic/Entities/Spawning/IEntityBootstrapper.cs @@ -1,4 +1,4 @@ -using NitroxServer.Helper; +using NitroxModel.Helper; using NitroxModel.DataStructures.GameLogic.Entities; namespace NitroxServer.GameLogic.Entities.Spawning diff --git a/NitroxServer/GameLogic/StoryManager.cs b/NitroxServer/GameLogic/StoryManager.cs index c7c53feb63..c09792a361 100644 --- a/NitroxServer/GameLogic/StoryManager.cs +++ b/NitroxServer/GameLogic/StoryManager.cs @@ -1,7 +1,6 @@ using System; using NitroxModel.DataStructures.GameLogic; using NitroxModel.Packets; -using NitroxServer.Helper; using NitroxServer.GameLogic.Unlockables; using NitroxModel.Helper; using NitroxModel; diff --git a/NitroxServer/Resources/PrefabPlaceholderAsset.cs b/NitroxServer/Resources/PrefabPlaceholderAsset.cs index d159cb3ded..4d81c2da54 100644 --- a/NitroxServer/Resources/PrefabPlaceholderAsset.cs +++ b/NitroxServer/Resources/PrefabPlaceholderAsset.cs @@ -1,4 +1,5 @@ -using NitroxServer.GameLogic.Entities; +using NitroxModel.DataStructures.GameLogic.Entities; +using NitroxModel.DataStructures.Unity; namespace NitroxServer.Resources; @@ -7,6 +8,8 @@ public class PrefabPlaceholderAsset public string ClassId { get; } public NitroxEntitySlot EntitySlot { get; } + public NitroxVector3 LocalPosition { get; set; } + public NitroxQuaternion LocalRotation { get; set; } public PrefabPlaceholderAsset(string classId, NitroxEntitySlot entitySlot) { From ec215e7e4d3f4aa3592e58012a02ceabe241fdbd Mon Sep 17 00:00:00 2001 From: killzoms Date: Tue, 15 Aug 2023 20:23:16 -0400 Subject: [PATCH 04/11] add some Kinematic prevention patches --- .../MonoBehaviours/MovementController.cs | 13 ++++- .../DataStructures/GameLogic/Entity.cs | 1 + ...reezeRigidbodyWhenFar_FixedUpdate_Patch.cs | 56 +++++++++++++++++++ .../Vehicle_ShouldSetKinematic_Patch.cs | 20 +++++++ NitroxServer/GameLogic/Entities/EntityData.cs | 5 +- 5 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs create mode 100644 NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs diff --git a/NitroxClient/MonoBehaviours/MovementController.cs b/NitroxClient/MonoBehaviours/MovementController.cs index 27c310c928..3a8628932f 100644 --- a/NitroxClient/MonoBehaviours/MovementController.cs +++ b/NitroxClient/MonoBehaviours/MovementController.cs @@ -33,7 +33,7 @@ private void Start() private void Update() { BeforeUpdate(); - if (!rigidbody) + if (!rigidbody && IsMoving) { transform.position = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, Scalar * Time.deltaTime); transform.rotation = Quaternion.Lerp(transform.rotation, TargetRotation, Scalar * Time.deltaTime); @@ -44,7 +44,7 @@ private void Update() private void FixedUpdate() { BeforeFixedUpdate(); - if (rigidbody) + if (rigidbody && IsMoving) { float timing = Scalar * Time.fixedDeltaTime; Vector3 newPos = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, timing); @@ -61,7 +61,14 @@ private void FixedUpdate() Quaternion delta = TargetRotation * transform.rotation.GetInverse(); delta.ToAngleAxis(out float angle, out Vector3 axis); - rigidbody.angularVelocity = .9f * Mathf.Deg2Rad * angle / timing * axis; + if (!float.IsInfinity(axis.x) && !float.IsInfinity(axis.y) && !float.IsInfinity(axis.z)) + { + rigidbody.angularVelocity = .9f * Mathf.Deg2Rad * angle / timing * axis; + } + else + { + rigidbody.angularVelocity = Vector3.zero; + } } } AfterFixedUpdate(); diff --git a/NitroxModel/DataStructures/GameLogic/Entity.cs b/NitroxModel/DataStructures/GameLogic/Entity.cs index 19e3e9e477..60e610529f 100644 --- a/NitroxModel/DataStructures/GameLogic/Entity.cs +++ b/NitroxModel/DataStructures/GameLogic/Entity.cs @@ -32,6 +32,7 @@ public abstract class Entity [DataMember(Order = 4)] public NitroxId ParentId { get; set; } + [DataMember(Order = 5)] public List ChildEntities { get; set; } = new List(); [IgnoreConstructor] diff --git a/NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs b/NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs new file mode 100644 index 0000000000..78b05afb75 --- /dev/null +++ b/NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using HarmonyLib; +using NitroxClient.GameLogic; +using NitroxClient.MonoBehaviours; +using NitroxModel.Helper; +using UnityEngine; + +namespace NitroxPatcher.Patches.Dynamic +{ + public sealed partial class FreezeRigidbodyWhenFar_FixedUpdate_Patch : NitroxPatch, IDynamicPatch + { + public static readonly MethodInfo TARGET_METHOD = Reflect.Method((FreezeRigidbodyWhenFar t) => t.FixedUpdate()); + + public static IEnumerable Transpiler(MethodBase original, IEnumerable instructions, ILGenerator generator) + { + List instructionList = instructions.ToList(); + for (int i = 0; i < instructionList.Count; i++) + { + CodeInstruction instruction = instructionList[i]; + + if (instruction.opcode == OpCodes.Call && instruction.operand.Equals(Reflect.Method((Component c) => c.GetComponent()))) + { + yield return instruction; + yield return instructionList[i+1]; + object jmpLabel = null; + + for (int j = i; j < instructionList.Count; j++) // search for branch instruction + { + if (instructionList[j].opcode == OpCodes.Ble_Un) + { + jmpLabel = instructionList[j].operand; + break; + } + } + yield return new CodeInstruction(OpCodes.Ldarg_0); + yield return new CodeInstruction(OpCodes.Call, Reflect.Property((Component c) => c.gameObject).GetGetMethod()); + yield return new CodeInstruction(OpCodes.Call, Reflect.Method(() => IsMoving(default))); + yield return new CodeInstruction(OpCodes.Brtrue, jmpLabel); + i = i + 1; + continue; + } + + yield return instruction; + } + } + + public static bool IsMoving(GameObject go) + { + return go.TryGetComponent(out MovementController mc) && mc.IsMoving; + } + } +} diff --git a/NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs b/NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs new file mode 100644 index 0000000000..821d0801bb --- /dev/null +++ b/NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs @@ -0,0 +1,20 @@ +using System.Reflection; +using NitroxClient.MonoBehaviours; +using NitroxModel.Helper; + +namespace NitroxPatcher.Patches.Dynamic; + +public sealed partial class Vehicle_ShouldSetKinematic_Patch : NitroxPatch, IDynamicPatch +{ + public static readonly MethodInfo TARGET_METHOD = Reflect.Method((Vehicle t) => t.ShouldSetKinematic()); + + public static bool Prefix(Vehicle __instance, ref bool __result) + { + if (__instance.TryGetComponent(out MovementController movementController)) + { + __result = !movementController.IsMoving; + return false; + } + return true; + } +} diff --git a/NitroxServer/GameLogic/Entities/EntityData.cs b/NitroxServer/GameLogic/Entities/EntityData.cs index 1e3dfd3f01..bca55f2d0f 100644 --- a/NitroxServer/GameLogic/Entities/EntityData.cs +++ b/NitroxServer/GameLogic/Entities/EntityData.cs @@ -25,10 +25,7 @@ private void ProtoAfterDeserialization() // TODO: Rework system to no longer persist children entities because they are duplicates. foreach (Entity entity in Entities) { - if (entity.ChildEntities == null) - { - entity.ChildEntities = new List(); - } + entity.ChildEntities.Clear(); } foreach (Entity entity in Entities) From da6c280402eb7ed344fdad50a84ff2346eb55eee Mon Sep 17 00:00:00 2001 From: killzoms Date: Fri, 18 Aug 2023 18:46:21 -0400 Subject: [PATCH 05/11] first round of bug fixes --- .../ConnectionState/DisconnectedStateTests.cs | 8 +- .../Processors/BasicMovementProcessor.cs | 28 +++++ .../Processors/PlayerMovementProcessor.cs | 4 +- .../SimulationOwnershipResponseProcessor.cs | 16 ++- .../Processors/VehicleMovementProcessor.cs | 4 +- NitroxClient/Debuggers/NetworkDebugger.cs | 3 +- NitroxClient/GameLogic/Entities.cs | 4 +- NitroxClient/GameLogic/LocalPlayer.cs | 14 ++- NitroxClient/GameLogic/MobileVehicleBay.cs | 11 +- NitroxClient/GameLogic/RemotePlayer.cs | 12 +- .../GameLogic/Simulation/LockRequest.cs | 4 +- NitroxClient/GameLogic/SimulationOwnership.cs | 15 ++- .../ReefbackWorldEntitySpawner.cs | 4 +- .../VehicleWorldEntitySpawner.cs | 14 ++- .../WorldEntitySpawnerResolver.cs | 5 +- .../GameLogic/Spawning/WorldEntitySpawner.cs | 4 +- NitroxClient/GameLogic/Vehicles.cs | 10 -- .../MonoBehaviours/MovementController.cs | 105 ++++++++++++++++-- .../MultiplayerVehicleControl.cs | 3 +- NitroxClient/MonoBehaviours/NitroxEntity.cs | 5 +- .../PlayerMovementBroadcaster.cs | 8 +- NitroxModel/Packets/BasicMovementPacket.cs | 29 +++++ NitroxModel/Packets/Movement.cs | 7 +- NitroxModel/Packets/Packet.cs | 5 +- NitroxModel/Packets/PlayerMovement.cs | 13 ++- NitroxModel/Packets/VehicleMovement.cs | 12 +- ...reezeRigidbodyWhenFar_FixedUpdate_Patch.cs | 2 +- .../PilotingChair_OnHandClick_Patch.cs | 7 +- .../PilotingChair_OnPlayerDeath_Patch.cs | 7 +- .../Dynamic/PilotingChair_ReleaseBy_Patch.cs | 7 +- .../Dynamic/Vehicle_OnPilotModeBegin_Patch.cs | 7 +- .../Dynamic/Vehicle_OnPilotModeEnd_Patch.cs | 6 +- .../Vehicle_ShouldSetKinematic_Patch.cs | 4 +- .../BasicMovementPacketProcessor.cs | 35 ++++++ .../Processors/PlayerMovementProcessor.cs | 4 +- .../VehicleMovementPacketProcessor.cs | 2 +- 36 files changed, 344 insertions(+), 84 deletions(-) create mode 100644 NitroxClient/Communication/Packets/Processors/BasicMovementProcessor.cs create mode 100644 NitroxModel/Packets/BasicMovementPacket.cs create mode 100644 NitroxServer/Communication/Packets/Processors/BasicMovementPacketProcessor.cs diff --git a/Nitrox.Test/Client/Communication/MultiplayerSession/ConnectionState/DisconnectedStateTests.cs b/Nitrox.Test/Client/Communication/MultiplayerSession/ConnectionState/DisconnectedStateTests.cs index b9a46c131f..66a055832b 100644 --- a/Nitrox.Test/Client/Communication/MultiplayerSession/ConnectionState/DisconnectedStateTests.cs +++ b/Nitrox.Test/Client/Communication/MultiplayerSession/ConnectionState/DisconnectedStateTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading.Tasks; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -29,7 +29,7 @@ public void NegotiateShouldStartTheClientOnTheContext() Disconnected connectionState = new Disconnected(); // Act - connectionState.NegotiateReservationAsync(connectionContext); + connectionState.NegotiateReservationAsync(connectionContext).RunSynchronously(); // Assert serverClient.IsConnected.Should().BeTrue(); @@ -52,7 +52,7 @@ public void NegotiateShouldSendMultiplayerSessionPolicyRequestPacketToClient() Disconnected connectionState = new Disconnected(); // Act - connectionState.NegotiateReservationAsync(connectionContext); + connectionState.NegotiateReservationAsync(connectionContext).RunSynchronously(); // Assert serverClient.Received().Send(Arg.Any()); @@ -75,7 +75,7 @@ public void NegotiateShouldTransitionToEstablishingSessionPolicyState() Disconnected connectionState = new Disconnected(); // Act - connectionState.NegotiateReservationAsync(connectionContext); + connectionState.NegotiateReservationAsync(connectionContext).RunSynchronously(); // Assert connectionContext.Received().UpdateConnectionState(Arg.Any()); diff --git a/NitroxClient/Communication/Packets/Processors/BasicMovementProcessor.cs b/NitroxClient/Communication/Packets/Processors/BasicMovementProcessor.cs new file mode 100644 index 0000000000..84f465361a --- /dev/null +++ b/NitroxClient/Communication/Packets/Processors/BasicMovementProcessor.cs @@ -0,0 +1,28 @@ +using System.Collections; +using NitroxClient.Communication.Packets.Processors.Abstract; +using NitroxClient.GameLogic; +using NitroxClient.MonoBehaviours; +using NitroxClient.Unity.Helper; +using NitroxModel_Subnautica.DataStructures; +using NitroxModel.DataStructures.Util; +using NitroxModel.Packets; +using UnityEngine; + +namespace NitroxClient.Communication.Packets.Processors; + +public class BasicMovementProcessor : ClientPacketProcessor +{ + public BasicMovementProcessor() + { + } + + public override void Process(BasicMovement movement) + { + if (NitroxEntity.TryGetObjectFrom(movement.Id, out GameObject gameObject)) + { + MovementController mc = gameObject.EnsureComponent(); + mc.TargetPosition = movement.Position.ToUnity(); + mc.TargetRotation = movement.Rotation.ToUnity(); + } + } +} diff --git a/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs b/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs index 6dc6082d8c..75ee300f11 100644 --- a/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs +++ b/NitroxClient/Communication/Packets/Processors/PlayerMovementProcessor.cs @@ -20,14 +20,14 @@ public PlayerMovementProcessor(PlayerManager remotePlayerManager) public override void Process(PlayerMovement movement) { - Optional remotePlayer = remotePlayerManager.Find(movement.PlayerId); + Optional remotePlayer = remotePlayerManager.Find(movement.Id); if (!remotePlayer.HasValue) { return; } remotePlayer.Value.UpdatePosition(movement.Position.ToUnity(), - movement.BodyRotation.ToUnity(), + movement.Rotation.ToUnity(), movement.AimingRotation.ToUnity()); } } diff --git a/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs b/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs index 45578434b5..f7faca9962 100644 --- a/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs +++ b/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs @@ -1,4 +1,4 @@ -using NitroxClient.Communication.Abstract; +using NitroxClient.Communication.Abstract; using NitroxClient.Communication.Packets.Processors.Abstract; using NitroxClient.GameLogic; using NitroxClient.MonoBehaviours; @@ -37,6 +37,8 @@ public override void Process(SimulationOwnershipResponse response) { RemoveRemoteController(response.Id); } + + SwapMovementController(response.Id, response.LockAcquired); } private void RemoveRemoteController(NitroxId id) @@ -49,5 +51,17 @@ private void RemoveRemoteController(NitroxId id) Object.Destroy(remotelyControlled); } } + + private void SwapMovementController(NitroxId id, bool lockAcquired) + { + Optional gameObject = NitroxEntity.GetObjectFrom(id); + + if (gameObject.HasValue) + { + MovementController movementController = gameObject.Value.GetComponent(); + movementController.SetBroadcasting(lockAcquired); + movementController.SetReceiving(!lockAcquired); + } + } } } diff --git a/NitroxClient/Communication/Packets/Processors/VehicleMovementProcessor.cs b/NitroxClient/Communication/Packets/Processors/VehicleMovementProcessor.cs index 2963d91a2c..347cf5e06c 100644 --- a/NitroxClient/Communication/Packets/Processors/VehicleMovementProcessor.cs +++ b/NitroxClient/Communication/Packets/Processors/VehicleMovementProcessor.cs @@ -1,4 +1,4 @@ -using NitroxClient.Communication.Packets.Processors.Abstract; +using NitroxClient.Communication.Packets.Processors.Abstract; using NitroxClient.GameLogic; using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.Util; @@ -20,7 +20,7 @@ public VehicleMovementProcessor(PlayerManager remotePlayerManager, Vehicles vehi public override void Process(VehicleMovement vehicleMovement) { VehicleMovementData vehicleModel = vehicleMovement.VehicleMovementData; - Optional player = remotePlayerManager.Find(vehicleMovement.PlayerId); + Optional player = remotePlayerManager.Find(vehicleMovement.Id); vehicles.UpdateVehiclePosition(vehicleModel, player); } } diff --git a/NitroxClient/Debuggers/NetworkDebugger.cs b/NitroxClient/Debuggers/NetworkDebugger.cs index a062d005b8..4e39b9269e 100644 --- a/NitroxClient/Debuggers/NetworkDebugger.cs +++ b/NitroxClient/Debuggers/NetworkDebugger.cs @@ -18,7 +18,8 @@ public class NetworkDebugger : BaseDebugger, INetworkDebugger private readonly List filter = new() { nameof(PlayerMovement), nameof(EntityTransformUpdates), nameof(PlayerStats), nameof(SpawnEntities), nameof(VehicleMovement), nameof(PlayerCinematicControllerCall), - nameof(PlayFMODAsset), nameof(PlayFMODCustomEmitter), nameof(PlayFMODStudioEmitter), nameof(PlayFMODCustomLoopingEmitter), nameof(SimulationOwnershipChange) + nameof(PlayFMODAsset), nameof(PlayFMODCustomEmitter), nameof(PlayFMODStudioEmitter), nameof(PlayFMODCustomLoopingEmitter), nameof(SimulationOwnershipChange), + nameof(BasicMovement) }; private readonly List packets = new List(PACKET_STORED_COUNT); diff --git a/NitroxClient/GameLogic/Entities.cs b/NitroxClient/GameLogic/Entities.cs index a11e2fe00b..d1c07f252b 100644 --- a/NitroxClient/GameLogic/Entities.cs +++ b/NitroxClient/GameLogic/Entities.cs @@ -29,7 +29,7 @@ public class Entities private readonly Dictionary entitySpawnersByType = new Dictionary(); - public Entities(IPacketSender packetSender, ThrottledPacketSender throttledPacketSender, PlayerManager playerManager, ILocalNitroxPlayer localPlayer) + public Entities(IPacketSender packetSender, ThrottledPacketSender throttledPacketSender, PlayerManager playerManager, ILocalNitroxPlayer localPlayer, SimulationOwnership simulationOwnership) { this.packetSender = packetSender; this.throttledPacketSender = throttledPacketSender; @@ -40,7 +40,7 @@ public Entities(IPacketSender packetSender, ThrottledPacketSender throttledPacke entitySpawnersByType[typeof(InstalledBatteryEntity)] = new InstalledBatteryEntitySpawner(); entitySpawnersByType[typeof(InventoryEntity)] = new InventoryEntitySpawner(); entitySpawnersByType[typeof(InventoryItemEntity)] = new InventoryItemEntitySpawner(); - entitySpawnersByType[typeof(WorldEntity)] = new WorldEntitySpawner(playerManager, localPlayer); + entitySpawnersByType[typeof(WorldEntity)] = new WorldEntitySpawner(playerManager, localPlayer, simulationOwnership); entitySpawnersByType[typeof(PlaceholderGroupWorldEntity)] = entitySpawnersByType[typeof(WorldEntity)]; entitySpawnersByType[typeof(EscapePodWorldEntity)] = entitySpawnersByType[typeof(WorldEntity)]; entitySpawnersByType[typeof(PlayerWorldEntity)] = entitySpawnersByType[typeof(WorldEntity)]; diff --git a/NitroxClient/GameLogic/LocalPlayer.cs b/NitroxClient/GameLogic/LocalPlayer.cs index f3f6d4c0c4..0b3e5b4309 100644 --- a/NitroxClient/GameLogic/LocalPlayer.cs +++ b/NitroxClient/GameLogic/LocalPlayer.cs @@ -25,6 +25,7 @@ public class LocalPlayer : ILocalNitroxPlayer private readonly Lazy body; private readonly Lazy playerModel; private readonly Lazy bodyPrototype; + private readonly NitroxEntity entity; public GameObject Body => body.Value; @@ -34,6 +35,7 @@ public class LocalPlayer : ILocalNitroxPlayer public string PlayerName => multiplayerSession.AuthenticationContext.Username; public ushort PlayerId => multiplayerSession.Reservation.PlayerId; + public PlayerSettings PlayerSettings => multiplayerSession.PlayerSettings; public Perms Permissions; @@ -47,18 +49,24 @@ public LocalPlayer(IMultiplayerSession multiplayerSession, IPacketSender packetS playerModel = new Lazy(() => Body.RequireGameObject("player_view")); bodyPrototype = new Lazy(CreateBodyPrototype); Permissions = Perms.PLAYER; + + if (!Player.mainObject.TryGetComponent(out NitroxEntity nitroxEntity)) + { + nitroxEntity = Player.mainObject.AddComponent(); + } + entity = nitroxEntity; } - public void BroadcastLocation(Vector3 location, Vector3 velocity, Quaternion bodyRotation, Quaternion aimingRotation, Optional vehicle) + public void BroadcastLocation(Vector3 location, Quaternion bodyRotation, Quaternion aimingRotation, Optional vehicle) { Movement movement; if (vehicle.HasValue) { - movement = new VehicleMovement(multiplayerSession.Reservation.PlayerId, vehicle.Value); + movement = new VehicleMovement(entity.Id, vehicle.Value); } else { - movement = new PlayerMovement(multiplayerSession.Reservation.PlayerId, location.ToDto(), bodyRotation.ToDto(), aimingRotation.ToDto()); + movement = new PlayerMovement(entity.Id, location.ToDto(), bodyRotation.ToDto(), aimingRotation.ToDto()); } packetSender.Send(movement); diff --git a/NitroxClient/GameLogic/MobileVehicleBay.cs b/NitroxClient/GameLogic/MobileVehicleBay.cs index 16c6456ce7..1d19c0fbdd 100644 --- a/NitroxClient/GameLogic/MobileVehicleBay.cs +++ b/NitroxClient/GameLogic/MobileVehicleBay.cs @@ -15,12 +15,12 @@ public class MobileVehicleBay public static GameObject MostRecentlyCrafted { get; set; } private readonly IPacketSender packetSender; - private readonly Vehicles vehicles; + private readonly SimulationOwnership simulationOwnership; - public MobileVehicleBay(IPacketSender packetSender, Vehicles vehicles) + public MobileVehicleBay(IPacketSender packetSender, Vehicles vehicles, SimulationOwnership simulationOwnership) { this.packetSender = packetSender; - this.vehicles = vehicles; + this.simulationOwnership = simulationOwnership; } public void BeginCrafting(ConstructorInput constructor, GameObject constructedObject, TechType techType, float duration) @@ -42,11 +42,12 @@ public void BeginCrafting(ConstructorInput constructor, GameObject constructedOb NitroxId constructedObjectId = NitroxEntity.GenerateNewId(constructedObject); + MovementController mc = constructedObject.AddComponent(); + VehicleWorldEntity vehicleEntity = new(constructorId, DayNightCycle.main.timePassedAsFloat, constructedObject.transform.ToLocalDto(), string.Empty, false, constructedObjectId, techType.ToDto(), null); VehicleChildEntityHelper.PopulateChildren(constructedObjectId, constructedObject.GetFullHierarchyPath(), vehicleEntity.ChildEntities, constructedObject); packetSender.Send(new EntitySpawnedByClient(vehicleEntity)); - - constructor.StartCoroutine(vehicles.UpdateVehiclePositionAfterSpawn(constructedObjectId, techType, constructedObject, duration + 10.0f)); + simulationOwnership.RequestSimulationLock(constructedObjectId, SimulationLockType.TRANSIENT); } } diff --git a/NitroxClient/GameLogic/RemotePlayer.cs b/NitroxClient/GameLogic/RemotePlayer.cs index f0d266a59e..4957a2b126 100644 --- a/NitroxClient/GameLogic/RemotePlayer.cs +++ b/NitroxClient/GameLogic/RemotePlayer.cs @@ -111,7 +111,7 @@ public void UpdatePosition(Vector3 position, Quaternion bodyRotation, Quaternion SetVehicle(null); SetPilotingChair(null); - MovementController.IsMoving = true; + MovementController.SetReceiving(true); MovementController.TargetPosition = position; MovementController.TargetRotation = bodyRotation; @@ -169,7 +169,10 @@ public void SetPilotingChair(PilotingChair newPilotingChair) RigidBody.isKinematic = AnimationController["cyclops_steering"] = isInPilotingChair; RigidBody.interpolation = isInPilotingChair ? RigidbodyInterpolation.None : RigidbodyInterpolation.Interpolate; - MovementController.IsMoving = !isInPilotingChair; + if (isInPilotingChair) + { + MovementController.SetReceiving(false); + } } } @@ -246,7 +249,10 @@ public void SetVehicle(Vehicle newVehicle) RigidBody.interpolation = Vehicle ? RigidbodyInterpolation.None : RigidbodyInterpolation.Interpolate; RigidBody.isKinematic = Vehicle; - MovementController.IsMoving = !Vehicle; + if (Vehicle) + { + MovementController.SetReceiving(false); + } AnimationController["in_seamoth"] = newVehicle is SeaMoth; AnimationController["in_exosuit"] = AnimationController["using_mechsuit"] = newVehicle is Exosuit; diff --git a/NitroxClient/GameLogic/Simulation/LockRequest.cs b/NitroxClient/GameLogic/Simulation/LockRequest.cs index 9ccda1eb19..cefebed1f7 100644 --- a/NitroxClient/GameLogic/Simulation/LockRequest.cs +++ b/NitroxClient/GameLogic/Simulation/LockRequest.cs @@ -1,4 +1,4 @@ -using NitroxModel.DataStructures; +using NitroxModel.DataStructures; namespace NitroxClient.GameLogic.Simulation { @@ -19,7 +19,7 @@ public override void LockRequestComplete(NitroxId id, bool lockAquired) { if (onComplete != null) { - onComplete(id, lockAquired, (T)context); + onComplete(id, lockAquired, context); } } diff --git a/NitroxClient/GameLogic/SimulationOwnership.cs b/NitroxClient/GameLogic/SimulationOwnership.cs index 00c1535c5b..f8024266df 100644 --- a/NitroxClient/GameLogic/SimulationOwnership.cs +++ b/NitroxClient/GameLogic/SimulationOwnership.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using NitroxClient.Communication.Abstract; using NitroxClient.GameLogic.Simulation; using NitroxModel.DataStructures; @@ -13,6 +14,9 @@ public class SimulationOwnership private readonly Dictionary simulatedIdsByLockType = new Dictionary(); private readonly Dictionary lockRequestsById = new Dictionary(); + public event Action StoppedSimulatingEntity; + public event Action StartedSimulatingEntity; + public SimulationOwnership(IMultiplayerSession muliplayerSession, IPacketSender packetSender) { this.muliplayerSession = muliplayerSession; @@ -68,11 +72,20 @@ public void ReceivedSimulationLockResponse(NitroxId id, bool lockAquired, Simula public void SimulateEntity(NitroxId id, SimulationLockType lockType) { simulatedIdsByLockType[id] = lockType; + if (StartedSimulatingEntity != null) + { + StartedSimulatingEntity(id); + } } public void StopSimulatingEntity(NitroxId id) { simulatedIdsByLockType.Remove(id); + + if (StoppedSimulatingEntity != null) + { + StoppedSimulatingEntity(id); + } } } } diff --git a/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs b/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs index d6f56aa4e5..06777200ce 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel.DataStructures.Util; @@ -33,7 +33,7 @@ public IEnumerator SpawnAsync(WorldEntity entity, Optional parent, E } life.initialized = true; - life.SpawnPlants(); + yield return life.SpawnPlants(); foreach (Entity childEntity in entity.ChildEntities) { if (childEntity is WorldEntity worldChild) diff --git a/NitroxClient/GameLogic/Spawning/WorldEntities/VehicleWorldEntitySpawner.cs b/NitroxClient/GameLogic/Spawning/WorldEntities/VehicleWorldEntitySpawner.cs index 2674533031..8fc1e6071c 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntities/VehicleWorldEntitySpawner.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntities/VehicleWorldEntitySpawner.cs @@ -3,6 +3,7 @@ using NitroxClient.MonoBehaviours; using NitroxClient.MonoBehaviours.Overrides; using NitroxClient.Unity.Helper; +using NitroxModel.DataStructures; using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel.DataStructures.Util; using NitroxModel.Helper; @@ -17,6 +18,12 @@ public class VehicleWorldEntitySpawner : IWorldEntitySpawner // that they are within allowed range. However, this range is a bit restrictive. We will allow constructor spawning up to a specified // distance - anything more will simply use world spawning (no need to play the animation anyways). private const float ALLOWED_CONSTRUCTOR_DISTANCE = 100.0f; + private readonly SimulationOwnership simulationOwnership; + + internal VehicleWorldEntitySpawner(SimulationOwnership simulationOwnership) + { + this.simulationOwnership = simulationOwnership; + } public IEnumerator SpawnAsync(WorldEntity entity, Optional parent, EntityCell cellRoot, TaskResult> result) { @@ -35,12 +42,17 @@ public IEnumerator SpawnAsync(WorldEntity entity, Optional parent, E { MobileVehicleBay.TransmitLocalSpawns = false; yield return SpawnViaConstructor(vehicleEntity, constructor, result); + result.value.Value.EnsureComponent(); + + simulationOwnership.RequestSimulationLock(vehicleEntity.Id, SimulationLockType.TRANSIENT); MobileVehicleBay.TransmitLocalSpawns = true; yield break; } } - yield return SpawnInWorld(vehicleEntity, result, parent); + yield return SpawnInWorld(vehicleEntity, result, parent); + result.value.Value.EnsureComponent(); + simulationOwnership.RequestSimulationLock(vehicleEntity.Id, SimulationLockType.TRANSIENT); } private IEnumerator SpawnInWorld(VehicleWorldEntity vehicleEntity, TaskResult> result, Optional parent) diff --git a/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs b/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs index 1d8ef1ae7c..d549e8fc3c 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs @@ -8,20 +8,21 @@ namespace NitroxClient.GameLogic.Spawning.WorldEntities; public class WorldEntitySpawnerResolver { private readonly DefaultWorldEntitySpawner defaultEntitySpawner = new(); - private readonly VehicleWorldEntitySpawner vehicleWorldEntitySpawner = new(); + private readonly VehicleWorldEntitySpawner vehicleWorldEntitySpawner; private readonly PlaceholderGroupWorldEntitySpawner prefabWorldEntitySpawner; private readonly PlayerWorldEntitySpawner playerWorldEntitySpawner; private readonly Dictionary customSpawnersByTechType = new(); - public WorldEntitySpawnerResolver(PlayerManager playerManager, ILocalNitroxPlayer localPlayer) + public WorldEntitySpawnerResolver(PlayerManager playerManager, ILocalNitroxPlayer localPlayer, SimulationOwnership simulationOwnership) { customSpawnersByTechType[TechType.Crash] = new CrashEntitySpawner(); customSpawnersByTechType[TechType.Reefback] = new ReefbackWorldEntitySpawner(defaultEntitySpawner); customSpawnersByTechType[TechType.EscapePod] = new EscapePodWorldEntitySpawner(); prefabWorldEntitySpawner = new PlaceholderGroupWorldEntitySpawner(this, defaultEntitySpawner); playerWorldEntitySpawner = new PlayerWorldEntitySpawner(playerManager, localPlayer); + vehicleWorldEntitySpawner = new VehicleWorldEntitySpawner(simulationOwnership); } public IWorldEntitySpawner ResolveEntitySpawner(WorldEntity entity) diff --git a/NitroxClient/GameLogic/Spawning/WorldEntitySpawner.cs b/NitroxClient/GameLogic/Spawning/WorldEntitySpawner.cs index 722fc04d01..239d6676e3 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntitySpawner.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntitySpawner.cs @@ -16,9 +16,9 @@ public class WorldEntitySpawner : EntitySpawner private readonly WorldEntitySpawnerResolver worldEntitySpawnResolver; private readonly Dictionary batchCellsById; - public WorldEntitySpawner(PlayerManager playerManager, ILocalNitroxPlayer localPlayer) + public WorldEntitySpawner(PlayerManager playerManager, ILocalNitroxPlayer localPlayer, SimulationOwnership simulationOwnership) { - worldEntitySpawnResolver = new WorldEntitySpawnerResolver(playerManager, localPlayer); + worldEntitySpawnResolver = new WorldEntitySpawnerResolver(playerManager, localPlayer, simulationOwnership); if (NitroxEnvironment.IsNormal) { diff --git a/NitroxClient/GameLogic/Vehicles.cs b/NitroxClient/GameLogic/Vehicles.cs index d45d21002e..9a7f033c6c 100644 --- a/NitroxClient/GameLogic/Vehicles.cs +++ b/NitroxClient/GameLogic/Vehicles.cs @@ -173,16 +173,6 @@ public IEnumerator AllowMovementPacketsAfterDockingAnimation(PacketSuppressor {}; public event Action BeforeFixedUpdate = () => {}; public event Action AfterUpdate = () => {}; public event Action AfterFixedUpdate = () => {}; + private Vector3 velocity; + private float curTime; private Rigidbody rigidbody; - public Vector3 Velocity; + private IPacketSender packetSender; + private SimulationOwnership simulationOwnership; + private NitroxEntity entity; + private static bool runOnce; + + public void SetBroadcasting(bool broadcasting) + { + Broadcasting = broadcasting; + if (Receiving && broadcasting) + { + Receiving = !broadcasting; + } + } + + public void SetReceiving(bool receiving) + { + Receiving = receiving; + if (Broadcasting && receiving) + { + Broadcasting = !receiving; + } + } + + private static void StartedSimulatingEntity(NitroxId id) + { + if (NitroxEntity.TryGetObjectFrom(id, out GameObject gameObject)) + { + if (gameObject.TryGetComponent(out MovementController mc)) + { + mc.SetBroadcasting(true); + } + } + } + + private static void StoppedSimulatingEntity(NitroxId id) + { + if (NitroxEntity.TryGetObjectFrom(id, out GameObject gameObject)) + { + if (gameObject.TryGetComponent(out MovementController mc)) + { + mc.SetReceiving(true); + } + } + } + + private void Awake() + { + packetSender = NitroxServiceLocator.LocateService(); + simulationOwnership = NitroxServiceLocator.LocateService(); + if (!runOnce) + { + runOnce = true; + simulationOwnership.StartedSimulatingEntity += StartedSimulatingEntity; + simulationOwnership.StoppedSimulatingEntity += StoppedSimulatingEntity; + } + } private void Start() { rigidbody = GetComponent(); + if (!TryGetComponent(out NitroxEntity nitroxEntity)) + { + NitroxEntity.GenerateNewId(gameObject); + + nitroxEntity = GetComponent(); + } + entity = nitroxEntity; } private void Update() { BeforeUpdate(); - if (!rigidbody && IsMoving) + if (!rigidbody && Receiving) { - transform.position = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, Scalar * Time.deltaTime); + transform.position = Vector3.SmoothDamp(transform.position, TargetPosition, ref velocity, Scalar * Time.deltaTime); transform.rotation = Quaternion.Lerp(transform.rotation, TargetRotation, Scalar * Time.deltaTime); } AfterUpdate(); @@ -44,10 +121,22 @@ private void Update() private void FixedUpdate() { BeforeFixedUpdate(); - if (rigidbody && IsMoving) + + if (Broadcasting && simulationOwnership.HasAnyLockType(entity.Id)) + { + curTime += Time.fixedDeltaTime; + if (curTime >= LOCATION_BROADCAST_TIME) + { + curTime = 0f; + + packetSender.Send(new BasicMovement(entity.Id, transform.position.ToDto(), transform.rotation.ToDto())); + } + } + + if (rigidbody && Receiving) { float timing = Scalar * Time.fixedDeltaTime; - Vector3 newPos = Vector3.SmoothDamp(transform.position, TargetPosition, ref Velocity, timing); + Vector3 newPos = Vector3.SmoothDamp(transform.position, TargetPosition, ref velocity, timing); Quaternion newRot = Quaternion.Lerp(transform.rotation, TargetRotation, timing); if (rigidbody.isKinematic) @@ -57,7 +146,7 @@ private void FixedUpdate() } else { - rigidbody.velocity = Velocity; + rigidbody.velocity = velocity; Quaternion delta = TargetRotation * transform.rotation.GetInverse(); delta.ToAngleAxis(out float angle, out Vector3 axis); diff --git a/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs b/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs index 4517d1eac3..574d23e21c 100644 --- a/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs +++ b/NitroxClient/MonoBehaviours/MultiplayerVehicleControl.cs @@ -56,13 +56,12 @@ internal virtual void SetArmPositions(Vector3 leftArmPosition, Vector3 rightArmP internal virtual void Enter() { - movementController.IsMoving = true; + movementController.SetReceiving(true); enabled = true; } public virtual void Exit() { - movementController.IsMoving = false; enabled = false; } diff --git a/NitroxClient/MonoBehaviours/NitroxEntity.cs b/NitroxClient/MonoBehaviours/NitroxEntity.cs index e2862e16d1..b9986f8a82 100644 --- a/NitroxClient/MonoBehaviours/NitroxEntity.cs +++ b/NitroxClient/MonoBehaviours/NitroxEntity.cs @@ -80,7 +80,10 @@ public static void SetNewId(GameObject gameObject, NitroxId id) if (gameObject.TryGetComponent(out NitroxEntity entity)) { - gameObjectsById.Remove(entity.Id); + if (entity.Id != null) + { + gameObjectsById.Remove(entity.Id); + } } else { diff --git a/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs b/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs index e5145de510..675689726b 100644 --- a/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs +++ b/NitroxClient/MonoBehaviours/PlayerMovementBroadcaster.cs @@ -41,7 +41,6 @@ public void FixedUpdate() } Vector3 currentPosition = Player.main.transform.position; - Vector3 playerVelocity = Player.main.playerController.velocity; // IDEA: possibly only CameraRotation is of interest, because bodyrotation is extracted from that. Quaternion bodyRotation = MainCameraControl.main.viewModel.transform.rotation; @@ -55,7 +54,7 @@ public void FixedUpdate() vehicle.Value.DriverRotation = Player.main.transform.rotation.ToDto(); } - localPlayer.BroadcastLocation(currentPosition, playerVelocity, bodyRotation, aimingRotation, vehicle); + localPlayer.BroadcastLocation(currentPosition, bodyRotation, aimingRotation, vehicle); } private Optional GetVehicleMovement() @@ -82,6 +81,11 @@ private Optional GetVehicleMovement() return Optional.Empty; } + if (vehicle.TryGetComponent(out MovementController mc)) + { + mc.SetReceiving(false); + } + Transform vehicleTransform = vehicle.transform; position = vehicleTransform.position; rotation = vehicleTransform.rotation; diff --git a/NitroxModel/Packets/BasicMovementPacket.cs b/NitroxModel/Packets/BasicMovementPacket.cs new file mode 100644 index 0000000000..2c5611eb94 --- /dev/null +++ b/NitroxModel/Packets/BasicMovementPacket.cs @@ -0,0 +1,29 @@ +using NitroxModel.DataStructures.Unity; +using NitroxModel.DataStructures; +using NitroxModel.Networking; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using static NitroxModel.Packets.Packet; + +namespace NitroxModel.Packets +{ + [Serializable] + public class BasicMovement : Movement + { + public override NitroxId Id { get; } + public override NitroxVector3 Position { get; } + public override NitroxQuaternion Rotation { get; } + + public BasicMovement(NitroxId id, NitroxVector3 position, NitroxQuaternion rotation) + { + Id = id; + Position = position; + Rotation = rotation; + DeliveryMethod = NitroxDeliveryMethod.DeliveryMethod.UNRELIABLE_SEQUENCED; + UdpChannel = UdpChannelId.MISC_MOVEMENT; + } + } +} diff --git a/NitroxModel/Packets/Movement.cs b/NitroxModel/Packets/Movement.cs index 03c1a46b49..7fef304003 100644 --- a/NitroxModel/Packets/Movement.cs +++ b/NitroxModel/Packets/Movement.cs @@ -1,13 +1,14 @@ using System; +using NitroxModel.DataStructures; using NitroxModel.DataStructures.Unity; +using NitroxModel.Networking; namespace NitroxModel.Packets; [Serializable] public abstract class Movement : Packet { - public abstract ushort PlayerId { get; } + public abstract NitroxId Id { get; } public abstract NitroxVector3 Position { get; } - public abstract NitroxQuaternion BodyRotation { get; } - public abstract NitroxQuaternion AimingRotation { get; } + public abstract NitroxQuaternion Rotation { get; } } diff --git a/NitroxModel/Packets/Packet.cs b/NitroxModel/Packets/Packet.cs index b49142aa3f..654eb66147 100644 --- a/NitroxModel/Packets/Packet.cs +++ b/NitroxModel/Packets/Packet.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -79,7 +79,8 @@ public enum UdpChannelId DEFAULT = 0, PLAYER_MOVEMENT = 1, VEHICLE_MOVEMENT = 2, - PLAYER_STATS = 3 + PLAYER_STATS = 3, + MISC_MOVEMENT = 4 } public byte[] Serialize() diff --git a/NitroxModel/Packets/PlayerMovement.cs b/NitroxModel/Packets/PlayerMovement.cs index 965d042eb7..78a5015db0 100644 --- a/NitroxModel/Packets/PlayerMovement.cs +++ b/NitroxModel/Packets/PlayerMovement.cs @@ -1,4 +1,5 @@ using System; +using NitroxModel.DataStructures; using NitroxModel.DataStructures.Unity; using NitroxModel.Networking; @@ -7,16 +8,16 @@ namespace NitroxModel.Packets [Serializable] public class PlayerMovement : Movement { - public override ushort PlayerId { get; } + public override NitroxId Id { get; } public override NitroxVector3 Position { get; } - public override NitroxQuaternion BodyRotation { get; } - public override NitroxQuaternion AimingRotation { get; } + public override NitroxQuaternion Rotation { get; } + public NitroxQuaternion AimingRotation { get; } - public PlayerMovement(ushort playerId, NitroxVector3 position, NitroxQuaternion bodyRotation, NitroxQuaternion aimingRotation) + public PlayerMovement(NitroxId id, NitroxVector3 position, NitroxQuaternion rotation, NitroxQuaternion aimingRotation) { - PlayerId = playerId; + Id = id; Position = position; - BodyRotation = bodyRotation; + Rotation = rotation; AimingRotation = aimingRotation; DeliveryMethod = NitroxDeliveryMethod.DeliveryMethod.UNRELIABLE_SEQUENCED; UdpChannel = UdpChannelId.PLAYER_MOVEMENT; diff --git a/NitroxModel/Packets/VehicleMovement.cs b/NitroxModel/Packets/VehicleMovement.cs index 3ea1d356aa..aa784af085 100644 --- a/NitroxModel/Packets/VehicleMovement.cs +++ b/NitroxModel/Packets/VehicleMovement.cs @@ -1,5 +1,6 @@ using System; using BinaryPack.Attributes; +using NitroxModel.DataStructures; using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.Unity; using NitroxModel.Networking; @@ -9,19 +10,18 @@ namespace NitroxModel.Packets [Serializable] public class VehicleMovement : Movement { - public override ushort PlayerId { get; } + public override NitroxId Id { get; } public VehicleMovementData VehicleMovementData { get; } [IgnoredMember] public override NitroxVector3 Position => VehicleMovementData.Position; [IgnoredMember] - public override NitroxQuaternion BodyRotation => VehicleMovementData.Rotation; - [IgnoredMember] - public override NitroxQuaternion AimingRotation => VehicleMovementData.Rotation; + public override NitroxQuaternion Rotation => VehicleMovementData.Rotation; - public VehicleMovement(ushort playerId, VehicleMovementData vehicleMovementData) + /// Player Id + public VehicleMovement(NitroxId id, VehicleMovementData vehicleMovementData) { - PlayerId = playerId; + Id = id; VehicleMovementData = vehicleMovementData; DeliveryMethod = NitroxDeliveryMethod.DeliveryMethod.UNRELIABLE_SEQUENCED; UdpChannel = UdpChannelId.VEHICLE_MOVEMENT; diff --git a/NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs b/NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs index 78b05afb75..6c58e6d3fe 100644 --- a/NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/FreezeRigidbodyWhenFar_FixedUpdate_Patch.cs @@ -50,7 +50,7 @@ public static IEnumerable Transpiler(MethodBase original, IEnum public static bool IsMoving(GameObject go) { - return go.TryGetComponent(out MovementController mc) && mc.IsMoving; + return go.TryGetComponent(out MovementController mc) && mc.Receiving; } } } diff --git a/NitroxPatcher/Patches/Dynamic/PilotingChair_OnHandClick_Patch.cs b/NitroxPatcher/Patches/Dynamic/PilotingChair_OnHandClick_Patch.cs index e96108c1d6..2974a75f8c 100644 --- a/NitroxPatcher/Patches/Dynamic/PilotingChair_OnHandClick_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/PilotingChair_OnHandClick_Patch.cs @@ -1,7 +1,8 @@ -using System.Reflection; +using System.Reflection; using NitroxClient.GameLogic; using NitroxClient.GameLogic.HUD.Components; using NitroxClient.GameLogic.Simulation; +using NitroxClient.MonoBehaviours; using NitroxModel.DataStructures; using NitroxModel.Helper; @@ -50,6 +51,10 @@ private static void ReceivedSimulationLockResponse(NitroxId id, bool lockAquired { skipPrefix = true; pilotingChair.OnHandClick(context.GuiHand); + if (pilotingChair.subRoot.TryGetComponent(out MovementController mc)) + { + mc.SetBroadcasting(false); + } skipPrefix = false; } else diff --git a/NitroxPatcher/Patches/Dynamic/PilotingChair_OnPlayerDeath_Patch.cs b/NitroxPatcher/Patches/Dynamic/PilotingChair_OnPlayerDeath_Patch.cs index 95ff53903a..3e246488f5 100644 --- a/NitroxPatcher/Patches/Dynamic/PilotingChair_OnPlayerDeath_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/PilotingChair_OnPlayerDeath_Patch.cs @@ -1,5 +1,6 @@ -using System.Reflection; +using System.Reflection; using NitroxClient.GameLogic; +using NitroxClient.MonoBehaviours; using NitroxModel.DataStructures; using NitroxModel.Helper; @@ -18,6 +19,10 @@ public static void Postfix(PilotingChair __instance) { // Request to be downgraded to a transient lock so we can still simulate the positioning. Resolve().RequestSimulationLock(id, SimulationLockType.TRANSIENT); + if (__instance.subRoot.TryGetComponent(out MovementController mc)) + { + mc.SetBroadcasting(true); + } } } } diff --git a/NitroxPatcher/Patches/Dynamic/PilotingChair_ReleaseBy_Patch.cs b/NitroxPatcher/Patches/Dynamic/PilotingChair_ReleaseBy_Patch.cs index 6f30e5684a..8d7838f946 100644 --- a/NitroxPatcher/Patches/Dynamic/PilotingChair_ReleaseBy_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/PilotingChair_ReleaseBy_Patch.cs @@ -1,5 +1,6 @@ -using System.Reflection; +using System.Reflection; using NitroxClient.GameLogic; +using NitroxClient.MonoBehaviours; using NitroxModel.DataStructures; using NitroxModel.Helper; @@ -18,6 +19,10 @@ public static void Postfix(PilotingChair __instance) { // Request to be downgraded to a transient lock so we can still simulate the positioning. Resolve().RequestSimulationLock(id, SimulationLockType.TRANSIENT); + if (__instance.subRoot.TryGetComponent(out MovementController mc)) + { + mc.SetBroadcasting(true); + } } } } diff --git a/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeBegin_Patch.cs b/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeBegin_Patch.cs index 73711d9c10..ef9a38448d 100644 --- a/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeBegin_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeBegin_Patch.cs @@ -1,5 +1,6 @@ -using System.Reflection; +using System.Reflection; using NitroxClient.GameLogic; +using NitroxClient.MonoBehaviours; using NitroxModel.Helper; namespace NitroxPatcher.Patches.Dynamic; @@ -11,5 +12,9 @@ public sealed partial class Vehicle_OnPilotModeBegin_Patch : NitroxPatch, IDynam public static void Prefix(Vehicle __instance) { Resolve().BroadcastOnPilotModeChanged(__instance, true); + if (__instance.TryGetComponent(out MovementController mc)) + { + mc.SetBroadcasting(false); + } } } diff --git a/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeEnd_Patch.cs b/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeEnd_Patch.cs index a86d788319..eb06a9e0f3 100644 --- a/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeEnd_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/Vehicle_OnPilotModeEnd_Patch.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using NitroxClient.GameLogic; using NitroxClient.MonoBehaviours; using NitroxModel.DataStructures; @@ -22,6 +22,10 @@ public static void Prefix(Vehicle __instance) if (__instance.TryGetIdOrWarn(out NitroxId id)) { Resolve().RequestSimulationLock(id, SimulationLockType.TRANSIENT); + if (__instance.TryGetComponent(out MovementController mc)) + { + mc.SetBroadcasting(true); + } } } } diff --git a/NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs b/NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs index 821d0801bb..7b2e48e954 100644 --- a/NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/Vehicle_ShouldSetKinematic_Patch.cs @@ -10,9 +10,9 @@ public sealed partial class Vehicle_ShouldSetKinematic_Patch : NitroxPatch, IDyn public static bool Prefix(Vehicle __instance, ref bool __result) { - if (__instance.TryGetComponent(out MovementController movementController)) + if (__instance.TryGetComponent(out MovementController movementController) && movementController.Receiving) { - __result = !movementController.IsMoving; + __result = true; return false; } return true; diff --git a/NitroxServer/Communication/Packets/Processors/BasicMovementPacketProcessor.cs b/NitroxServer/Communication/Packets/Processors/BasicMovementPacketProcessor.cs new file mode 100644 index 0000000000..5c758d9256 --- /dev/null +++ b/NitroxServer/Communication/Packets/Processors/BasicMovementPacketProcessor.cs @@ -0,0 +1,35 @@ +using NitroxModel.DataStructures.GameLogic; +using NitroxModel.DataStructures.GameLogic.Entities; +using NitroxModel.DataStructures.Util; +using NitroxModel.Packets; +using NitroxServer.Communication.Packets.Processors.Abstract; +using NitroxServer.GameLogic; +using NitroxServer.GameLogic.Entities; + +namespace NitroxServer.Communication.Packets.Processors +{ + class BasicMovementPacketProcessor : AuthenticatedPacketProcessor + { + private readonly PlayerManager playerManager; + private readonly EntityRegistry entityRegistry; + + public BasicMovementPacketProcessor(PlayerManager playerManager, EntityRegistry entityRegistry) + { + this.playerManager = playerManager; + this.entityRegistry = entityRegistry; + } + + public override void Process(BasicMovement packet, Player player) + { + Optional entity = entityRegistry.GetEntityById(packet.Id); + + if (entity.HasValue) + { + entity.Value.Transform.Position = packet.Position; + entity.Value.Transform.Rotation = packet.Rotation; + } + + playerManager.SendPacketToOtherPlayers(packet, player); + } + } +} diff --git a/NitroxServer/Communication/Packets/Processors/PlayerMovementProcessor.cs b/NitroxServer/Communication/Packets/Processors/PlayerMovementProcessor.cs index f84bbfeb36..b11642dabd 100644 --- a/NitroxServer/Communication/Packets/Processors/PlayerMovementProcessor.cs +++ b/NitroxServer/Communication/Packets/Processors/PlayerMovementProcessor.cs @@ -26,11 +26,11 @@ public override void Process(PlayerMovement packet, Player player) if (playerEntity.HasValue) { playerEntity.Value.Transform.Position = packet.Position; - playerEntity.Value.Transform.Rotation = packet.BodyRotation; + playerEntity.Value.Transform.Rotation = packet.Rotation; } player.Position = packet.Position; - player.Rotation = packet.BodyRotation; + player.Rotation = packet.Rotation; playerManager.SendPacketToOtherPlayers(packet, player); } } diff --git a/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs b/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs index 6a22c3c9de..c222de6866 100644 --- a/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs +++ b/NitroxServer/Communication/Packets/Processors/VehicleMovementPacketProcessor.cs @@ -29,7 +29,7 @@ public override void Process(VehicleMovement packet, Player player) worldVehicle.Transform.Rotation = packet.VehicleMovementData.Rotation; } - if (player.Id == packet.PlayerId) + if (player.GameObjectId == packet.Id) { player.Position = packet.VehicleMovementData.DriverPosition; player.Rotation = packet.VehicleMovementData.DriverRotation; ; From 35ada97762ffbffbaba33b6aaa759ad5425f3ae0 Mon Sep 17 00:00:00 2001 From: tornac1234 Date: Fri, 18 Aug 2023 19:57:05 -0400 Subject: [PATCH 06/11] add QoL change to GroundMotor.movingPlatform.movementTransfer Co-authored-by: tornac1234 --- .../Dynamic/SubRoot_OnPlayerEntered_Patch.cs | 11 +++++++++- .../Dynamic/SubRoot_OnPlayerExited_Patch.cs | 22 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs diff --git a/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs index d5821e4ce6..2fbab0f024 100644 --- a/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -60,4 +60,13 @@ public static IEnumerable Transpiler(MethodBase original, IEnum } return instructionList; } + + public static void Prefix() + { + PlayerMotor motor = Player.main.playerController.activeController; + if (motor is GroundMotor groundMotor) + { + groundMotor.movingPlatform.movementTransfer = GroundMotor.MovementTransferOnJump.PermaLocked; + } + } } diff --git a/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs new file mode 100644 index 0000000000..562dacd6d7 --- /dev/null +++ b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using HarmonyLib; +using NitroxModel.Helper; + +namespace NitroxPatcher.Patches.Dynamic; + +public sealed partial class SubRoot_OnPlayerExited_Patch : NitroxPatch, IDynamicPatch +{ + private static readonly MethodInfo TARGET_METHOD = Reflect.Method((SubRoot t) => t.OnPlayerExited(default(Player))); + + public static void Prefix() + { + PlayerMotor motor = Player.main.playerController.activeController; + if (motor is GroundMotor groundMotor) + { + groundMotor.movingPlatform.movementTransfer = GroundMotor.MovementTransferOnJump.PermaTransfer; + } + } +} From 68efa0f57a96cb61d8e44076118355d756cdfb97 Mon Sep 17 00:00:00 2001 From: killzoms Date: Fri, 18 Aug 2023 20:34:06 -0400 Subject: [PATCH 07/11] disallow High Precision physics when the Cyclops is being simulated --- .../Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs b/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs index 9b1a287d49..c96ed54f16 100644 --- a/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs @@ -18,11 +18,11 @@ public static bool Prefix(ref bool __result) { if (Player.main.currentSub) { - MultiplayerCyclops cyclops = Player.main.currentSub.GetComponent(); + MovementController movementController = Player.main.currentSub.GetComponent(); - if (cyclops) + if (movementController && movementController.Receiving) { - __result = (cyclops.CurrentPlayer != null); + __result = false; return false; } } From 27c7a730bcb7f1f9eeada5c1415cbbda8c42d89e Mon Sep 17 00:00:00 2001 From: killzoms Date: Fri, 29 Sep 2023 17:29:09 -0400 Subject: [PATCH 08/11] latest changes --- .../WorldEntities/EscapePodWorldEntitySpawner.cs | 13 +++++++++++-- .../WorldEntities/ReefbackWorldEntitySpawner.cs | 6 ++++++ .../WorldEntities/WorldEntitySpawnerResolver.cs | 2 +- NitroxClient/MonoBehaviours/MovementController.cs | 9 +++++++-- NitroxPatcher/Main.cs | 2 +- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/NitroxClient/GameLogic/Spawning/WorldEntities/EscapePodWorldEntitySpawner.cs b/NitroxClient/GameLogic/Spawning/WorldEntities/EscapePodWorldEntitySpawner.cs index 0266fdb6cc..fec52948eb 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntities/EscapePodWorldEntitySpawner.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntities/EscapePodWorldEntitySpawner.cs @@ -2,6 +2,7 @@ using NitroxClient.GameLogic.Spawning.Metadata; using NitroxClient.MonoBehaviours; using NitroxClient.MonoBehaviours.Overrides; +using NitroxModel.DataStructures; using NitroxModel.DataStructures.GameLogic.Entities; using NitroxModel.DataStructures.Util; using NitroxModel_Subnautica.DataStructures; @@ -17,6 +18,12 @@ public class EscapePodWorldEntitySpawner : IWorldEntitySpawner * EscapePod.main to the new escape pod. */ public static bool SURPRESS_ESCAPE_POD_AWAKE_METHOD; + private SimulationOwnership simulationOwnership; + + public EscapePodWorldEntitySpawner(SimulationOwnership simulationOwnership) + { + this.simulationOwnership = simulationOwnership; + } public IEnumerator SpawnAsync(WorldEntity entity, Optional parent, EntityCell cellRoot, TaskResult> result) { @@ -30,6 +37,8 @@ public IEnumerator SpawnAsync(WorldEntity entity, Optional parent, E SURPRESS_ESCAPE_POD_AWAKE_METHOD = true; GameObject escapePod = CreateNewEscapePod(escapePodEntity); + escapePod.EnsureComponent(); + simulationOwnership.RequestSimulationLock(entity.Id, SimulationLockType.TRANSIENT); SURPRESS_ESCAPE_POD_AWAKE_METHOD = false; @@ -48,7 +57,7 @@ private static GameObject CreateNewEscapePod(EscapePodWorldEntity escapePodEntit EntityMetadataProcessor.ApplyMetadata(escapePod, escapePodEntity.Metadata); - Rigidbody rigidbody = escapePod.GetComponent(); + Rigidbody rigidbody = escapePod.GetComponent();/* if (rigidbody != null) { rigidbody.constraints = RigidbodyConstraints.FreezeAll; @@ -57,7 +66,7 @@ private static GameObject CreateNewEscapePod(EscapePodWorldEntity escapePodEntit { Log.Error("Escape pod did not have a rigid body!"); } - + */ escapePod.transform.position = escapePodEntity.Transform.Position.ToUnity(); FixStartMethods(escapePod); diff --git a/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs b/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs index 06777200ce..b69f75431c 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntities/ReefbackWorldEntitySpawner.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using NitroxModel.DataStructures.GameLogic; using NitroxModel.DataStructures.GameLogic.Entities; @@ -38,6 +39,11 @@ public IEnumerator SpawnAsync(WorldEntity entity, Optional parent, E { if (childEntity is WorldEntity worldChild) { + if (DateTime.Now.Month == 4 && DateTime.Now.Day == 1) + { + worldChild.ClassId = entity.ClassId; // Reefback Migration + } + TaskResult> childTaskResult = new(); yield return defaultSpawner.SpawnAsync(worldChild, reefback, cellRoot, childTaskResult); Optional child = childTaskResult.Get(); diff --git a/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs b/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs index d549e8fc3c..a03d20e357 100644 --- a/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs +++ b/NitroxClient/GameLogic/Spawning/WorldEntities/WorldEntitySpawnerResolver.cs @@ -19,7 +19,7 @@ public WorldEntitySpawnerResolver(PlayerManager playerManager, ILocalNitroxPlaye { customSpawnersByTechType[TechType.Crash] = new CrashEntitySpawner(); customSpawnersByTechType[TechType.Reefback] = new ReefbackWorldEntitySpawner(defaultEntitySpawner); - customSpawnersByTechType[TechType.EscapePod] = new EscapePodWorldEntitySpawner(); + customSpawnersByTechType[TechType.EscapePod] = new EscapePodWorldEntitySpawner(simulationOwnership); prefabWorldEntitySpawner = new PlaceholderGroupWorldEntitySpawner(this, defaultEntitySpawner); playerWorldEntitySpawner = new PlayerWorldEntitySpawner(playerManager, localPlayer); vehicleWorldEntitySpawner = new VehicleWorldEntitySpawner(simulationOwnership); diff --git a/NitroxClient/MonoBehaviours/MovementController.cs b/NitroxClient/MonoBehaviours/MovementController.cs index 8efca21501..cde6cb8156 100644 --- a/NitroxClient/MonoBehaviours/MovementController.cs +++ b/NitroxClient/MonoBehaviours/MovementController.cs @@ -137,12 +137,11 @@ private void FixedUpdate() { float timing = Scalar * Time.fixedDeltaTime; Vector3 newPos = Vector3.SmoothDamp(transform.position, TargetPosition, ref velocity, timing); - Quaternion newRot = Quaternion.Lerp(transform.rotation, TargetRotation, timing); if (rigidbody.isKinematic) { rigidbody.MovePosition(newPos); - rigidbody.MoveRotation(newRot); + rigidbody.MoveRotation(TargetRotation); } else { @@ -150,8 +149,14 @@ private void FixedUpdate() Quaternion delta = TargetRotation * transform.rotation.GetInverse(); delta.ToAngleAxis(out float angle, out Vector3 axis); + if (!float.IsInfinity(axis.x) && !float.IsInfinity(axis.y) && !float.IsInfinity(axis.z)) { + if (angle > 180f) + { + angle -= 360f; + } + rigidbody.angularVelocity = .9f * Mathf.Deg2Rad * angle / timing * axis; } else diff --git a/NitroxPatcher/Main.cs b/NitroxPatcher/Main.cs index 9666e2ceee..16a34e87c6 100644 --- a/NitroxPatcher/Main.cs +++ b/NitroxPatcher/Main.cs @@ -1,4 +1,4 @@ -extern alias JB; +extern alias JB; global using NitroxModel.Logger; global using static NitroxClient.Helpers.NitroxEntityExtensions; using System; From 18f229f6896efbb509ad5eaca619d5073eb737e5 Mon Sep 17 00:00:00 2001 From: killzoms Date: Sat, 30 Sep 2023 18:14:21 -0400 Subject: [PATCH 09/11] couple bug fixes --- .../SimulationOwnershipResponseProcessor.cs | 2 +- .../GroundMotor_UpdateFunction_Patch.cs | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs diff --git a/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs b/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs index f7faca9962..a3b0c9e681 100644 --- a/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs +++ b/NitroxClient/Communication/Packets/Processors/SimulationOwnershipResponseProcessor.cs @@ -58,7 +58,7 @@ private void SwapMovementController(NitroxId id, bool lockAcquired) if (gameObject.HasValue) { - MovementController movementController = gameObject.Value.GetComponent(); + MovementController movementController = gameObject.Value.EnsureComponent(); movementController.SetBroadcasting(lockAcquired); movementController.SetReceiving(!lockAcquired); } diff --git a/NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs b/NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs new file mode 100644 index 0000000000..1a093d3a0a --- /dev/null +++ b/NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs @@ -0,0 +1,28 @@ +using System.Reflection; +using NitroxClient.GameLogic; +using NitroxModel.DataStructures; +using NitroxModel.DataStructures.GameLogic.Entities.Metadata; +using NitroxModel.Helper; +using NitroxModel_Subnautica.DataStructures; +using UnityEngine; + +namespace NitroxPatcher.Patches.Dynamic; + +public sealed partial class GroundMotor_UpdateFunction_Patch : NitroxPatch, IDynamicPatch +{ + private static readonly MethodInfo TARGET_METHOD = Reflect.Method((GroundMotor t) => t.UpdateFunction()); + + public static void Postfix(GroundMotor __instance) + { + if (Physics.Raycast(__instance.transform.position + __instance.controller.center + Vector3.down * __instance.controller.height * 0.5f, Vector3.down, out RaycastHit hitInfo, __instance.controller.skinWidth + 0.01f) && hitInfo.transform.TryGetComponent(out Rigidbody rb)) + { + Vector3 platformPosition = hitInfo.transform.position; + Vector3 rbPosition = rb.position; + + Vector3 posRelativeToRigidbody = __instance.transform.position - rbPosition; + Vector3 posRelativeToPlatform = posRelativeToRigidbody + platformPosition; + + __instance.transform.position = posRelativeToPlatform; + } + } +} From 4178fd212feb8ab9e3c7c9cfa3a8ead55a75af85 Mon Sep 17 00:00:00 2001 From: killzoms Date: Sat, 30 Sep 2023 18:41:45 -0400 Subject: [PATCH 10/11] movementTransfer patch fix --- .../Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs | 7 ++----- .../Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs index 2fbab0f024..504a773049 100644 --- a/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerEntered_Patch.cs @@ -63,10 +63,7 @@ public static IEnumerable Transpiler(MethodBase original, IEnum public static void Prefix() { - PlayerMotor motor = Player.main.playerController.activeController; - if (motor is GroundMotor groundMotor) - { - groundMotor.movingPlatform.movementTransfer = GroundMotor.MovementTransferOnJump.PermaLocked; - } + GroundMotor motor = Player.main.groundMotor; + motor.movingPlatform.movementTransfer = GroundMotor.MovementTransferOnJump.PermaLocked; } } diff --git a/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs index 562dacd6d7..5fbd3d6dfe 100644 --- a/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/SubRoot_OnPlayerExited_Patch.cs @@ -13,10 +13,7 @@ public sealed partial class SubRoot_OnPlayerExited_Patch : NitroxPatch, IDynamic public static void Prefix() { - PlayerMotor motor = Player.main.playerController.activeController; - if (motor is GroundMotor groundMotor) - { - groundMotor.movingPlatform.movementTransfer = GroundMotor.MovementTransferOnJump.PermaTransfer; - } + GroundMotor motor = Player.main.groundMotor; + motor.movingPlatform.movementTransfer = GroundMotor.MovementTransferOnJump.PermaTransfer; } } From 237b05cfb73a76023272ded7d26cde177d3ceaf0 Mon Sep 17 00:00:00 2001 From: killzoms Date: Sat, 21 Oct 2023 13:36:51 -0400 Subject: [PATCH 11/11] Reapply HighPrecisionPhysics --- .../GroundMotor_UpdateFunction_Patch.cs | 28 ------------------- ...ayer_RequiresHighPrecisionPhysics_Patch.cs | 2 +- .../Dynamic/Player_SetCurrentSub_Patch.cs | 2 +- 3 files changed, 2 insertions(+), 30 deletions(-) delete mode 100644 NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs diff --git a/NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs b/NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs deleted file mode 100644 index 1a093d3a0a..0000000000 --- a/NitroxPatcher/Patches/Dynamic/GroundMotor_UpdateFunction_Patch.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Reflection; -using NitroxClient.GameLogic; -using NitroxModel.DataStructures; -using NitroxModel.DataStructures.GameLogic.Entities.Metadata; -using NitroxModel.Helper; -using NitroxModel_Subnautica.DataStructures; -using UnityEngine; - -namespace NitroxPatcher.Patches.Dynamic; - -public sealed partial class GroundMotor_UpdateFunction_Patch : NitroxPatch, IDynamicPatch -{ - private static readonly MethodInfo TARGET_METHOD = Reflect.Method((GroundMotor t) => t.UpdateFunction()); - - public static void Postfix(GroundMotor __instance) - { - if (Physics.Raycast(__instance.transform.position + __instance.controller.center + Vector3.down * __instance.controller.height * 0.5f, Vector3.down, out RaycastHit hitInfo, __instance.controller.skinWidth + 0.01f) && hitInfo.transform.TryGetComponent(out Rigidbody rb)) - { - Vector3 platformPosition = hitInfo.transform.position; - Vector3 rbPosition = rb.position; - - Vector3 posRelativeToRigidbody = __instance.transform.position - rbPosition; - Vector3 posRelativeToPlatform = posRelativeToRigidbody + platformPosition; - - __instance.transform.position = posRelativeToPlatform; - } - } -} diff --git a/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs b/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs index c96ed54f16..56abb89188 100644 --- a/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/Player_RequiresHighPrecisionPhysics_Patch.cs @@ -22,7 +22,7 @@ public static bool Prefix(ref bool __result) if (movementController && movementController.Receiving) { - __result = false; + __result = true; return false; } } diff --git a/NitroxPatcher/Patches/Dynamic/Player_SetCurrentSub_Patch.cs b/NitroxPatcher/Patches/Dynamic/Player_SetCurrentSub_Patch.cs index 604c6fa61f..1d906eb657 100644 --- a/NitroxPatcher/Patches/Dynamic/Player_SetCurrentSub_Patch.cs +++ b/NitroxPatcher/Patches/Dynamic/Player_SetCurrentSub_Patch.cs @@ -1,4 +1,4 @@ -using System.Reflection; +using System.Reflection; using NitroxClient.GameLogic; using NitroxModel.Helper;