diff --git a/QSB/Events/QSBEventManager.cs b/QSB/Events/QSBEventManager.cs index f5569835..fccfc942 100644 --- a/QSB/Events/QSBEventManager.cs +++ b/QSB/Events/QSBEventManager.cs @@ -5,6 +5,7 @@ using QSB.DeathSync.Events; using QSB.ElevatorSync.Events; using QSB.FrequencySync.Events; using QSB.GeyserSync.Events; +using QSB.ItemSync.Events; using QSB.LogSync.Events; using QSB.OrbSync.Events; using QSB.Player.Events; @@ -56,6 +57,7 @@ namespace QSB.Events new MoonStateChangeEvent(), new EnterLeaveEvent(), new QuantumAuthorityEvent(), + new DropItemEvent(), // Conversation/dialogue/exploration new ConversationEvent(), new ConversationStartEndEvent(), @@ -122,5 +124,35 @@ namespace QSB.Events } GlobalMessenger.FireEvent(eventName, arg1, arg2, arg3); } + + public static void FireEvent(string eventName, T arg1, U arg2, V arg3, W arg4) + { + if (!QSBCore.IsInMultiplayer) + { + DebugLog.ToConsole($"Warning - Tried to send event {eventName} while not connected to/hosting server.", MessageType.Warning); + return; + } + GlobalMessenger.FireEvent(eventName, arg1, arg2, arg3, arg4); + } + + public static void FireEvent(string eventName, T arg1, U arg2, V arg3, W arg4, X arg5) + { + if (!QSBCore.IsInMultiplayer) + { + DebugLog.ToConsole($"Warning - Tried to send event {eventName} while not connected to/hosting server.", MessageType.Warning); + return; + } + GlobalMessenger.FireEvent(eventName, arg1, arg2, arg3, arg4, arg5); + } + + public static void FireEvent(string eventName, T arg1, U arg2, V arg3, W arg4, X arg5, Y arg6) + { + if (!QSBCore.IsInMultiplayer) + { + DebugLog.ToConsole($"Warning - Tried to send event {eventName} while not connected to/hosting server.", MessageType.Warning); + return; + } + GlobalMessenger.FireEvent(eventName, arg1, arg2, arg3, arg4, arg5, arg6); + } } } \ No newline at end of file diff --git a/QSB/ItemSync/Events/DropItemEvent.cs b/QSB/ItemSync/Events/DropItemEvent.cs index d5cc0f23..9c873d0e 100644 --- a/QSB/ItemSync/Events/DropItemEvent.cs +++ b/QSB/ItemSync/Events/DropItemEvent.cs @@ -11,27 +11,26 @@ namespace QSB.ItemSync.Events public override QSB.Events.EventType Type => QSB.Events.EventType.DropItem; public override void SetupListener() - => GlobalMessenger.AddListener(EventNames.QSBDropItem, Handler); + => GlobalMessenger.AddListener(EventNames.QSBDropItem, Handler); public override void CloseListener() - => GlobalMessenger.RemoveListener(EventNames.QSBDropItem, Handler); + => GlobalMessenger.RemoveListener(EventNames.QSBDropItem, Handler); - private void Handler(int objectId, Vector3 position, Vector3 normal, Transform parent, Sector sector, DetachableFragment fragment) - => SendEvent(CreateMessage(objectId, position, normal, parent, sector, fragment)); + private void Handler(int objectId, Vector3 position, Vector3 normal, Sector sector) + => SendEvent(CreateMessage(objectId, position, normal, sector)); - private DropItemMessage CreateMessage(int objectId, Vector3 position, Vector3 normal, Transform parent, Sector sector, DetachableFragment fragment) => new DropItemMessage + private DropItemMessage CreateMessage(int objectId, Vector3 position, Vector3 normal, Sector sector) => new DropItemMessage { ObjectId = objectId, Position = position, Normal = normal, - Parent = parent, Sector = sector, - DetachableFragment = fragment }; public override void OnReceiveRemote(bool server, DropItemMessage message) { var worldObject = QSBWorldSync.GetWorldFromId(message.ObjectId); + worldObject.DropItem(message.Position, message.Normal, message.Sector); } } } diff --git a/QSB/ItemSync/Events/DropItemMessage.cs b/QSB/ItemSync/Events/DropItemMessage.cs index 0d882da4..18f1c465 100644 --- a/QSB/ItemSync/Events/DropItemMessage.cs +++ b/QSB/ItemSync/Events/DropItemMessage.cs @@ -11,9 +11,7 @@ namespace QSB.ItemSync.Events public int ObjectId { get; set; } public Vector3 Position { get; set; } public Vector3 Normal { get; set; } - public Transform Parent { get; set; } public Sector Sector { get; set; } - public DetachableFragment DetachableFragment { get; set; } public override void Deserialize(QNetworkReader reader) { diff --git a/QSB/ItemSync/ItemManager.cs b/QSB/ItemSync/ItemManager.cs index 508e1897..2cbb2afb 100644 --- a/QSB/ItemSync/ItemManager.cs +++ b/QSB/ItemSync/ItemManager.cs @@ -2,6 +2,7 @@ using QSB.ItemSync.WorldObjects; using QSB.Utility; using QSB.WorldSync; +using System.Collections.Generic; using UnityEngine; namespace QSB.ItemSync @@ -10,6 +11,8 @@ namespace QSB.ItemSync { public static ItemManager Instance { get; private set; } + private List _oldScrollList = new List(); + public void Awake() { Instance = this; @@ -21,8 +24,61 @@ namespace QSB.ItemSync public void RebuildItems(OWScene scene) { DebugLog.DebugWrite("Rebuilding OWItems...", MessageType.Warning); - QSBWorldSync.Init(); + _oldScrollList = QSBWorldSync.Init(); QSBWorldSync.Init(); } + + public static IQSBOWItem GetObject(OWItem unityObject) + { + IQSBOWItem worldObj = null; + if (unityObject.GetType() == typeof(ScrollItem)) + { + worldObj = QSBWorldSync.GetWorldFromUnity((ScrollItem)unityObject); + } + else if (unityObject.GetType() == typeof(NomaiConversationStone)) + { + //worldObj = QSBWorldSync.GetWorldFromUnity((MultiStateQuantumObject)unityObject); + } + else if (unityObject.GetType() == typeof(SharedStone)) + { + //worldObj = QSBWorldSync.GetWorldFromUnity((QuantumShuffleObject)unityObject); + } + else if (unityObject.GetType() == typeof(WarpCoreItem)) + { + //worldObj = QSBWorldSync.GetWorldFromUnity((QuantumShuffleObject)unityObject); + } + else + { + DebugLog.ToConsole($"Warning - couldn't work out type of OWITem {unityObject.name}.", MessageType.Warning); + } + return worldObj; + } + + public static IQSBOWItemSocket GetObject(OWItemSocket unityObject) + { + IQSBOWItemSocket worldObj = null; + if (unityObject.GetType() == typeof(ScrollItem)) + { + worldObj = QSBWorldSync.GetWorldFromUnity((ScrollSocket)unityObject); + } + else + { + DebugLog.ToConsole($"Warning - couldn't work out type of OWITemSocket {unityObject.name}.", MessageType.Warning); + } + return worldObj; + } + + public void OnRenderObject() + { + if (!QSBCore.HasWokenUp || !QSBCore.DebugMode || !QSBCore.ShowLinesInDebug) + { + return; + } + + foreach (var item in _oldScrollList) + { + Popcron.Gizmos.Cube(item.transform.position, item.transform.rotation, Vector3.one, Color.blue); + } + } } } diff --git a/QSB/ItemSync/Patches/ItemPatches.cs b/QSB/ItemSync/Patches/ItemPatches.cs index 45d021c7..c2ddde46 100644 --- a/QSB/ItemSync/Patches/ItemPatches.cs +++ b/QSB/ItemSync/Patches/ItemPatches.cs @@ -1,5 +1,7 @@ -using QSB.Patches; +using QSB.Events; +using QSB.Patches; using QSB.Utility; +using QSB.WorldSync; using System.Reflection; using UnityEngine; @@ -24,6 +26,7 @@ namespace QSB.ItemSync.Patches public static bool ItemTool_SocketItem(OWItem ____heldItem, OWItemSocket socket) { DebugLog.DebugWrite($"Socket item {____heldItem.name} into socket {socket.name}."); + var objectId = QSBWorldSync.GetIdFromTypeSubset(ItemManager.GetObject(socket)); return true; } @@ -62,10 +65,19 @@ namespace QSB.ItemSync.Patches var parent = (detachableFragment != null) ? detachableFragment.transform : targetRigidbody.transform; + var objectId = QSBWorldSync.GetIdFromTypeSubset(ItemManager.GetObject(____heldItem)); ____heldItem.DropItem(hit.point, hit.normal, parent, sector, detachableFragment); ____heldItem = null; Locator.GetToolModeSwapper().UnequipTool(); - DebugLog.DebugWrite($"Drop item at point:{hit.point}, normal:{hit.normal}, parent:{parent.name}, sector:{sector.name}, fragment:{detachableFragment?.name}."); + var parentSector = parent.GetComponentInChildren(); + if (parentSector != null) + { + var localPos = parentSector.transform.InverseTransformPoint(hit.point); + QSBEventManager.FireEvent(EventNames.QSBDropItem, objectId, localPos, hit.normal, parentSector); + return false; + } + var localPosition = sector.transform.InverseTransformPoint(hit.point); + QSBEventManager.FireEvent(EventNames.QSBDropItem, objectId, localPosition, hit.normal, sector); return false; } } diff --git a/QSB/ItemSync/WorldObjects/IQSBOWItem.cs b/QSB/ItemSync/WorldObjects/IQSBOWItem.cs index 166f61c1..a85d02a2 100644 --- a/QSB/ItemSync/WorldObjects/IQSBOWItem.cs +++ b/QSB/ItemSync/WorldObjects/IQSBOWItem.cs @@ -1,9 +1,10 @@ using QSB.WorldSync; +using UnityEngine; namespace QSB.ItemSync.WorldObjects { public interface IQSBOWItem : IWorldObjectTypeSubset { - uint HoldingPlayer { get; set; } + void DropItem(Vector3 position, Vector3 normal, Sector sector); } } diff --git a/QSB/ItemSync/WorldObjects/IQSBOWItemSocket.cs b/QSB/ItemSync/WorldObjects/IQSBOWItemSocket.cs index 03c970f4..d3aaf2df 100644 --- a/QSB/ItemSync/WorldObjects/IQSBOWItemSocket.cs +++ b/QSB/ItemSync/WorldObjects/IQSBOWItemSocket.cs @@ -1,7 +1,6 @@ -namespace QSB.ItemSync.WorldObjects -{ - public interface IQSBOWItemSocket - { +using QSB.WorldSync; - } +namespace QSB.ItemSync.WorldObjects +{ + public interface IQSBOWItemSocket : IWorldObjectTypeSubset { } } diff --git a/QSB/ItemSync/WorldObjects/QSBOWItem.cs b/QSB/ItemSync/WorldObjects/QSBOWItem.cs index 50f21d31..8483b666 100644 --- a/QSB/ItemSync/WorldObjects/QSBOWItem.cs +++ b/QSB/ItemSync/WorldObjects/QSBOWItem.cs @@ -1,12 +1,25 @@ -using QSB.WorldSync; +using OWML.Utils; +using QSB.WorldSync; +using UnityEngine; namespace QSB.ItemSync.WorldObjects { internal class QSBOWItem : WorldObject, IQSBOWItem where T : OWItem { - public uint HoldingPlayer { get; set; } - public override void Init(T attachedObject, int id) { } + + public virtual void DropItem(Vector3 position, Vector3 normal, Sector sector) + { + AttachedObject.transform.SetParent(sector.transform); + AttachedObject.transform.localScale = Vector3.one; + var localDropNormal = AttachedObject.GetValue("_localDropNormal"); + var lhs = Quaternion.FromToRotation(AttachedObject.transform.TransformDirection(localDropNormal), normal); + AttachedObject.transform.rotation = lhs * AttachedObject.transform.rotation; + var localDropOffset = AttachedObject.GetValue("_localDropOffset"); + AttachedObject.transform.position = sector.transform.TransformPoint(position) + AttachedObject.transform.TransformDirection(localDropOffset); + AttachedObject.SetSector(sector); + AttachedObject.SetColliderActivation(true); + } } } diff --git a/QSB/ItemSync/WorldObjects/QSBScrollItem.cs b/QSB/ItemSync/WorldObjects/QSBScrollItem.cs index e0552f95..55d77743 100644 --- a/QSB/ItemSync/WorldObjects/QSBScrollItem.cs +++ b/QSB/ItemSync/WorldObjects/QSBScrollItem.cs @@ -1,4 +1,6 @@ -namespace QSB.ItemSync.WorldObjects +using UnityEngine; + +namespace QSB.ItemSync.WorldObjects { internal class QSBScrollItem : QSBOWItem { diff --git a/QSB/OrbSync/OrbManager.cs b/QSB/OrbSync/OrbManager.cs index 093657b8..3186692b 100644 --- a/QSB/OrbSync/OrbManager.cs +++ b/QSB/OrbSync/OrbManager.cs @@ -43,8 +43,6 @@ namespace QSB.OrbSync foreach (var orb in QSBWorldSync.OldOrbList) { - Popcron.Gizmos.Cube(orb.transform.position, orb.transform.rotation, Vector3.one / 3); - var rails = orb.GetValue("_safetyRails"); if (rails.Length > 0) { diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj index d8b2dbbc..76ef6e7f 100644 --- a/QSB/QSB.csproj +++ b/QSB/QSB.csproj @@ -221,10 +221,12 @@ - + + + diff --git a/QSB/TransformSync/PlayerTransformSync.cs b/QSB/TransformSync/PlayerTransformSync.cs index 681ea322..e0528260 100644 --- a/QSB/TransformSync/PlayerTransformSync.cs +++ b/QSB/TransformSync/PlayerTransformSync.cs @@ -59,7 +59,6 @@ namespace QSB.TransformSync { return; } - Popcron.Gizmos.Cube(Player.Body.transform.position, Player.Body.transform.rotation, new Vector3(1, 2, 1)); Popcron.Gizmos.Line(ReferenceSector.Position, Player.Body.transform.position, Color.blue, true); Popcron.Gizmos.Sphere(ReferenceSector.Position, 5f, Color.cyan); } diff --git a/QSB/Utility/Callback6Args.cs b/QSB/Utility/Callback6Args.cs deleted file mode 100644 index 17e40867..00000000 --- a/QSB/Utility/Callback6Args.cs +++ /dev/null @@ -1 +0,0 @@ -public delegate void Callback(T arg1, U arg2, V arg3, W arg4, X arg5, Y arg6); \ No newline at end of file diff --git a/QSB/Utility/CustomCallbacks.cs b/QSB/Utility/CustomCallbacks.cs new file mode 100644 index 00000000..58e3d1b5 --- /dev/null +++ b/QSB/Utility/CustomCallbacks.cs @@ -0,0 +1,3 @@ +public delegate void Callback(T arg1, U arg2, V arg3, W arg4); +public delegate void Callback(T arg1, U arg2, V arg3, W arg4, X arg5); +public delegate void Callback(T arg1, U arg2, V arg3, W arg4, X arg5, Y arg6); \ No newline at end of file diff --git a/QSB/Utility/GlobalMessenger4Args.cs b/QSB/Utility/GlobalMessenger4Args.cs new file mode 100644 index 00000000..ccb4b448 --- /dev/null +++ b/QSB/Utility/GlobalMessenger4Args.cs @@ -0,0 +1,79 @@ +using OWML.Common; +using System; +using System.Collections.Generic; + +namespace QSB.Utility +{ + public static class GlobalMessenger + { + public static void AddListener(string eventType, Callback handler) + { + object obj = _eventTable; + lock (obj) + { + if (!_eventTable.TryGetValue(eventType, out var eventData)) + { + eventData = new EventData(); + _eventTable.Add(eventType, eventData); + } + eventData.Callbacks.Add(handler); + } + } + + public static void RemoveListener(string eventType, Callback handler) + { + object obj = _eventTable; + lock (obj) + { + if (_eventTable.TryGetValue(eventType, out var eventData)) + { + var num = eventData.Callbacks.IndexOf(handler); + if (num >= 0) + { + eventData.Callbacks[num] = eventData.Callbacks[eventData.Callbacks.Count - 1]; + eventData.Callbacks.RemoveAt(eventData.Callbacks.Count - 1); + } + } + } + } + + public static void FireEvent(string eventType, T arg1, U arg2, V arg3, W arg4) + { + object obj = _eventTable; + lock (obj) + { + if (_eventTable.TryGetValue(eventType, out var eventData)) + { + if (eventData.IsInvoking) + { + throw new InvalidOperationException("GlobalMessenger does not support recursive FireEvent calls to the same eventType."); + } + eventData.IsInvoking = true; + eventData.Temp.AddRange(eventData.Callbacks); + for (var i = 0; i < eventData.Temp.Count; i++) + { + try + { + eventData.Temp[i](arg1, arg2, arg3, arg4); + } + catch (Exception exception) + { + DebugLog.ToConsole($"Error - {exception.Message}", MessageType.Error); + } + } + eventData.Temp.Clear(); + eventData.IsInvoking = false; + } + } + } + + private static IDictionary _eventTable = new Dictionary(ComparerLibrary.stringEqComparer); + + private class EventData + { + public List> Callbacks = new List>(); + public List> Temp = new List>(); + public bool IsInvoking; + } + } +} diff --git a/QSB/Utility/GlobalMessenger5Args.cs b/QSB/Utility/GlobalMessenger5Args.cs new file mode 100644 index 00000000..3727252d --- /dev/null +++ b/QSB/Utility/GlobalMessenger5Args.cs @@ -0,0 +1,79 @@ +using OWML.Common; +using System; +using System.Collections.Generic; + +namespace QSB.Utility +{ + public static class GlobalMessenger + { + public static void AddListener(string eventType, Callback handler) + { + object obj = _eventTable; + lock (obj) + { + if (!_eventTable.TryGetValue(eventType, out var eventData)) + { + eventData = new EventData(); + _eventTable.Add(eventType, eventData); + } + eventData.Callbacks.Add(handler); + } + } + + public static void RemoveListener(string eventType, Callback handler) + { + object obj = _eventTable; + lock (obj) + { + if (_eventTable.TryGetValue(eventType, out var eventData)) + { + var num = eventData.Callbacks.IndexOf(handler); + if (num >= 0) + { + eventData.Callbacks[num] = eventData.Callbacks[eventData.Callbacks.Count - 1]; + eventData.Callbacks.RemoveAt(eventData.Callbacks.Count - 1); + } + } + } + } + + public static void FireEvent(string eventType, T arg1, U arg2, V arg3, W arg4, X arg5) + { + object obj = _eventTable; + lock (obj) + { + if (_eventTable.TryGetValue(eventType, out var eventData)) + { + if (eventData.IsInvoking) + { + throw new InvalidOperationException("GlobalMessenger does not support recursive FireEvent calls to the same eventType."); + } + eventData.IsInvoking = true; + eventData.Temp.AddRange(eventData.Callbacks); + for (var i = 0; i < eventData.Temp.Count; i++) + { + try + { + eventData.Temp[i](arg1, arg2, arg3, arg4, arg5); + } + catch (Exception exception) + { + DebugLog.ToConsole($"Error - {exception.Message}", MessageType.Error); + } + } + eventData.Temp.Clear(); + eventData.IsInvoking = false; + } + } + } + + private static IDictionary _eventTable = new Dictionary(ComparerLibrary.stringEqComparer); + + private class EventData + { + public List> Callbacks = new List>(); + public List> Temp = new List>(); + public bool IsInvoking; + } + } +}