Merge branch 'authority-sync-again' into dev

# Conflicts:
#	QSB/SuspendableSync/SuspendableManager.cs
This commit is contained in:
JohnCorby 2021-12-02 15:20:11 -08:00
commit 5c01fac081
14 changed files with 162 additions and 196 deletions

View File

@ -1,5 +1,6 @@
using HarmonyLib;
using QSB.Anglerfish.WorldObjects;
using QSB.AuthoritySync;
using QSB.Events;
using QSB.Patches;
using QSB.Utility;
@ -42,7 +43,7 @@ namespace QSB.Anglerfish.Patches
__instance.gameObject.SetActive(true);
__instance._anglerBody.Unsuspend();
__instance.RaiseEvent(nameof(__instance.OnAnglerUnsuspended), __instance._currentState);
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbAngler.TransformSync.NetIdentity, false);
qsbAngler.TransformSync.NetIdentity.FireAuthQueue(true);
return false;
}
if (__instance.gameObject.activeSelf && !__instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe | DynamicOccupant.Ship))
@ -50,7 +51,7 @@ namespace QSB.Anglerfish.Patches
__instance._anglerBody.Suspend();
__instance.gameObject.SetActive(false);
__instance.RaiseEvent(nameof(__instance.OnAnglerSuspended), __instance._currentState);
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbAngler.TransformSync.NetIdentity, true);
qsbAngler.TransformSync.NetIdentity.FireAuthQueue(false);
}
return false;

View File

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

View File

@ -0,0 +1,87 @@
using System.Collections.Generic;
using System.Linq;
using QSB.Events;
using QSB.Utility;
using QuantumUNET;
using QuantumUNET.Components;
namespace QSB.AuthoritySync
{
public static class AuthorityManager
{
#region host only
/// whoever is first gets authority
private static readonly Dictionary<QNetworkIdentity, List<uint>> _authQueue = new();
public static void RegisterAuthQueue(this QNetworkIdentity identity) => _authQueue.Add(identity, new List<uint>());
public static void UnregisterAuthQueue(this QNetworkIdentity identity) => _authQueue.Remove(identity);
public static void UpdateAuthQueue(this QNetworkIdentity identity, uint id, bool queue)
{
var authQueue = _authQueue[identity];
var oldAuthority = authQueue.Contains(id);
if (queue == oldAuthority)
{
return;
}
if (queue)
{
authQueue.Add(id);
}
else
{
authQueue.Remove(id);
}
var newOwner = authQueue.Count != 0 ? authQueue[0] : uint.MaxValue;
SetAuthority(identity, newOwner);
}
/// transfer authority to a different client
public static void OnDisconnect(uint id)
{
foreach (var identity in _authQueue.Keys)
{
identity.UpdateAuthQueue(id, false);
}
}
public static void SetAuthority(this 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($"{identity.NetId}:{identity.gameObject.name} - "
// + $"set authority to {id}");
}
#endregion
#region any client
public static void FireAuthQueue(this QNetworkIdentity identity, bool queue) =>
QSBEventManager.FireEvent(EventNames.QSBAuthorityQueue, identity, queue);
#endregion
}
}

View File

@ -0,0 +1,37 @@
using QSB.Events;
using QuantumUNET.Components;
namespace QSB.AuthoritySync
{
public class AuthorityQueueEvent : QSBEvent<AuthorityQueueMessage>
{
public override void SetupListener() =>
GlobalMessenger<QNetworkIdentity, bool>.AddListener(EventNames.QSBAuthorityQueue, Handler);
public override void CloseListener() =>
GlobalMessenger<QNetworkIdentity, bool>.RemoveListener(EventNames.QSBAuthorityQueue, Handler);
private void Handler(QNetworkIdentity identity, bool queue) => SendEvent(CreateMessage(identity, queue));
private AuthorityQueueMessage CreateMessage(QNetworkIdentity identity, bool queue) => new()
{
OnlySendToHost = true,
Identity = identity,
Queue = queue
};
public override void OnReceiveLocal(bool isHost, AuthorityQueueMessage message) => OnReceive(message);
public override void OnReceiveRemote(bool isHost, AuthorityQueueMessage message) => OnReceive(message);
private static void OnReceive(AuthorityQueueMessage message)
{
if (!QSBCore.WorldObjectsReady)
{
return;
}
message.Identity.UpdateAuthQueue(message.FromId, message.Queue);
}
}
}

View File

@ -2,25 +2,25 @@
using QuantumUNET.Components;
using QuantumUNET.Transport;
namespace QSB.SuspendableSync
namespace QSB.AuthoritySync
{
public class SuspendChangeMessage : PlayerMessage
public class AuthorityQueueMessage : PlayerMessage
{
public QNetworkIdentity Identity;
public bool Suspended;
public bool Queue;
public override void Deserialize(QNetworkReader reader)
{
base.Deserialize(reader);
Identity = reader.ReadNetworkIdentity();
Suspended = reader.ReadBoolean();
Queue = reader.ReadBoolean();
}
public override void Serialize(QNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(Identity);
writer.Write(Suspended);
writer.Write(Queue);
}
}
}

View File

@ -101,7 +101,7 @@
public static string QSBLearnLaunchCodes = "QSBLearnLaunchCodes";
public static string QSBSatelliteRepairTick = "QSBSatelliteRepairTick";
public static string QSBSatelliteRepaired = "QSBSatelliteRepairTick";
public static string QSBSuspendChange = "QSBSuspendChange";
public static string QSBAuthorityQueue = "QSBAuthorityQueue";
public static string QSBJellyfishRising = "QSBJellyfishRising";
}
}

View File

@ -3,6 +3,7 @@ using OWML.Common;
using QSB.Anglerfish.Events;
using QSB.Animation.NPC.Events;
using QSB.Animation.Player.Events;
using QSB.AuthoritySync;
using QSB.CampfireSync.Events;
using QSB.ClientServerStateSync.Events;
using QSB.ConversationSync.Events;
@ -23,7 +24,6 @@ using QSB.ShipSync.Events;
using QSB.ShipSync.Events.Component;
using QSB.ShipSync.Events.Hull;
using QSB.StatueSync.Events;
using QSB.SuspendableSync;
using QSB.TimeSync.Events;
using QSB.Tools.FlashlightTool.Events;
using QSB.Tools.ProbeLauncherTool.Events;
@ -114,7 +114,7 @@ namespace QSB.Events
new IdentifyFrequencyEvent(),
new IdentifySignalEvent(),
new NpcAnimationEvent(),
new SuspendChangeEvent(),
new AuthorityQueueEvent(),
// Ship
new FlyShipEvent(),
new HatchEvent(),

View File

@ -1,4 +1,5 @@
using HarmonyLib;
using QSB.AuthoritySync;
using QSB.Events;
using QSB.JellyfishSync.WorldObjects;
using QSB.Patches;
@ -24,14 +25,14 @@ namespace QSB.JellyfishSync.Patches
{
__instance.gameObject.SetActive(true);
__instance._jellyfishBody.Unsuspend();
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbJellyfish.TransformSync.NetIdentity, false);
qsbJellyfish.TransformSync.NetIdentity.FireAuthQueue(true);
return false;
}
if (__instance.gameObject.activeSelf && !__instance._sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe | DynamicOccupant.Ship))
{
__instance._jellyfishBody.Suspend();
__instance.gameObject.SetActive(false);
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, qsbJellyfish.TransformSync.NetIdentity, true);
qsbJellyfish.TransformSync.NetIdentity.FireAuthQueue(false);
}
return false;

View File

@ -1,6 +1,5 @@
using QSB.Events;
using QSB.AuthoritySync;
using QSB.JellyfishSync.TransformSync;
using QSB.SuspendableSync;
using QSB.WorldSync;
using QuantumUNET;
using UnityEngine;
@ -22,19 +21,19 @@ namespace QSB.JellyfishSync.WorldObjects
{
QNetworkServer.Spawn(Object.Instantiate(QSBNetworkManager.Instance.JellyfishPrefab));
QSBCore.UnityEvents.RunWhen(() => TransformSync, () =>
SuspendableManager.Register(TransformSync.NetIdentity));
TransformSync.NetIdentity.RegisterAuthQueue());
}
// for when you host/connect mid-game
QSBCore.UnityEvents.RunWhen(() => TransformSync, () =>
QSBEventManager.FireEvent(EventNames.QSBSuspendChange, TransformSync.NetIdentity, AttachedObject._jellyfishBody.IsSuspended()));
TransformSync.NetIdentity.FireAuthQueue(!AttachedObject._jellyfishBody.IsSuspended()));
}
public override void OnRemoval()
{
if (QSBCore.IsHost)
{
SuspendableManager.Unregister(TransformSync.NetIdentity);
TransformSync.NetIdentity.UnregisterAuthQueue();
QNetworkServer.Destroy(TransformSync.gameObject);
}
}

View File

@ -1,12 +1,11 @@
using OWML.Common;
using System.Linq;
using OWML.Common;
using QSB.AuthoritySync;
using QSB.Events;
using QSB.OrbSync.TransformSync;
using QSB.Utility;
using QSB.WorldSync;
using QSB.WorldSync.Events;
using QuantumUNET;
using QuantumUNET.Components;
using System.Linq;
namespace QSB.OrbSync.Events
{
@ -49,7 +48,6 @@ namespace QSB.OrbSync.Events
private static void HandleServer(WorldObjectMessage message)
{
var fromPlayer = QNetworkServer.connections.First(x => x.GetPlayerId() == message.FromId);
if (NomaiOrbTransformSync.OrbTransformSyncs == null || NomaiOrbTransformSync.OrbTransformSyncs.Count == 0)
{
DebugLog.ToConsole($"Error - OrbTransformSyncs is empty or null. (ID {message.ObjectId})", MessageType.Error);
@ -62,11 +60,6 @@ namespace QSB.OrbSync.Events
return;
}
if (fromPlayer == null)
{
DebugLog.ToConsole("Error - FromPlayer is null!", MessageType.Error);
}
var orbSync = NomaiOrbTransformSync.OrbTransformSyncs.Where(x => x != null)
.FirstOrDefault(x => x.AttachedObject == QSBWorldSync.OldOrbList[message.ObjectId].transform);
if (orbSync == null)
@ -75,27 +68,7 @@ namespace QSB.OrbSync.Events
return;
}
var orbIdentity = orbSync.GetComponent<QNetworkIdentity>();
if (orbIdentity == null)
{
DebugLog.ToConsole($"Error - Orb identity is null. (ID {message.ObjectId})", MessageType.Error);
return;
}
var currentOwner = orbIdentity.ClientAuthorityOwner;
var newOwner = fromPlayer;
if (currentOwner == newOwner)
{
return;
}
if (currentOwner != null && currentOwner != fromPlayer)
{
orbIdentity.RemoveClientAuthority(currentOwner);
}
orbIdentity.AssignClientAuthority(fromPlayer);
orbSync.NetIdentity.SetAuthority(message.FromId);
orbSync.enabled = true;
}
@ -124,4 +97,4 @@ namespace QSB.OrbSync.Events
orb.enabled = true;
}
}
}
}

View File

@ -2,6 +2,7 @@
using System.Linq;
using OWML.Common;
using OWML.Utils;
using QSB.AuthoritySync;
using QSB.ClientServerStateSync;
using QSB.DeathSync;
using QSB.Events;
@ -11,7 +12,6 @@ using QSB.Player;
using QSB.Player.TransformSync;
using QSB.PoolSync;
using QSB.ShipSync.TransformSync;
using QSB.SuspendableSync;
using QSB.TimeSync;
using QSB.Utility;
using QSB.WorldSync;
@ -209,32 +209,33 @@ namespace QSB
{
DebugLog.DebugWrite("OnServerDisconnect", MessageType.Info);
// remove authority for orbs
// revert authority for orbs
foreach (var item in NomaiOrbTransformSync.OrbTransformSyncs)
{
if (!item)
{
DebugLog.ToConsole($"Warning - null transform sync in NomaiOrbTransformSync.OrbTransformSyncs!", MessageType.Warning);
continue;
}
var identity = item.NetIdentity;
if (identity.ClientAuthorityOwner == conn)
{
identity.RemoveClientAuthority(conn);
identity.SetAuthority(QSBPlayerManager.LocalPlayerId);
}
}
// remove authority from ship
// revert authority from ship
if (ShipTransformSync.LocalInstance)
{
var identity = ShipTransformSync.LocalInstance.NetIdentity;
if (identity.ClientAuthorityOwner == conn)
{
identity.RemoveClientAuthority(conn);
identity.SetAuthority(QSBPlayerManager.LocalPlayerId);
}
}
SuspendableManager.OnDisconnect(conn);
AuthorityManager.OnDisconnect(conn.GetPlayerId());
base.OnServerDisconnect(conn);
}

View File

@ -1,11 +1,9 @@
using OWML.Utils;
using QSB.AuthoritySync;
using QSB.Events;
using QSB.Messaging;
using QSB.Player;
using QSB.ShipSync.TransformSync;
using QSB.Utility;
using QuantumUNET;
using System.Linq;
using UnityEngine;
namespace QSB.ShipSync.Events
@ -57,24 +55,9 @@ namespace QSB.ShipSync.Events
if (QSBCore.IsHost)
{
var newAuthority = ShipManager.Instance.CurrentFlyer == uint.MaxValue
? QNetworkServer.connections.First(x => x.GetPlayerId() == QSBPlayerManager.LocalPlayerId)
: QNetworkServer.connections.First(x => x.GetPlayerId() == id);
var ship = ShipTransformSync.LocalInstance;
var shipNetId = ship.NetIdentity;
if (shipNetId.ClientAuthorityOwner == newAuthority)
{
return;
}
if (shipNetId.ClientAuthorityOwner != null && shipNetId.ClientAuthorityOwner != newAuthority)
{
shipNetId.RemoveClientAuthority(shipNetId.ClientAuthorityOwner);
}
shipNetId.AssignClientAuthority(newAuthority);
ShipTransformSync.LocalInstance.NetIdentity.SetAuthority(isFlying
? id
: QSBPlayerManager.LocalPlayerId);
}
}
}

View File

@ -1,37 +0,0 @@
using QSB.Events;
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;
}
SuspendableManager.UpdateSuspended(message.FromId, message.Identity, message.Suspended);
}
}
}

View File

@ -1,78 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using QSB.Utility;
using QuantumUNET;
using QuantumUNET.Components;
namespace QSB.SuspendableSync
{
/// all of this is host only
public static class SuspendableManager
{
private 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);
public static void UpdateSuspended(uint id, QNetworkIdentity identity, bool suspended)
{
var unsuspendedFor = _unsuspendedFor[identity];
var oldSuspended = !unsuspendedFor.Contains(id);
if (suspended == oldSuspended)
{
return;
}
if (!suspended)
{
unsuspendedFor.Add(id);
}
else
{
unsuspendedFor.Remove(id);
}
var newOwner = unsuspendedFor.Count != 0 ? unsuspendedFor[0] : uint.MaxValue;
SetAuthority(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);
}
}
/// transfer authority to a different client
public static void OnDisconnect(QNetworkConnection conn)
{
var id = conn.GetPlayerId();
foreach (var (identity, unsuspendedFor) in _unsuspendedFor)
{
if (unsuspendedFor.Remove(id))
{
var newOwner = unsuspendedFor.Count != 0 ? unsuspendedFor[0] : uint.MaxValue;
SetAuthority(identity, newOwner);
}
}
}
}
}