Files
Fishing2/Packages/com.nwh.dynamicwaterphysics/Samples~/MultiplayerPUN2Sample/Runtime/PhotonMultiplayerShip.cs
2026-02-27 17:44:21 +08:00

129 lines
5.9 KiB
C#

// ╔════════════════════════════════════════════════════════════════╗
// ║ Copyright © 2025 NWH Coding d.o.o. All rights reserved. ║
// ║ Licensed under Unity Asset Store Terms of Service: ║
// ║ https://unity.com/legal/as-terms ║
// ║ Use permitted only in compliance with the License. ║
// ║ Distributed "AS IS", without warranty of any kind. ║
// ╚════════════════════════════════════════════════════════════════╝
#region
using NWH.DWP2.ShipController;
using NWH.DWP2.WaterObjects;
using Photon.Pun;
using UnityEngine;
#endregion
namespace NWH.DWP2.Multiplayer.PUN2
{
/// <summary>
/// Adds multi-player functionality to a vehicle through Photon Unity Networking 2.
/// Uses PhotonRigidbodyView for physics synchronization (velocity) and PhotonTransformView for position/rotation.
/// Note: Using both may cause jitter on some configurations. If issues occur, remove PhotonTransformView.
/// </summary>
[RequireComponent(typeof(PhotonRigidbodyView))]
[RequireComponent(typeof(PhotonTransformView))]
[RequireComponent(typeof(PhotonView))]
[RequireComponent(typeof(AdvancedShipController))]
public class PhotonMultiplayerShip : MonoBehaviour, IPunObservable
{
public bool simulateWaterObjectsOnClient = true;
private PhotonRigidbodyView _photonRigidbodyView;
private PhotonTransformView _photonTransformView;
private PhotonView _photonView;
private AdvancedShipController _shipController;
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
// Guard against null reference if called before initialization completes
if (_shipController == null)
{
return;
}
if (stream.IsWriting)
{
// Send
stream.SendNext(_shipController.input.Steering);
stream.SendNext(_shipController.input.Throttle);
stream.SendNext(_shipController.input.Throttle2);
stream.SendNext(_shipController.input.Throttle3);
stream.SendNext(_shipController.input.Throttle4);
stream.SendNext(_shipController.input.BowThruster);
stream.SendNext(_shipController.input.SternThruster);
stream.SendNext(_shipController.input.SubmarineDepth);
stream.SendNext(_shipController.input.RotateSail);
stream.SendNext(_shipController.input.EngineStartStop);
stream.SendNext(_shipController.input.Anchor);
}
else
{
// Receive
_shipController.input.autoSetInput = false;
_shipController.input.Steering = (float)stream.ReceiveNext();
_shipController.input.Throttle = (float)stream.ReceiveNext();
_shipController.input.Throttle2 = (float)stream.ReceiveNext();
_shipController.input.Throttle3 = (float)stream.ReceiveNext();
_shipController.input.Throttle4 = (float)stream.ReceiveNext();
_shipController.input.BowThruster = (float)stream.ReceiveNext();
_shipController.input.SternThruster = (float)stream.ReceiveNext();
_shipController.input.SubmarineDepth = (float)stream.ReceiveNext();
_shipController.input.RotateSail = (float)stream.ReceiveNext();
_shipController.input.EngineStartStop = (bool)stream.ReceiveNext();
_shipController.input.Anchor = (bool)stream.ReceiveNext();
}
}
private void Initialize()
{
_shipController = GetComponent<AdvancedShipController>();
_photonView = GetComponent<PhotonView>();
_photonRigidbodyView = GetComponent<PhotonRigidbodyView>();
_photonTransformView = GetComponent<PhotonTransformView>();
// Note: PhotonNetwork.SendRate and SerializationRate should be configured globally
// in your NetworkManager/connection script, not per-object. Default is 20/10.
// Recommended: 20-30 for fast-paced gameplay, 10-15 for slower games.
_shipController.MultiplayerIsRemote = !_photonView.IsMine;
// Remote ships keep full physics simulation (non-kinematic) for realistic collisions
// Both PhotonRigidbodyView and PhotonTransformView sync together to prevent desync
// Note: May cause jitter on some setups; if so, remove PhotonTransformView component
// Disable water objects if not local as the position is synced
if (_shipController.MultiplayerIsRemote && !simulateWaterObjectsOnClient)
{
foreach (WaterObject waterObject in gameObject.GetComponentsInChildren<WaterObject>())
{
waterObject.enabled = false;
}
}
_photonView.ObservedComponents.Clear();
_photonView.ObservedComponents.Add(_photonTransformView);
_photonView.ObservedComponents.Add(_photonRigidbodyView);
_photonView.ObservedComponents.Add(this);
}
private void Awake()
{
_shipController = GetComponent<AdvancedShipController>();
_shipController.onShipInitialized.AddListener(Initialize);
}
private void OnDestroy()
{
if (_shipController != null)
{
_shipController.onShipInitialized.RemoveListener(Initialize);
}
}
}
}