Sync probe launcher rotation, allow one person to use at a time

This commit is contained in:
Nick 2022-08-26 18:21:13 -04:00
parent efa54ba7c8
commit 875d269781
8 changed files with 203 additions and 2 deletions

View File

@ -8,7 +8,7 @@ using UnityEngine;
namespace QSB.EchoesOfTheEye;
internal abstract class RotatingElementsVariableSyncer<TWorldObject> : BaseVariableSyncer<Quaternion[]>, ILinkedNetworkBehaviour
public abstract class RotatingElementsVariableSyncer<TWorldObject> : BaseVariableSyncer<Quaternion[]>, ILinkedNetworkBehaviour
where TWorldObject : IWorldObject
{
public override void OnStartClient()

View File

@ -24,6 +24,7 @@ using QSB.Player.TransformSync;
using QSB.SaveSync;
using QSB.ShipSync;
using QSB.ShipSync.TransformSync;
using QSB.StationaryProbeLauncherSync.TransformSync;
using QSB.Syncs.Occasional;
using QSB.TimeSync;
using QSB.Tools.ProbeTool.TransformSync;
@ -56,6 +57,7 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
public GameObject ShipModulePrefab { get; private set; }
public GameObject ShipLegPrefab { get; private set; }
public GameObject ModelShipPrefab { get; private set; }
public GameObject StationaryProbeLauncherPrefab { get; private set; }
private string PlayerName { get; set; }
private GameObject _probePrefab;
@ -149,6 +151,9 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
ModelShipPrefab = MakeNewNetworkObject(14, "NetworkModelShip", typeof(ModelShipTransformSync));
spawnPrefabs.Add(ModelShipPrefab);
StationaryProbeLauncherPrefab = MakeNewNetworkObject(15, "NetworkStationaryProbeLauncher", typeof(StationaryProbeLauncherTransformSync));
spawnPrefabs.Add(StationaryProbeLauncherPrefab);
ConfigureNetworkManager();
}

View File

@ -0,0 +1,11 @@
using QSB.Messaging;
using QSB.StationaryProbeLauncherSync.WorldObjects;
namespace QSB.StationaryProbeLauncherSync.Messages;
public class StationaryProbeLauncherMessage : QSBWorldObjectMessage<QSBStationaryProbeLauncher, bool>
{
public StationaryProbeLauncherMessage(bool inUse) : base(inUse) { }
public override void OnReceiveRemote() => WorldObject.OnUseStateChanged(Data, From);
}

View File

@ -0,0 +1,27 @@
using HarmonyLib;
using QSB.Messaging;
using QSB.Patches;
using QSB.StationaryProbeLauncherSync.Messages;
using QSB.StationaryProbeLauncherSync.WorldObjects;
using QSB.WorldSync;
namespace QSB.StationaryProbeLauncherSync.Patches;
[HarmonyPatch]
public class StationaryProbeLauncherPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
[HarmonyPostfix]
[HarmonyPatch(typeof(StationaryProbeLauncher), nameof(StationaryProbeLauncher.FinishExitSequence))]
public static void StationaryProbeLauncher_FinishExitSequence(Elevator __instance)
{
if (Remote)
{
return;
}
var qsbStationaryProbe = __instance.GetWorldObject<QSBStationaryProbeLauncher>();
qsbStationaryProbe.SendMessage(new StationaryProbeLauncherMessage(false));
}
}

View File

@ -0,0 +1,15 @@
using Cysharp.Threading.Tasks;
using QSB.StationaryProbeLauncherSync.WorldObjects;
using QSB.Utility;
using QSB.WorldSync;
using System.Threading;
namespace QSB.StationaryProbeLauncherSync;
public class StationaryProbeLauncherManager : WorldObjectManager
{
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) =>
QSBWorldSync.Init<QSBStationaryProbeLauncher, ProbeLauncher>(QSBWorldSync.GetUnityObjects<StationaryProbeLauncher>().SortDeterministic());
}

View File

@ -0,0 +1,35 @@
using Mirror;
using QSB.EchoesOfTheEye;
using QSB.StationaryProbeLauncherSync.WorldObjects;
using UnityEngine;
namespace QSB.StationaryProbeLauncherSync.TransformSync;
public class StationaryProbeLauncherTransformSync : RotatingElementsVariableSyncer<QSBStationaryProbeLauncher>
{
protected override Transform[] RotatingElements => new Transform[] { WorldObject.AttachedObject.transform };
protected override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
var launcher = (WorldObject.AttachedObject as StationaryProbeLauncher);
writer.Write(launcher.transform.localRotation);
writer.Write(launcher._degreesX);
writer.Write(launcher._degreesY);
writer.Write(launcher._audioSource.GetLocalVolume());
}
protected override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
var launcher = (WorldObject.AttachedObject as StationaryProbeLauncher);
launcher.transform.localRotation = reader.Read<Quaternion>();
launcher._degreesX = reader.Read<float>();
launcher._degreesY = reader.Read<float>();
launcher._audioSource.SetLocalVolume(reader.Read<float>());
}
}

View File

@ -0,0 +1,108 @@
using Cysharp.Threading.Tasks;
using Mirror;
using QSB.AuthoritySync;
using QSB.Messaging;
using QSB.Player;
using QSB.StationaryProbeLauncherSync.Messages;
using QSB.StationaryProbeLauncherSync.TransformSync;
using QSB.Tools.ProbeLauncherTool.WorldObjects;
using QSB.Utility.LinkedWorldObject;
using System.Threading;
namespace QSB.StationaryProbeLauncherSync.WorldObjects;
public class QSBStationaryProbeLauncher : QSBProbeLauncher, ILinkedWorldObject<StationaryProbeLauncherTransformSync>
{
public StationaryProbeLauncherTransformSync NetworkBehaviour { get; private set; }
public void SetNetworkBehaviour(NetworkBehaviour networkBehaviour) => NetworkBehaviour = (StationaryProbeLauncherTransformSync)networkBehaviour;
private bool _isInit;
private bool _isInUse;
private Shape _shape;
private StationaryProbeLauncher _stationaryProbeLauncher;
public override async UniTask Init(CancellationToken ct)
{
_isInit = true;
// This is implemented by inheriting LinkedWorldObject normally, however I want to inherit from QSBProbeLauncher
// Else we'd have to redo the sync for the effects
if (QSBCore.IsHost)
{
this.SpawnLinked(QSBNetworkManager.singleton.StationaryProbeLauncherPrefab, false);
}
else
{
await this.WaitForLink(ct);
}
await base.Init(ct);
_stationaryProbeLauncher = AttachedObject as StationaryProbeLauncher;
_shape = ((InteractZone)_stationaryProbeLauncher._interactVolume)._trigger._shape;
_stationaryProbeLauncher._interactVolume.OnPressInteract += OnPressInteract;
UpdateUse();
}
public override void OnRemoval()
{
_isInit = false;
if (QSBCore.IsHost)
{
NetworkServer.Destroy(NetworkBehaviour.gameObject);
}
base.OnRemoval();
_stationaryProbeLauncher._interactVolume.OnPressInteract -= OnPressInteract;
}
private void OnPressInteract()
{
// Whoever is using it needs authority to be able to rotate it
// If this is a client they'll get authority from the host when the message is received otherwise give now
if (QSBCore.IsHost) NetworkBehaviour.netIdentity.SetAuthority(QSBPlayerManager.LocalPlayerId);
_isInUse = true;
this.SendMessage(new StationaryProbeLauncherMessage(_isInUse));
}
public override void SendInitialState(uint to)
{
base.SendInitialState(to);
this.SendMessage(new StationaryProbeLauncherMessage(_isInUse) { To = to });
}
private void UpdateUse()
{
// Stuff can be null when its sending the initial state info
if (!_isInit) return;
// If somebody is using this we disable the interaction shape
_shape.enabled = !_isInUse;
if (_isInUse)
{
_stationaryProbeLauncher._audioSource.SetLocalVolume(0f);
_stationaryProbeLauncher._audioSource.Start();
}
else
{
_stationaryProbeLauncher._audioSource.Stop();
}
}
public void OnUseStateChanged(bool isInUse, uint from)
{
// Whoever is using it needs authority to be able to rotate it
if (QSBCore.IsHost) NetworkBehaviour.netIdentity.SetAuthority(from);
_isInUse = isInUse;
UpdateUse();
}
}

View File

@ -12,7 +12,7 @@ internal class ProbeLauncherManager : WorldObjectManager
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
{
QSBWorldSync.Init<QSBProbeLauncher, ProbeLauncher>(typeof(PlayerProbeLauncher));
QSBWorldSync.Init<QSBProbeLauncher, ProbeLauncher>(typeof(PlayerProbeLauncher), typeof(StationaryProbeLauncher));
if (scene == OWScene.SolarSystem)
{
QSBWorldSync.Init<QSBProbeLauncher, ProbeLauncher>(new[]