handle host/connect mid-game suspend update

This commit is contained in:
JohnCorby 2021-11-30 20:17:14 -08:00
parent 459929e4df
commit ee36974fde
8 changed files with 114 additions and 105 deletions

View File

@ -38,7 +38,7 @@ namespace QSB.Anglerfish.Patches
__instance.gameObject.SetActive(true);
__instance._anglerBody.Unsuspend();
__instance.RaiseEvent(nameof(__instance.OnAnglerUnsuspended), __instance._currentState);
QSBEventManager.FireEvent(EventNames.QSBSuspensionChange, qsbAngler.TransformSync.NetIdentity, false);
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbAngler.TransformSync.NetIdentity, false);
return false;
}
if (__instance.gameObject.activeSelf && !__instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe | DynamicOccupant.Ship))
@ -46,7 +46,7 @@ namespace QSB.Anglerfish.Patches
__instance._anglerBody.Suspend();
__instance.gameObject.SetActive(false);
__instance.RaiseEvent(nameof(__instance.OnAnglerSuspended), __instance._currentState);
QSBEventManager.FireEvent(EventNames.QSBSuspensionChange, qsbAngler.TransformSync.NetIdentity, true);
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbAngler.TransformSync.NetIdentity, true);
}
return false;

View File

@ -1,4 +1,6 @@
using QSB.Anglerfish.TransformSync;
using QSB.Events;
using QSB.SuspendableSync;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
@ -21,14 +23,21 @@ namespace QSB.Anglerfish.WorldObjects
if (QSBCore.IsHost)
{
QSBCore.UnityEvents.RunWhen(() => TransformSync, () =>
SuspendableManager.Register(TransformSync.NetIdentity));
Object.Instantiate(QSBNetworkManager.Instance.AnglerPrefab).SpawnWithServerAuthority();
}
// for when you host/connect mid-game
QSBCore.UnityEvents.RunWhen(() => TransformSync, () =>
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, TransformSync.NetIdentity, AttachedObject._anglerBody.IsSuspended()));
}
public override void OnRemoval()
{
if (QSBCore.IsHost)
{
SuspendableManager.Unregister(TransformSync.NetIdentity);
QNetworkServer.Destroy(TransformSync.gameObject);
}
}

View File

@ -101,6 +101,6 @@
public static string QSBLearnLaunchCodes = "QSBLearnLaunchCodes";
public static string QSBSatelliteRepairTick = "QSBSatelliteRepairTick";
public static string QSBSatelliteRepaired = "QSBSatelliteRepairTick";
public static string QSBSuspensionChange = "QSBSuspensionChange";
public static string QSBSuspendChange = "QSBSuspendChange";
}
}

View File

@ -22,7 +22,7 @@ using QSB.ShipSync.Events;
using QSB.ShipSync.Events.Component;
using QSB.ShipSync.Events.Hull;
using QSB.StatueSync.Events;
using QSB.SuspensionAuthoritySync;
using QSB.SuspendableSync;
using QSB.TimeSync.Events;
using QSB.Tools.FlashlightTool.Events;
using QSB.Tools.ProbeLauncherTool.Events;
@ -112,7 +112,7 @@ namespace QSB.Events
new IdentifyFrequencyEvent(),
new IdentifySignalEvent(),
new NpcAnimationEvent(),
new SuspensionChangeEvent(),
new SuspendChangeEvent(),
// Ship
new FlyShipEvent(),
new HatchEvent(),

View File

@ -0,0 +1,84 @@
using System.Linq;
using QSB.Events;
using QSB.Player;
using QSB.Utility;
using QuantumUNET;
using QuantumUNET.Components;
namespace QSB.SuspendableSync
{
public class SuspendChangeEvent : QSBEvent<SuspendChangeMessage>
{
public override void SetupListener() =>
GlobalMessenger<QNetworkIdentity, bool>.AddListener(EventNames.QSBSuspendChange, Handler);
public override void CloseListener() =>
GlobalMessenger<QNetworkIdentity, bool>.RemoveListener(EventNames.QSBSuspendChange, Handler);
private void Handler(QNetworkIdentity identity, bool suspended) => SendEvent(CreateMessage(identity, suspended));
private SuspendChangeMessage CreateMessage(QNetworkIdentity identity, bool unsuspended) => new()
{
OnlySendToHost = true,
Identity = identity,
Suspended = unsuspended
};
public override void OnReceiveLocal(bool isHost, SuspendChangeMessage message) => OnReceive(message);
public override void OnReceiveRemote(bool isHost, SuspendChangeMessage message) => OnReceive(message);
private static void OnReceive(SuspendChangeMessage message)
{
if (!QSBCore.WorldObjectsReady)
{
return;
}
var unsuspendedFor = SuspendableManager._unsuspendedFor[message.Identity];
var suspended = !unsuspendedFor.Contains(message.FromId);
if (message.Suspended == suspended)
{
return;
}
if (!message.Suspended)
{
unsuspendedFor.Add(message.FromId);
}
else
{
unsuspendedFor.Remove(message.FromId);
}
var newOwner = unsuspendedFor.Count != 0 ? unsuspendedFor[0] : uint.MaxValue;
SetAuthority(message.Identity, newOwner);
}
private static void SetAuthority(QNetworkIdentity identity, uint id)
{
var oldConn = identity.ClientAuthorityOwner;
var newConn = id != uint.MaxValue
? QNetworkServer.connections.First(x => x.GetPlayerId() == id)
: null;
if (oldConn == newConn)
{
return;
}
if (oldConn != null)
{
identity.RemoveClientAuthority(oldConn);
}
if (newConn != null)
{
identity.AssignClientAuthority(newConn);
}
DebugLog.DebugWrite($"{QSBPlayerManager.LocalPlayerId}.{identity.NetId}:{identity.gameObject.name} - set authority to {id}");
}
}
}

View File

@ -2,9 +2,9 @@
using QuantumUNET.Components;
using QuantumUNET.Transport;
namespace QSB.SuspensionAuthoritySync
namespace QSB.SuspendableSync
{
public class SuspensionChangeMessage : PlayerMessage
public class SuspendChangeMessage : PlayerMessage
{
public QNetworkIdentity Identity;
public bool Suspended;

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
using QuantumUNET.Components;
namespace QSB.SuspendableSync
{
/// all of this is host only
public static class SuspendableManager
{
internal static readonly Dictionary<QNetworkIdentity, List<uint>> _unsuspendedFor = new();
public static void Register(QNetworkIdentity identity) => _unsuspendedFor.Add(identity, new List<uint>());
public static void Unregister(QNetworkIdentity identity) => _unsuspendedFor.Remove(identity);
}
}

View File

@ -1,98 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using QSB.Events;
using QSB.Player;
using QSB.Utility;
using QuantumUNET;
using QuantumUNET.Components;
namespace QSB.SuspensionAuthoritySync
{
public class SuspensionChangeEvent : QSBEvent<SuspensionChangeMessage>
{
private static Dictionary<QNetworkIdentity, List<uint>> _potentialOwners;
public override void SetupListener()
{
if (QSBCore.IsHost)
{
_potentialOwners = new Dictionary<QNetworkIdentity, List<uint>>();
}
GlobalMessenger<QNetworkIdentity, bool>.AddListener(EventNames.QSBSuspensionChange, Handler);
}
public override void CloseListener()
{
if (QSBCore.IsHost)
{
_potentialOwners = null;
}
GlobalMessenger<QNetworkIdentity, bool>.RemoveListener(EventNames.QSBSuspensionChange, Handler);
}
private void Handler(QNetworkIdentity identity, bool suspended) => SendEvent(CreateMessage(identity, suspended));
private SuspensionChangeMessage CreateMessage(QNetworkIdentity identity, bool suspended) => new()
{
OnlySendToHost = true,
Identity = identity,
Suspended = suspended
};
public override void OnReceiveLocal(bool isHost, SuspensionChangeMessage message) => OnReceive(message);
public override void OnReceiveRemote(bool isHost, SuspensionChangeMessage message) => OnReceive(message);
private static void OnReceive(SuspensionChangeMessage message)
{
if (!QSBCore.WorldObjectsReady)
{
return;
}
// init owner list for this identity
if (!_potentialOwners.TryGetValue(message.Identity, out var potentialOwners))
{
potentialOwners = new List<uint>();
_potentialOwners[message.Identity] = potentialOwners;
}
if (!message.Suspended)
{
potentialOwners.Add(message.FromId);
}
else
{
potentialOwners.Remove(message.FromId);
}
var newOwner = potentialOwners.Count != 0 ? potentialOwners[0] : uint.MaxValue;
SetAuthority(message.Identity, newOwner);
}
private static void SetAuthority(QNetworkIdentity identity, uint id)
{
var oldConn = identity.ClientAuthorityOwner;
var newConn = id != uint.MaxValue
? QNetworkServer.connections.First(x => x.GetPlayerId() == id)
: null;
if (oldConn == newConn)
{
return;
}
if (oldConn != null)
{
identity.RemoveClientAuthority(oldConn);
}
if (newConn != null)
{
identity.AssignClientAuthority(newConn);
}
DebugLog.DebugWrite($"{QSBPlayerManager.LocalPlayerId}.{identity.NetId}:{identity.gameObject.name} - set authority to {id}");
}
}
}