Merge pull request #129 from Raicuparta/nebula/event-overhaul

Event Overhaul
This commit is contained in:
Mister_Nebula 2020-08-10 19:59:48 +01:00 committed by GitHub
commit 95d15ed805
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 991 additions and 755 deletions

View File

@ -1,5 +1,6 @@
using System;
using OWML.ModHelper.Events;
using QSB.Events;
using QSB.Messaging;
using UnityEngine;
using UnityEngine.Networking;
@ -62,7 +63,7 @@ namespace QSB.Animation
{
InitCommon(body);
_triggerHandler = new MessageHandler<AnimTriggerMessage>();
_triggerHandler = new MessageHandler<AnimTriggerMessage>(MessageType.AnimTrigger);
_triggerHandler.OnServerReceiveMessage += OnServerReceiveMessage;
_triggerHandler.OnClientReceiveMessage += OnClientReceiveMessage;
@ -71,8 +72,8 @@ namespace QSB.Animation
_playerController.OnBecomeGrounded += OnBecomeGrounded;
_playerController.OnBecomeUngrounded += OnBecomeUngrounded;
GlobalMessenger.AddListener("SuitUp", OnSuitUp);
GlobalMessenger.AddListener("RemoveSuit", OnSuitDown);
GlobalMessenger.AddListener(EventNames.SuitUp, OnSuitUp);
GlobalMessenger.AddListener(EventNames.RemoveSuit, OnSuitDown);
}
public void InitRemote(Transform body)
@ -160,14 +161,10 @@ namespace QSB.Animation
_bodyAnim.SetTrigger(trigger.ToString());
break;
case AnimTrigger.SuitUp:
_bodyAnim.runtimeAnimatorController = _suitedAnimController;
_unsuitedGraphics.SetActive(false);
_suitedGraphics.SetActive(true);
SuitUp();
break;
case AnimTrigger.SuitDown:
_bodyAnim.runtimeAnimatorController = _unsuitedAnimController;
_unsuitedGraphics.SetActive(true);
_suitedGraphics.SetActive(false);
SuitDown();
break;
case AnimTrigger.Crouch:
_crouchParam.Target = value;
@ -177,6 +174,20 @@ namespace QSB.Animation
}
}
public void SuitUp()
{
_bodyAnim.runtimeAnimatorController = _suitedAnimController;
_unsuitedGraphics.SetActive(false);
_suitedGraphics.SetActive(true);
}
public void SuitDown()
{
_bodyAnim.runtimeAnimatorController = _unsuitedAnimController;
_unsuitedGraphics.SetActive(true);
_suitedGraphics.SetActive(false);
}
private void Update()
{
if (isLocalPlayer)

View File

@ -1,103 +0,0 @@
using System.Collections;
using QSB.Messaging;
using QSB.TransformSync;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.Events
{
public class EventHandler : NetworkBehaviour
{
public static EventHandler LocalInstance;
private MessageHandler<EventMessage> _eventHandler;
private void Awake()
{
LocalInstance = this;
_eventHandler = new MessageHandler<EventMessage>();
_eventHandler.OnClientReceiveMessage += OnClientReceiveMessage;
_eventHandler.OnServerReceiveMessage += OnServerReceiveMessage;
}
public void Send(EventType eventType)
{
StartCoroutine(SendEvent(eventType));
}
private IEnumerator SendEvent(EventType eventType)
{
yield return new WaitUntil(() => PlayerTransformSync.LocalInstance != null);
var message = new EventMessage
{
EventType = (int)eventType,
SenderId = PlayerTransformSync.LocalInstance.netId.Value
};
_eventHandler.SendToServer(message);
}
private void OnServerReceiveMessage(EventMessage message)
{
_eventHandler.SendToAll(message);
}
private void OnClientReceiveMessage(EventMessage message)
{
var player = PlayerRegistry.GetPlayer(message.SenderId);
if (message.SenderId == PlayerRegistry.LocalPlayer.NetId)
{
return;
}
switch ((EventType)message.EventType)
{
case EventType.TurnOnFlashlight:
player.UpdateState(State.Flashlight, true);
player.FlashLight.TurnOn();
break;
case EventType.TurnOffFlashlight:
player.UpdateState(State.Flashlight, false);
player.FlashLight.TurnOff();
break;
case EventType.SuitUp:
player.UpdateState(State.Suit, true);
break;
case EventType.RemoveSuit:
player.UpdateState(State.Suit, false);
break;
case EventType.EquipSignalscope:
player.UpdateState(State.Signalscope, true);
player.Signalscope.EquipTool();
break;
case EventType.UnequipSignalscope:
player.UpdateState(State.Signalscope, false);
player.Signalscope.UnequipTool();
break;
case EventType.EquipTranslator:
player.UpdateState(State.Translator, true);
player.Translator.EquipTool();
break;
case EventType.UnequipTranslator:
player.UpdateState(State.Translator, false);
player.Translator.UnequipTool();
break;
case EventType.ProbeLauncherEquipped:
player.UpdateState(State.ProbeLauncher, true);
player.ProbeLauncher.EquipTool();
break;
case EventType.ProbeLauncherUnequipped:
player.UpdateState(State.ProbeLauncher, false);
player.ProbeLauncher.UnequipTool();
break;
case EventType.RetrieveProbe:
player.UpdateState(State.ProbeActive, false);
player.Probe.Deactivate();
break;
case EventType.LaunchProbe:
player.UpdateState(State.ProbeActive, true);
player.Probe.Activate();
break;
}
}
}
}

28
QSB/Events/EventList.cs Normal file
View File

@ -0,0 +1,28 @@
namespace QSB.Events
{
/// <summary>
/// Creates instances of all of the events QSB uses.
/// </summary>
public static class EventList
{
public static bool Ready { get; private set; }
public static void Init()
{
new PlayerReadyEvent();
new PlayerSuitEvent();
new PlayerFlashlightEvent();
new PlayerSignalscopeEvent();
new PlayerTranslatorEvent();
new PlayerProbeLauncherEvent();
new PlayerProbeEvent();
new PlayerSectorEvent();
new PlayerJoinEvent();
new PlayerLeaveEvent();
new PlayerDeathEvent();
new PlayerStatesRequestEvent();
Ready = true;
}
}
}

View File

@ -1,112 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace QSB.Events
{
public class EventListener : MonoBehaviour
{
private readonly Dictionary<EventType, List<Type>> _typedList = new Dictionary<EventType, List<Type>>
{
{ EventType.EquipSignalscope, new List<Type> { typeof(Signalscope)} },
{ EventType.ProbeLauncherEquipped, new List<Type> { typeof(ProbeLauncher) } },
{ EventType.ProbeLauncherUnequipped, new List<Type> { typeof(ProbeLauncher) } },
{ EventType.RetrieveProbe, new List<Type> { typeof(SurveyorProbe) } },
{ EventType.LaunchProbe, new List<Type> { typeof(SurveyorProbe) } }
};
private void Awake()
{
foreach (var item in Enum.GetNames(typeof(EventType)))
{
if (!_typedList.Keys.Contains((EventType)Enum.Parse(typeof(EventType), item)))
{
GlobalMessenger.AddListener(item, () => SendEvent(item));
}
}
foreach (var item in _typedList)
{
InvokeGenericMethod(item.Key, item.Value);
}
}
private void InvokeGenericMethod(EventType eventType, List<Type> items)
{
var oldMethod = GetGenericMethod(typeof(EventListener), "Listen", items.Count);
var newMethod = oldMethod.MakeGenericMethod(items.ToArray());
newMethod.Invoke(this, new[] { (object)Enum.GetName(typeof(EventType), eventType) });
}
private void SendEvent(string eventName)
{
var eventType = (EventType)Enum.Parse(typeof(EventType), eventName);
var player = PlayerRegistry.LocalPlayer;
EventHandler.LocalInstance.Send(eventType);
switch (eventType)
{
case EventType.TurnOnFlashlight:
player.UpdateState(State.Flashlight, true);
break;
case EventType.TurnOffFlashlight:
player.UpdateState(State.Flashlight, false);
break;
case EventType.SuitUp:
player.UpdateState(State.Suit, true);
break;
case EventType.RemoveSuit:
player.UpdateState(State.Suit, false);
break;
case EventType.EquipSignalscope:
player.UpdateState(State.Signalscope, true);
break;
case EventType.UnequipSignalscope:
player.UpdateState(State.Signalscope, false);
break;
case EventType.EquipTranslator:
player.UpdateState(State.Translator, true);
break;
case EventType.UnequipTranslator:
player.UpdateState(State.Translator, false);
break;
case EventType.ProbeLauncherEquipped:
player.UpdateState(State.ProbeLauncher, true);
break;
case EventType.ProbeLauncherUnequipped:
player.UpdateState(State.ProbeLauncher, false);
break;
case EventType.RetrieveProbe:
player.UpdateState(State.ProbeActive, false);
break;
case EventType.LaunchProbe:
player.UpdateState(State.ProbeActive, true);
break;
}
}
public void Listen<T>(string eventName)
{
GlobalMessenger<T>.AddListener(eventName, var => SendEvent(eventName));
}
public void Listen<T, TU>(string eventName)
{
GlobalMessenger<T, TU>.AddListener(eventName, (var, var2) => SendEvent(eventName));
}
private MethodInfo GetGenericMethod(Type type, string methodName, int typeCount)
{
var methods = type.GetMethods()
.Where(m => m.Name == methodName && m.IsGenericMethodDefinition)
.Select(m => new { m, typeParams = m.GetGenericArguments() })
.Select(t => new { t, normalParams = t.m.GetParameters() })
.Where(t => t.t.typeParams.Length == typeCount)
.Select(t => t.t.m);
return methods.Single();
}
}
}

View File

@ -1,24 +0,0 @@
using QSB.Messaging;
using UnityEngine.Networking;
namespace QSB.Events
{
public class EventMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.Event;
public int EventType { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
EventType = reader.ReadInt32();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(EventType);
}
}
}

31
QSB/Events/EventNames.cs Normal file
View File

@ -0,0 +1,31 @@
namespace QSB.Events
{
public static class EventNames
{
public static string TurnOnFlashlight = "TurnOnFlashlight";
public static string TurnOffFlashlight = "TurnOffFlashlight";
public static string LaunchProbe = "LaunchProbe";
public static string RetrieveProbe = "RetrieveProbe";
public static string ProbeLauncherEquipped = "ProbeLauncherEquipped";
public static string ProbeLauncherUnequipped = "ProbeLauncherUnequipped";
public static string EquipSignalscope = "EquipSignalscope";
public static string UnequipSignalscope = "UnequipSignalscope";
public static string SuitUp = "SuitUp";
public static string RemoveSuit = "RemoveSuit";
public static string EquipTranslator = "EquipTranslator";
public static string UnequipTranslator = "UnequipTranslator";
public static string ExitShip = "ExitShip";
public static string RestartTimeLoop = "RestartTimeLoop";
public static string WakeUp = "WakeUp";
public static string QSBPlayerDeath = "QSBPlayerDeath";
public static string QSBPlayerJoin = "QSBPlayerJoin";
public static string QSBPlayerLeave = "QSBPlayerLeave";
public static string QSBPlayerReady = "QSBPlayerReady";
public static string QSBSectorChange = "QSBSectorChange";
public static string QSBPlayerStatesRequest = "QSBPlayerStatesRequest";
public static string QSBServerTime = "QSBServerTime";
public static string QSBOnProbeAnchor = "QSBOnProbeAnchor";
public static string QSBOnProbeWarp = "QSBOnProbeWarp";
}
}

View File

@ -1,20 +0,0 @@
namespace QSB.Events
{
public enum EventType
{
TurnOnFlashlight,
TurnOffFlashlight,
SuitUp,
RemoveSuit,
EquipSignalscope,
UnequipSignalscope,
EquipTranslator,
UnequipTranslator,
ProbeLauncherEquipped,
ProbeLauncherUnequipped,
RetrieveProbe,
LaunchProbe,
QSBOnProbeWarp,
QSBOnProbeAnchor
}
}

View File

@ -1,43 +0,0 @@
using System.Collections;
using QSB.Messaging;
using QSB.TransformSync;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.Events
{
public class FullStateRequest : NetworkBehaviour
{
public static FullStateRequest Instance { get; private set; }
private MessageHandler<StateRequestMessage> _stateRequestHandler;
private void Awake()
{
Instance = this;
_stateRequestHandler = new MessageHandler<StateRequestMessage>();
_stateRequestHandler.OnServerReceiveMessage += OnServerReceiveMessage;
}
public void Request()
{
StartCoroutine(SendRequest());
}
private IEnumerator SendRequest()
{
yield return new WaitUntil(() => PlayerTransformSync.LocalInstance != null);
var message = new StateRequestMessage
{
SenderId = PlayerTransformSync.LocalInstance.netId.Value
};
_stateRequestHandler.SendToServer(message);
}
private void OnServerReceiveMessage(StateRequestMessage message)
{
GameState.LocalInstance.Send();
}
}
}

View File

@ -1,39 +0,0 @@
using QSB.Messaging;
using UnityEngine.Networking;
namespace QSB.Events
{
public class GameState : NetworkBehaviour
{
public static GameState LocalInstance { get; private set; }
private MessageHandler<FullStateMessage> _messageHandler;
private void Awake()
{
_messageHandler = new MessageHandler<FullStateMessage>();
_messageHandler.OnClientReceiveMessage += OnClientReceiveMessage;
LocalInstance = this;
}
private void OnClientReceiveMessage(FullStateMessage message)
{
PlayerRegistry.HandleFullStateMessage(message);
}
public void Send()
{
foreach (var player in PlayerRegistry.PlayerList)
{
var message = new FullStateMessage
{
PlayerName = player.Name,
SenderId = player.NetId
};
_messageHandler.SendToAll(message);
}
}
}
}

View File

@ -93,7 +93,7 @@ namespace QSB.Events
"{0} chased their memories"
} }
};
public static string GetPhrase(DeathType deathType)
{
return DeathDictionary[deathType].OrderBy(x => Guid.NewGuid()).First();

View File

@ -0,0 +1,28 @@
using QSB.Messaging;
using QSB.Utility;
namespace QSB.Events
{
public class PlayerDeathEvent : QSBEvent<PlayerDeathMessage>
{
public override MessageType Type => MessageType.PlayerDeath;
public override void SetupListener()
{
GlobalMessenger<DeathType>.AddListener(EventNames.QSBPlayerDeath, type => SendEvent(CreateMessage(type)));
}
private PlayerDeathMessage CreateMessage(DeathType type) => new PlayerDeathMessage
{
SenderId = LocalPlayerId,
DeathType = type
};
public override void OnReceiveRemote(PlayerDeathMessage message)
{
var playerName = PlayerRegistry.GetPlayer(message.SenderId).Name;
var deathMessage = Necronomicon.GetPhrase(message.DeathType);
DebugLog.ToAll(string.Format(deathMessage, playerName));
}
}
}

View File

@ -0,0 +1,37 @@
using QSB.Messaging;
namespace QSB.Events
{
public class PlayerFlashlightEvent : QSBEvent<ToggleMessage>
{
public override MessageType Type => MessageType.FlashlightActiveChange;
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.TurnOnFlashlight, () => SendEvent(CreateMessage(true)));
GlobalMessenger.AddListener(EventNames.TurnOffFlashlight, () => SendEvent(CreateMessage(false)));
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
SenderId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveRemote(ToggleMessage message)
{
var player = PlayerRegistry.GetPlayer(message.SenderId);
player.UpdateState(State.Flashlight, message.ToggleValue);
if (!IsInUniverse)
{
return;
}
player.FlashLight?.UpdateState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
PlayerRegistry.LocalPlayer.UpdateState(State.Flashlight, message.ToggleValue);
}
}
}

View File

@ -1,54 +0,0 @@
using System.Collections;
using QSB.Messaging;
using QSB.TransformSync;
using QSB.Utility;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.Events
{
public class PlayerJoin : NetworkBehaviour
{
public static string MyName { get; private set; }
private MessageHandler<JoinMessage> _joinHandler;
private void Awake()
{
_joinHandler = new MessageHandler<JoinMessage>();
_joinHandler.OnClientReceiveMessage += OnClientReceiveMessage;
_joinHandler.OnServerReceiveMessage += OnServerReceiveMessage;
}
// Called when joining a server
public void Join(string playerName)
{
MyName = playerName;
StartCoroutine(SendJoinMessage(playerName));
}
// Send join message with player name and ID
private IEnumerator SendJoinMessage(string playerName)
{
yield return new WaitUntil(() => PlayerTransformSync.LocalInstance != null);
var message = new JoinMessage
{
PlayerName = playerName,
SenderId = PlayerTransformSync.LocalInstance.netId.Value
};
_joinHandler.SendToServer(message);
}
private void OnServerReceiveMessage(JoinMessage message)
{
_joinHandler.SendToAll(message);
}
private void OnClientReceiveMessage(JoinMessage message)
{
var player = PlayerRegistry.CreatePlayer(message.SenderId);
player.Name = message.PlayerName;
DebugLog.ToAll(message.PlayerName, "joined!");
}
}
}

View File

@ -0,0 +1,38 @@
using QSB.Messaging;
using QSB.TransformSync;
using QSB.Utility;
namespace QSB.Events
{
public class PlayerJoinEvent : QSBEvent<PlayerJoinMessage>
{
public override MessageType Type => MessageType.PlayerJoin;
public override void SetupListener()
{
GlobalMessenger<string>.AddListener(EventNames.QSBPlayerJoin, name => SendEvent(CreateMessage(name)));
}
private PlayerJoinMessage CreateMessage(string name) => new PlayerJoinMessage
{
SenderId = PlayerTransformSync.LocalInstance.netId.Value,
PlayerName = name
};
public override void OnReceiveRemote(PlayerJoinMessage message)
{
var player = PlayerRegistry.CreatePlayer(message.SenderId);
player.Name = message.PlayerName;
var text = $"{player.Name} joined!";
DebugLog.ToAll(OWML.Common.MessageType.Info, text);
}
public override void OnReceiveLocal(PlayerJoinMessage message)
{
var player = PlayerRegistry.CreatePlayer(PlayerTransformSync.LocalInstance.netId.Value);
player.Name = message.PlayerName;
var text = $"Connected to server as {player.Name}.";
DebugLog.ToAll(OWML.Common.MessageType.Info, text);
}
}
}

View File

@ -1,60 +0,0 @@
using System.Linq;
using QSB.Messaging;
using QSB.Utility;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.Events
{
/// <summary>
/// Client-only-side component for managing player leaves.
/// </summary>
public class PlayerLeave : NetworkBehaviour
{
private MessageHandler<LeaveMessage> _leaveHandler;
private void Awake()
{
_leaveHandler = new MessageHandler<LeaveMessage>();
_leaveHandler.OnClientReceiveMessage += OnClientReceiveMessage;
}
public void Leave(uint playerId, uint[] objectIds)
{
var message = new LeaveMessage
{
SenderId = playerId,
ObjectIds = objectIds
};
_leaveHandler.SendToAll(message);
}
private void OnClientReceiveMessage(LeaveMessage message)
{
var playerName = PlayerRegistry.GetPlayer(message.SenderId).Name;
DebugLog.ToAll(playerName, "disconnected.");
PlayerRegistry.RemovePlayer(message.SenderId);
foreach (var objectId in message.ObjectIds)
{
DestroyObject(objectId);
}
}
private void DestroyObject(uint objectId)
{
var component = GameObject.FindObjectsOfType<NetworkBehaviour>()
.FirstOrDefault(x => x.netId.Value == objectId);
if (component == null)
{
return;
}
var transformSync = component.GetComponent<TransformSync.TransformSync>();
if (transformSync != null)
{
Destroy(transformSync.SyncedTransform.gameObject);
}
Destroy(component.gameObject);
}
}
}

View File

@ -0,0 +1,51 @@
using QSB.Messaging;
using QSB.Utility;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.Events
{
public class PlayerLeaveEvent : QSBEvent<PlayerLeaveMessage>
{
public override MessageType Type => MessageType.PlayerLeave;
public override void SetupListener()
{
GlobalMessenger<uint, uint[]>.AddListener(EventNames.QSBPlayerLeave, (id, objects) => SendEvent(CreateMessage(id, objects)));
}
private PlayerLeaveMessage CreateMessage(uint id, uint[] objects) => new PlayerLeaveMessage
{
SenderId = id,
ObjectIds = objects
};
public override void OnReceiveRemote(PlayerLeaveMessage message)
{
var playerName = PlayerRegistry.GetPlayer(message.SenderId).Name;
DebugLog.ToAll(playerName, "disconnected.");
PlayerRegistry.RemovePlayer(message.SenderId);
foreach (var objectId in message.ObjectIds)
{
DestroyObject(objectId);
}
}
private void DestroyObject(uint objectId)
{
var component = Object.FindObjectsOfType<NetworkBehaviour>()
.FirstOrDefault(x => x.netId.Value == objectId);
if (component == null)
{
return;
}
var transformSync = component.GetComponent<TransformSync.TransformSync>();
if (transformSync != null)
{
Object.Destroy(transformSync.SyncedTransform.gameObject);
}
Object.Destroy(component.gameObject);
}
}
}

View File

@ -0,0 +1,33 @@
using QSB.Messaging;
namespace QSB.Events
{
public class PlayerProbeEvent : QSBEvent<ToggleMessage>
{
public override MessageType Type => MessageType.ProbeActiveChange;
public override void SetupListener()
{
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.LaunchProbe, probe => SendEvent(CreateMessage(true)));
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.RetrieveProbe, probe => SendEvent(CreateMessage(false)));
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
SenderId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveRemote(ToggleMessage message)
{
var player = PlayerRegistry.GetPlayer(message.SenderId);
player.UpdateState(State.ProbeActive, message.ToggleValue);
player.Probe.SetState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
PlayerRegistry.LocalPlayer.UpdateState(State.ProbeActive, message.ToggleValue);
}
}
}

View File

@ -0,0 +1,38 @@
using QSB.Messaging;
using QSB.Utility;
namespace QSB.Events
{
public class PlayerProbeLauncherEvent : QSBEvent<ToggleMessage>
{
public override MessageType Type => MessageType.ProbeLauncherActiveChange;
public override void SetupListener()
{
GlobalMessenger<ProbeLauncher>.AddListener(EventNames.ProbeLauncherEquipped, var => SendEvent(CreateMessage(true)));
GlobalMessenger<ProbeLauncher>.AddListener(EventNames.ProbeLauncherUnequipped, var => SendEvent(CreateMessage(false)));
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
SenderId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveRemote(ToggleMessage message)
{
var player = PlayerRegistry.GetPlayer(message.SenderId);
player.UpdateState(State.ProbeLauncher, message.ToggleValue);
if (!IsInUniverse)
{
return;
}
player.ProbeLauncher?.ChangeEquipState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
PlayerRegistry.LocalPlayer.UpdateState(State.ProbeLauncher, message.ToggleValue);
}
}
}

View File

@ -0,0 +1,26 @@
using QSB.Messaging;
namespace QSB.Events
{
public class PlayerReadyEvent : QSBEvent<ToggleMessage>
{
public override MessageType Type => MessageType.PlayerReady;
public override void SetupListener()
{
GlobalMessenger<bool>.AddListener(EventNames.QSBPlayerReady, ready => SendEvent(CreateMessage(ready)));
}
private ToggleMessage CreateMessage(bool ready) => new ToggleMessage
{
SenderId = LocalPlayerId,
ToggleValue = ready
};
public override void OnServerReceive(ToggleMessage message)
{
PlayerRegistry.GetPlayer(message.SenderId).IsReady = message.ToggleValue;
PlayerState.LocalInstance.Send();
}
}
}

View File

@ -0,0 +1,42 @@
using QSB.Messaging;
using QSB.TransformSync;
using QSB.Utility;
namespace QSB.Events
{
public class PlayerSectorEvent : QSBEvent<SectorMessage>
{
public override MessageType Type => MessageType.PlayerSectorChange;
public override void SetupListener()
{
GlobalMessenger<uint, Sector.Name, string>.AddListener(EventNames.QSBSectorChange, (netId, sectorId, sectorName) => SendEvent(CreateMessage(netId, sectorId, sectorName)));
}
private SectorMessage CreateMessage(uint netId, Sector.Name sectorId, string sectorName) => new SectorMessage
{
SenderId = netId,
SectorId = sectorId,
SectorName = sectorName
};
public override void OnReceiveRemote(SectorMessage message)
{
if (!IsInUniverse)
{
return;
}
var sector = SectorSync.LocalInstance.FindSectorByName(message.SectorId, message.SectorName);
if (sector == null)
{
DebugLog.ToScreen($"Sector {message.SectorName}, {message.SectorId} not found!");
return;
}
var transformSync = PlayerRegistry.GetTransformSync(message.SenderId);
DebugLog.ToScreen($"{transformSync.GetType().Name} of ID {message.SenderId} set to {message.SectorName}");
transformSync.ReferenceTransform = sector.transform;
}
}
}

View File

@ -0,0 +1,38 @@
using QSB.Messaging;
using QSB.Utility;
namespace QSB.Events
{
public class PlayerSignalscopeEvent : QSBEvent<ToggleMessage>
{
public override MessageType Type => MessageType.SignalscopeActiveChange;
public override void SetupListener()
{
GlobalMessenger<Signalscope>.AddListener(EventNames.EquipSignalscope, var => SendEvent(CreateMessage(true)));
GlobalMessenger.AddListener(EventNames.UnequipSignalscope, () => SendEvent(CreateMessage(false)));
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
SenderId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveRemote(ToggleMessage message)
{
var player = PlayerRegistry.GetPlayer(message.SenderId);
player.UpdateState(State.Signalscope, message.ToggleValue);
if (!IsInUniverse)
{
return;
}
player.Signalscope?.ChangeEquipState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
PlayerRegistry.LocalPlayer.UpdateState(State.Signalscope, message.ToggleValue);
}
}
}

48
QSB/Events/PlayerState.cs Normal file
View File

@ -0,0 +1,48 @@
using QSB.Messaging;
using QSB.TransformSync;
using QSB.Utility;
using UnityEngine.Networking;
namespace QSB.Events
{
public class PlayerState : NetworkBehaviour
{
public static PlayerState LocalInstance { get; private set; }
private MessageHandler<PlayerStateMessage> _messageHandler;
private void Awake()
{
_messageHandler = new MessageHandler<PlayerStateMessage>(MessageType.FullState);
_messageHandler.OnClientReceiveMessage += OnClientReceiveMessage;
LocalInstance = this;
}
private void OnClientReceiveMessage(PlayerStateMessage message)
{
if (message.SenderId == PlayerTransformSync.LocalInstance.netId.Value)
{
return;
}
UnityHelper.Instance.RunWhen(() => PlayerRegistry.GetTransformSync(message.SenderId) != null,
() => PlayerRegistry.HandleFullStateMessage(message));
}
public void Send()
{
foreach (var player in PlayerRegistry.PlayerList)
{
var message = new PlayerStateMessage
{
SenderId = player.NetId,
PlayerName = player.Name,
PlayerReady = player.IsReady,
PlayerState = player.State
};
_messageHandler.SendToAll(message);
}
}
}
}

View File

@ -0,0 +1,25 @@
using QSB.Messaging;
using QSB.TransformSync;
namespace QSB.Events
{
public class PlayerStatesRequestEvent : QSBEvent<PlayerMessage>
{
public override MessageType Type => MessageType.FullStateRequest;
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.QSBPlayerStatesRequest, () => SendEvent(CreateMessage()));
}
private PlayerMessage CreateMessage() => new PlayerMessage
{
SenderId = PlayerTransformSync.LocalInstance.netId.Value
};
public override void OnServerReceive(PlayerMessage message)
{
PlayerState.LocalInstance.Send();
}
}
}

View File

@ -0,0 +1,32 @@
using QSB.Messaging;
namespace QSB.Events
{
public class PlayerSuitEvent : QSBEvent<ToggleMessage>
{
public override MessageType Type => MessageType.SuitActiveChange;
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.SuitUp, () => SendEvent(CreateMessage(true)));
GlobalMessenger.AddListener(EventNames.RemoveSuit, () => SendEvent(CreateMessage(false)));
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
SenderId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveRemote(ToggleMessage message)
{
var player = PlayerRegistry.GetPlayer(message.SenderId);
player.UpdateState(State.Suit, message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
PlayerRegistry.LocalPlayer.UpdateState(State.Suit, message.ToggleValue);
}
}
}

View File

@ -0,0 +1,38 @@
using QSB.Messaging;
using QSB.Utility;
namespace QSB.Events
{
public class PlayerTranslatorEvent : QSBEvent<ToggleMessage>
{
public override MessageType Type => MessageType.TranslatorActiveChange;
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.EquipTranslator, () => SendEvent(CreateMessage(true)));
GlobalMessenger.AddListener(EventNames.UnequipTranslator, () => SendEvent(CreateMessage(false)));
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
SenderId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveRemote(ToggleMessage message)
{
var player = PlayerRegistry.GetPlayer(message.SenderId);
player.UpdateState(State.Translator, message.ToggleValue);
if (!IsInUniverse)
{
return;
}
player.Translator?.ChangeEquipState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
PlayerRegistry.LocalPlayer.UpdateState(State.Translator, message.ToggleValue);
}
}
}

86
QSB/Events/QSBEvent.cs Normal file
View File

@ -0,0 +1,86 @@
using QSB.Messaging;
using QSB.TransformSync;
using QSB.Utility;
namespace QSB.Events
{
/// <summary>
/// Abstract class that handles all event code.
/// </summary>
/// <typeparam name="T">The message type to use.</typeparam>
public abstract class QSBEvent<T> where T : PlayerMessage, new()
{
public abstract MessageType Type { get; }
public uint LocalPlayerId => PlayerRegistry.LocalPlayer.NetId;
private readonly MessageHandler<T> _eventHandler;
protected bool IsInUniverse { get; private set; }
protected QSBEvent()
{
_eventHandler = new MessageHandler<T>(Type);
_eventHandler.OnClientReceiveMessage += OnClientReceive;
_eventHandler.OnServerReceiveMessage += OnServerReceive;
SetupListener();
LoadManager.OnCompleteSceneLoad += OnCompleteSceneLoad;
}
private void OnCompleteSceneLoad(OWScene oldScene, OWScene newScene)
{
IsInUniverse = newScene == OWScene.SolarSystem || newScene == OWScene.EyeOfTheUniverse;
}
/// <summary>
/// Called to set up the activators for the event.
/// </summary>
public abstract void SetupListener();
/// <summary>
/// Called on every client that didn't send the event.
/// </summary>
/// <param name="message"></param>
public virtual void OnReceiveRemote(T message)
{
}
/// <summary>
/// Called on the client that sent the event.
/// </summary>
/// <param name="message"></param>
public virtual void OnReceiveLocal(T message)
{
OnReceiveRemote(message);
}
/// <summary>
/// Called on the server.
/// </summary>
/// <param name="message"></param>
public virtual void OnServerReceive(T message)
{
_eventHandler.SendToAll(message);
}
public void SendEvent(T message)
{
UnityHelper.Instance.RunWhen(() => PlayerTransformSync.LocalInstance != null, () => Send(message));
}
private void Send(T message)
{
_eventHandler.SendToServer(message);
}
private void OnClientReceive(T message)
{
if (message.SenderId == PlayerTransformSync.LocalInstance?.netId.Value)
{
OnReceiveLocal(message);
return;
}
OnReceiveRemote(message);
}
}
}

View File

@ -0,0 +1,27 @@
using QSB.Messaging;
using QSB.TimeSync;
namespace QSB.Events
{
public class ServerTimeEvent : QSBEvent<ServerTimeMessage>
{
public override MessageType Type => MessageType.ServerTime;
public override void SetupListener()
{
GlobalMessenger<float, int>.AddListener(EventNames.QSBServerTime, (time, count) => SendEvent(CreateMessage(time, count)));
}
private ServerTimeMessage CreateMessage(float time, int count) => new ServerTimeMessage
{
SenderId = PlayerRegistry.LocalPlayer.NetId,
ServerTime = time,
LoopCount = count
};
public override void OnReceiveRemote(ServerTimeMessage message)
{
WakeUpSync.LocalInstance.OnClientReceiveMessage(message);
}
}
}

View File

@ -1,9 +0,0 @@
using QSB.Messaging;
namespace QSB.Events
{
public class StateRequestMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.FullStateRequest;
}
}

View File

@ -1,28 +1,24 @@
using QSB.Messaging;
using UnityEngine.Networking;
using UnityEngine.Networking;
namespace QSB.Animation
namespace QSB.Messaging
{
public class AnimTriggerMessage : QSBMessage
public class AnimTriggerMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.AnimTrigger;
public short TriggerId;
public uint SenderId;
public float Value;
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
Value = reader.ReadSingle();
TriggerId = reader.ReadInt16();
SenderId = reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(Value);
writer.Write(TriggerId);
writer.Write(SenderId);
}
}
}

View File

@ -4,13 +4,16 @@ using UnityEngine.Networking;
namespace QSB.Messaging
{
// Extend this to create new message handlers.
public class MessageHandler<T> where T : QSBMessage, new()
public class MessageHandler<T> where T : MessageBase, new()
{
public event Action<T> OnClientReceiveMessage;
public event Action<T> OnServerReceiveMessage;
public MessageHandler()
private readonly MessageType _messageType;
public MessageHandler(MessageType messageType)
{
_messageType = messageType + 1 + MsgType.Highest;
if (QSBNetworkManager.IsReady)
{
Init();
@ -23,9 +26,8 @@ namespace QSB.Messaging
private void Init()
{
var message = (T)Activator.CreateInstance(typeof(T));
NetworkServer.RegisterHandler((short)message.MessageType, OnServerReceiveMessageHandler);
NetworkManager.singleton.client.RegisterHandler((short)message.MessageType, OnClientReceiveMessageHandler);
NetworkServer.RegisterHandler((short)_messageType, OnServerReceiveMessageHandler);
NetworkManager.singleton.client.RegisterHandler((short)_messageType, OnClientReceiveMessageHandler);
}
public void SendToAll(T message)
@ -34,7 +36,7 @@ namespace QSB.Messaging
{
return;
}
NetworkServer.SendToAll((short)message.MessageType, message);
NetworkServer.SendToAll((short)_messageType, message);
}
public void SendToServer(T message)
@ -43,7 +45,7 @@ namespace QSB.Messaging
{
return;
}
NetworkManager.singleton.client.Send((short)message.MessageType, message);
NetworkManager.singleton.client.Send((short)_messageType, message);
}
private void OnClientReceiveMessageHandler(NetworkMessage netMsg)

View File

@ -1,18 +1,22 @@
using UnityEngine.Networking;
namespace QSB.Messaging
namespace QSB.Messaging
{
public enum MessageType
{
Sector = MsgType.Highest + 1,
WakeUp = MsgType.Highest + 2,
AnimTrigger = MsgType.Highest + 3,
Join = MsgType.Highest + 4,
Death = MsgType.Highest + 5,
Leave = MsgType.Highest + 6,
FullState = MsgType.Highest + 7,
FullStateRequest = MsgType.Highest + 8,
Event = MsgType.Highest + 9
// Add other message types here, incrementing the value.
Sector,
ServerTime,
AnimTrigger,
FullState,
FullStateRequest,
FlashlightActiveChange,
SignalscopeActiveChange,
TranslatorActiveChange,
ProbeLauncherActiveChange,
SuitActiveChange,
PlayerJoin,
PlayerLeave,
PlayerDeath,
PlayerSectorChange,
PlayerReady,
ProbeActiveChange
}
}

View File

@ -1,12 +1,9 @@
using QSB.Messaging;
using UnityEngine.Networking;
using UnityEngine.Networking;
namespace QSB.Events
namespace QSB.Messaging
{
public class DeathMessage : PlayerMessage
public class PlayerDeathMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.Death;
public DeathType DeathType { get; set; }
public override void Deserialize(NetworkReader reader)

View File

@ -1,12 +1,9 @@
using QSB.Messaging;
using UnityEngine.Networking;
using UnityEngine.Networking;
namespace QSB.Events
namespace QSB.Messaging
{
public class JoinMessage : PlayerMessage
public class PlayerJoinMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.Join;
public string PlayerName { get; set; }
public override void Deserialize(NetworkReader reader)
@ -21,4 +18,4 @@ namespace QSB.Events
writer.Write(PlayerName);
}
}
}
}

View File

@ -1,14 +1,11 @@
using System;
using System.Linq;
using QSB.Messaging;
using UnityEngine.Networking;
namespace QSB.Events
namespace QSB.Messaging
{
public class LeaveMessage : PlayerMessage
public class PlayerLeaveMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.Leave;
public uint[] ObjectIds { get; set; }
public override void Deserialize(NetworkReader reader)
@ -23,4 +20,4 @@ namespace QSB.Events
writer.Write(string.Join(",", ObjectIds.Select(x => x.ToString()).ToArray()));
}
}
}
}

View File

@ -1,9 +1,8 @@
using QSB.Messaging;
using UnityEngine.Networking;
using UnityEngine.Networking;
namespace QSB.Events
namespace QSB.Messaging
{
public abstract class PlayerMessage : QSBMessage
public class PlayerMessage : MessageBase
{
public uint SenderId { get; set; }

View File

@ -1,24 +1,27 @@
using QSB.Messaging;
using UnityEngine.Networking;
using UnityEngine.Networking;
namespace QSB.Events
namespace QSB.Messaging
{
public class FullStateMessage : PlayerMessage
public class PlayerStateMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.FullState;
public string PlayerName { get; set; }
public bool PlayerReady { get; set; }
public State PlayerState { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
PlayerName = reader.ReadString();
PlayerReady = reader.ReadBoolean();
PlayerState = (State)reader.ReadInt32();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(PlayerName);
writer.Write(PlayerReady);
writer.Write((int)PlayerState);
}
}
}

View File

@ -1,9 +0,0 @@
using UnityEngine.Networking;
namespace QSB.Messaging
{
public abstract class QSBMessage : MessageBase
{
public abstract MessageType MessageType { get; }
}
}

View File

@ -0,0 +1,24 @@
using UnityEngine.Networking;
namespace QSB.Messaging
{
public class SectorMessage : PlayerMessage
{
public Sector.Name SectorId;
public string SectorName;
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
SectorId = (Sector.Name)reader.ReadInt32();
SectorName = reader.ReadString();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write((int)SectorId);
writer.Write(SectorName);
}
}
}

View File

@ -1,23 +1,22 @@
using QSB.Messaging;
using UnityEngine.Networking;
using UnityEngine.Networking;
namespace QSB.TimeSync
namespace QSB.Messaging
{
public class WakeUpMessage : QSBMessage
public class ServerTimeMessage : PlayerMessage
{
public override MessageType MessageType => MessageType.WakeUp;
public float ServerTime { get; set; }
public int LoopCount { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
ServerTime = reader.ReadSingle();
LoopCount = reader.ReadInt16();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(ServerTime);
writer.Write(LoopCount);
}

View File

@ -0,0 +1,21 @@
using UnityEngine.Networking;
namespace QSB.Messaging
{
public class ToggleMessage : PlayerMessage
{
public bool ToggleValue { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
ToggleValue = reader.ReadBoolean();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(ToggleValue);
}
}
}

View File

@ -17,8 +17,8 @@ namespace QSB
public QSBTool Translator => GetToolByType(ToolType.Translator);
public QSBTool ProbeLauncher => GetToolByType(ToolType.ProbeLauncher);
public string Name { get; set; }
public bool IsReady => Body != null;
public State State { get; private set; }
public bool IsReady { get; set; }
public State State { get; set; }
public PlayerInfo(uint id)
{
@ -39,6 +39,27 @@ namespace QSB
State = states;
}
public void UpdateStateObjects()
{
if (!QSB.WokenUp)
{
return;
}
FlashLight.UpdateState(FlagsHelper.IsSet(State, State.Flashlight));
Translator.ChangeEquipState(FlagsHelper.IsSet(State, State.Translator));
ProbeLauncher.ChangeEquipState(FlagsHelper.IsSet(State, State.ProbeLauncher));
Signalscope.ChangeEquipState(FlagsHelper.IsSet(State, State.Signalscope));
if (FlagsHelper.IsSet(State, State.Suit))
{
PlayerRegistry.GetAnimationSync(NetId).SuitUp();
}
else
{
PlayerRegistry.GetAnimationSync(NetId).SuitDown();
}
}
public bool GetState(State state)
{
return FlagsHelper.IsSet(State, state);

View File

@ -1,8 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using QSB.Events;
using QSB.TransformSync;
using QSB.Animation;
using QSB.Messaging;
namespace QSB
{
@ -13,7 +13,6 @@ namespace QSB
public static List<TransformSync.TransformSync> TransformSyncs { get; } = new List<TransformSync.TransformSync>();
public static List<TransformSync.TransformSync> LocalTransformSyncs => TransformSyncs.Where(t => t != null && t.hasAuthority).ToList();
public static List<AnimationSync> AnimationSyncs { get; } = new List<AnimationSync>();
public static PlayerInfo CreatePlayer(uint id)
@ -42,10 +41,17 @@ namespace QSB
PlayerList.Remove(GetPlayer(id));
}
public static void HandleFullStateMessage(FullStateMessage message)
public static void HandleFullStateMessage(PlayerStateMessage message)
{
var player = GetPlayer(message.SenderId) ?? CreatePlayer(message.SenderId);
player.Name = message.PlayerName;
player.IsReady = message.PlayerReady;
player.State = message.PlayerState;
if (LocalPlayer.IsReady == true)
{
player.UpdateStateObjects();
}
}
public static TransformSync.TransformSync GetTransformSync(uint id)

View File

@ -12,6 +12,7 @@ namespace QSB
public static IModHelper Helper;
public static string DefaultServerIP;
public static bool DebugMode;
public static bool WokenUp;
private void Awake()
{
@ -26,8 +27,21 @@ namespace QSB
gameObject.AddComponent<QSBNetworkManager>();
gameObject.AddComponent<NetworkManagerHUD>();
gameObject.AddComponent<DebugActions>();
gameObject.AddComponent<EventListener>();
gameObject.AddComponent<FullStateRequest>();
gameObject.AddComponent<UnityHelper>();
GlobalMessenger.AddListener(EventNames.RestartTimeLoop, OnLoopStart);
GlobalMessenger.AddListener(EventNames.WakeUp, OnWakeUp);
}
private void OnWakeUp()
{
WokenUp = true;
GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest);
}
private void OnLoopStart()
{
WokenUp = false;
}
public override void Configure(IModConfig config)

View File

@ -114,33 +114,41 @@
<Compile Include="Animation\AnimationSync.cs" />
<Compile Include="Animation\AnimatorMirror.cs" />
<Compile Include="Animation\AnimFloatParam.cs" />
<Compile Include="Animation\AnimTriggerMessage.cs" />
<Compile Include="Animation\AnimTrigger.cs" />
<Compile Include="Events\EventNames.cs" />
<Compile Include="Events\PlayerDeathEvent.cs" />
<Compile Include="Events\PlayerFlashlightEvent.cs" />
<Compile Include="Events\PlayerJoinEvent.cs" />
<Compile Include="Events\PlayerLeaveEvent.cs" />
<Compile Include="Events\PlayerProbeEvent.cs" />
<Compile Include="Events\PlayerReadyEvent.cs" />
<Compile Include="Events\PlayerSectorEvent.cs" />
<Compile Include="Events\PlayerStatesRequestEvent.cs" />
<Compile Include="Events\PlayerSuitEvent.cs" />
<Compile Include="Events\ServerTimeEvent.cs" />
<Compile Include="Messaging\AnimTriggerMessage.cs" />
<Compile Include="Messaging\PlayerDeathMessage.cs" />
<Compile Include="Messaging\PlayerLeaveMessage.cs" />
<Compile Include="Events\PlayerProbeLauncherEvent.cs" />
<Compile Include="Events\PlayerSignalscopeEvent.cs" />
<Compile Include="Events\PlayerTranslatorEvent.cs" />
<Compile Include="Events\QSBEvent.cs" />
<Compile Include="Messaging\PlayerJoinMessage.cs" />
<Compile Include="Messaging\ToggleMessage.cs" />
<Compile Include="Tools\QSBFlashlight.cs" />
<Compile Include="Tools\QSBProbe.cs" />
<Compile Include="Tools\QSBTool.cs" />
<Compile Include="Tools\ToolType.cs" />
<Compile Include="TransformSync\PlayerProbeSync.cs" />
<Compile Include="Utility\DebugActions.cs" />
<Compile Include="Events\EventListener.cs" />
<Compile Include="Events\EventType.cs" />
<Compile Include="Events\FullStateMessage.cs" />
<Compile Include="Events\FullStateRequest.cs" />
<Compile Include="Events\GameState.cs" />
<Compile Include="Events\EventHandler.cs" />
<Compile Include="Events\EventMessage.cs" />
<Compile Include="Events\EventList.cs" />
<Compile Include="Messaging\PlayerStateMessage.cs" />
<Compile Include="Events\PlayerState.cs" />
<Compile Include="Events\Necronomicon.cs" />
<Compile Include="Events\JoinMessage.cs" />
<Compile Include="Events\LeaveMessage.cs" />
<Compile Include="Events\PlayerLeave.cs" />
<Compile Include="Utility\DebugLog.cs" />
<Compile Include="Events\DeathMessage.cs" />
<Compile Include="Events\PlayerJoin.cs" />
<Compile Include="Events\PlayerMessage.cs" />
<Compile Include="Events\StateRequestMessage.cs" />
<Compile Include="Messaging\PlayerMessage.cs" />
<Compile Include="Messaging\MessageHandler.cs" />
<Compile Include="Messaging\MessageType.cs" />
<Compile Include="Messaging\QSBMessage.cs" />
<Compile Include="PlayerInfo.cs" />
<Compile Include="State.cs" />
<Compile Include="TimeSync\PreventShipDestruction.cs" />
@ -151,18 +159,20 @@
<Compile Include="TransformSync\PlayerHUDMarker.cs" />
<Compile Include="Tools\PlayerToolsManager.cs" />
<Compile Include="Utility\Patches.cs" />
<Compile Include="Utility\QSBExtensions.cs" />
<Compile Include="Utility\QuaternionHelper.cs" />
<Compile Include="TimeSync\PreserveTimeScale.cs" />
<Compile Include="TransformSync\ShipTransformSync.cs" />
<Compile Include="TransformSync\TransformSync.cs" />
<Compile Include="TransformSync\SectorMessage.cs" />
<Compile Include="Messaging\SectorMessage.cs" />
<Compile Include="TransformSync\SectorSync.cs" />
<Compile Include="TimeSync\WakeUpMessage.cs" />
<Compile Include="Messaging\ServerTimeMessage.cs" />
<Compile Include="TimeSync\WakeUpSync.cs" />
<Compile Include="QSBNetworkManager.cs" />
<Compile Include="QSB.cs" />
<Compile Include="TransformSync\PlayerTransformSync.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utility\UnityHelper.cs" />
</ItemGroup>
<ItemGroup>
<None Include="default-config.json" />

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<GameDir>D:/EpicGames/OuterWilds</GameDir>
<GameDir>D:\EpicGames\OuterWilds</GameDir>
<OwmlDir>C:\Users\Henry\Downloads\OWModManager\OWML</OwmlDir>
</PropertyGroup>
</Project>

View File

@ -110,8 +110,7 @@ namespace QSB
NetworkServer.SpawnWithClientAuthority(Instantiate(_cameraPrefab), connection);
NetworkServer.SpawnWithClientAuthority(Instantiate(_probePrefab), connection);
var gameState = gameObject.AddComponent<GameState>();
gameState.Send();
gameObject.AddComponent<Events.PlayerState>();
}
public override void OnClientConnect(NetworkConnection connection) // Called on the client when connecting to a server
@ -119,32 +118,31 @@ namespace QSB
base.OnClientConnect(connection);
gameObject.AddComponent<SectorSync>();
gameObject.AddComponent<PlayerJoin>().Join(_playerName);
gameObject.AddComponent<PlayerLeave>();
gameObject.AddComponent<RespawnOnDeath>();
gameObject.AddComponent<PreventShipDestruction>();
gameObject.AddComponent<Events.EventHandler>();
if (!Network.isServer)
{
gameObject.AddComponent<GameState>();
gameObject.AddComponent<Events.PlayerState>();
}
_canEditName = false;
OnNetworkManagerReady.Invoke();
IsReady = true;
UnityHelper.Instance.RunWhen(() => PlayerTransformSync.LocalInstance != null, EventList.Init);
UnityHelper.Instance.RunWhen(() => EventList.Ready,
() => GlobalMessenger<string>.FireEvent(EventNames.QSBPlayerJoin, _playerName));
}
public override void OnStopClient() // Called on the client when closing connection
{
DebugLog.ToScreen("OnStopClient");
Destroy(GetComponent<SectorSync>());
Destroy(GetComponent<PlayerJoin>());
Destroy(GetComponent<PlayerLeave>());
Destroy(GetComponent<RespawnOnDeath>());
Destroy(GetComponent<PreventShipDestruction>());
Destroy(GetComponent<Events.EventHandler>());
if (IsClientConnected())
{
PlayerTransformSync.LocalInstance.gameObject.GetComponent<AnimationSync>().Reset();
@ -158,7 +156,7 @@ namespace QSB
var playerId = connection.playerControllers[0].gameObject.GetComponent<PlayerTransformSync>().netId.Value;
var objectIds = connection.clientOwnedObjects.Select(x => x.Value).ToArray();
GetComponent<PlayerLeave>().Leave(playerId, objectIds);
GlobalMessenger<uint, uint[]>.FireEvent(EventNames.QSBPlayerLeave, playerId, objectIds);
base.OnServerDisconnect(connection);
}

View File

@ -1,5 +1,4 @@
using OWML.ModHelper.Events;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.TimeSync
@ -16,7 +15,7 @@ namespace QSB.TimeSync
return;
}
var campfires = GameObject.FindObjectsOfType<Campfire>();
var campfires = FindObjectsOfType<Campfire>();
foreach (var campfire in campfires)
{
campfire.SetValue("_canSleepHere", false); // Stop players from sleeping at campfires

View File

@ -10,13 +10,13 @@ namespace QSB.TimeSync
{
private void Awake()
{
QSB.Helper.HarmonyHelper.Transpile<ShipDetachableLeg>("Detach", typeof(Patch), "ReturnNull");
QSB.Helper.HarmonyHelper.Transpile<ShipDetachableModule>("Detach", typeof(Patch), "ReturnNull");
QSB.Helper.HarmonyHelper.Transpile<ShipDetachableLeg>("Detach", typeof(Patch), nameof(Patch.ReturnNull));
QSB.Helper.HarmonyHelper.Transpile<ShipDetachableModule>("Detach", typeof(Patch), nameof(Patch.ReturnNull));
QSB.Helper.HarmonyHelper.EmptyMethod<ShipEjectionSystem>("OnPressInteract");
QSB.Helper.Events.Subscribe<ShipDamageController>(OWML.Common.Events.AfterAwake);
QSB.Helper.Events.OnEvent += OnEvent;
QSB.Helper.Events.Event += OnEvent;
}
private void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)

View File

@ -1,9 +1,6 @@
using System.Linq;
using OWML.ModHelper.Events;
using QSB.Events;
using QSB.Messaging;
using QSB.TransformSync;
using QSB.Utility;
using UnityEngine;
namespace QSB.TimeSync
@ -32,8 +29,6 @@ namespace QSB.TimeSync
private ShipCockpitController _cockpitController;
private PlayerSpacesuit _spaceSuit;
private MessageHandler<DeathMessage> _deathHandler;
private void Awake()
{
_instance = this;
@ -41,7 +36,7 @@ namespace QSB.TimeSync
QSB.Helper.HarmonyHelper.AddPrefix<DeathManager>("KillPlayer", typeof(Patches), nameof(Patches.PreFinishDeathSequence));
QSB.Helper.HarmonyHelper.AddPostfix<DeathManager>("KillPlayer", typeof(Patches), nameof(Patches.BroadcastDeath));
QSB.Helper.Events.Subscribe<PlayerResources>(OWML.Common.Events.AfterStart);
QSB.Helper.Events.OnEvent += OnEvent;
QSB.Helper.Events.Event += OnEvent;
}
private void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)
@ -61,23 +56,20 @@ namespace QSB.TimeSync
_fluidDetector = Locator.GetPlayerCamera().GetComponentInChildren<FluidDetector>();
var shipTransform = Locator.GetShipTransform();
if (shipTransform != null)
if (shipTransform == null)
{
_shipComponents = shipTransform.GetComponentsInChildren<ShipComponent>();
_hatchController = shipTransform.GetComponentInChildren<HatchController>();
_cockpitController = shipTransform.GetComponentInChildren<ShipCockpitController>();
_shipBody = Locator.GetShipBody();
_shipSpawnPoint = GetSpawnPoint(true);
// Move debug spawn point to initial ship position.
_playerSpawnPoint = GetSpawnPoint();
_shipSpawnPoint.transform.position = shipTransform.position;
_shipSpawnPoint.transform.rotation = shipTransform.rotation;
return;
}
_shipComponents = shipTransform.GetComponentsInChildren<ShipComponent>();
_hatchController = shipTransform.GetComponentInChildren<HatchController>();
_cockpitController = shipTransform.GetComponentInChildren<ShipCockpitController>();
_shipBody = Locator.GetShipBody();
_shipSpawnPoint = GetSpawnPoint(true);
_deathHandler = new MessageHandler<DeathMessage>();
_deathHandler.OnServerReceiveMessage += OnServerReceiveMessage;
_deathHandler.OnClientReceiveMessage += OnClientReceiveMessage;
// Move debug spawn point to initial ship position.
_playerSpawnPoint = GetSpawnPoint();
_shipSpawnPoint.transform.position = shipTransform.position;
_shipSpawnPoint.transform.rotation = shipTransform.rotation;
}
public void ResetShip()
@ -109,13 +101,13 @@ namespace QSB.TimeSync
_cockpitController.Invoke("CompleteExitFlightConsole");
_hatchController.SetValue("_isPlayerInShip", false);
_hatchController.Invoke("OpenHatch");
GlobalMessenger.FireEvent("ExitShip");
GlobalMessenger.FireEvent(EventNames.ExitShip);
}
public void ResetPlayer()
{
// Reset player position.
OWRigidbody playerBody = Locator.GetPlayerBody();
var playerBody = Locator.GetPlayerBody();
playerBody.WarpToPositionRotation(_playerSpawnPoint.transform.position, _playerSpawnPoint.transform.rotation);
playerBody.SetVelocity(_playerSpawnPoint.GetPointVelocity());
_playerSpawnPoint.AddObjectToTriggerVolumes(Locator.GetPlayerDetector().gameObject);
@ -141,18 +133,6 @@ namespace QSB.TimeSync
);
}
private void OnServerReceiveMessage(DeathMessage message)
{
_deathHandler.SendToAll(message);
}
private void OnClientReceiveMessage(DeathMessage message)
{
var playerName = PlayerRegistry.GetPlayer(message.SenderId).Name;
var deathMessage = Necronomicon.GetPhrase(message.DeathType);
DebugLog.ToAll(string.Format(deathMessage, playerName));
}
internal static class Patches
{
public static bool PreFinishDeathSequence(DeathType deathType)
@ -172,14 +152,8 @@ namespace QSB.TimeSync
public static void BroadcastDeath(DeathType deathType)
{
var message = new DeathMessage
{
SenderId = PlayerTransformSync.LocalInstance.netId.Value,
DeathType = deathType
};
_instance._deathHandler.SendToServer(message);
GlobalMessenger<DeathType>.FireEvent(EventNames.QSBPlayerDeath, deathType);
}
}
}
}

View File

@ -1,4 +1,5 @@
using QSB.Messaging;
using QSB.Events;
using QSB.Messaging;
using UnityEngine;
using UnityEngine.Networking;
@ -6,6 +7,8 @@ namespace QSB.TimeSync
{
public class WakeUpSync : NetworkBehaviour
{
public static WakeUpSync LocalInstance { get; private set; }
private const float TimeThreshold = 0.5f;
private const float MaxFastForwardSpeed = 60f;
private const float MaxFastForwardDiff = 20f;
@ -14,8 +17,6 @@ namespace QSB.TimeSync
private enum State { NotLoaded, Loaded, FastForwarding, Pausing }
private State _state = State.NotLoaded;
private MessageHandler<WakeUpMessage> _wakeUpHandler;
private float _sendTimer;
private float _serverTime;
private float _timeScale;
@ -23,6 +24,11 @@ namespace QSB.TimeSync
private int _localLoopCount;
private int _serverLoopCount;
public override void OnStartLocalPlayer()
{
LocalInstance = this;
}
private void Start()
{
if (!isLocalPlayer)
@ -30,9 +36,6 @@ namespace QSB.TimeSync
return;
}
_wakeUpHandler = new MessageHandler<WakeUpMessage>();
_wakeUpHandler.OnClientReceiveMessage += OnClientReceiveMessage;
var scene = LoadManager.GetCurrentScene();
if (scene == OWScene.SolarSystem || scene == OWScene.EyeOfTheUniverse)
{
@ -43,7 +46,7 @@ namespace QSB.TimeSync
LoadManager.OnCompleteSceneLoad += OnCompleteSceneLoad;
}
GlobalMessenger.AddListener("RestartTimeLoop", OnLoopStart);
GlobalMessenger.AddListener(EventNames.RestartTimeLoop, OnLoopStart);
}
private void OnCompleteSceneLoad(OWScene oldScene, OWScene newScene)
@ -65,6 +68,7 @@ namespace QSB.TimeSync
private void Init()
{
GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest);
_state = State.Loaded;
gameObject.AddComponent<PreserveTimeScale>();
if (isServer)
@ -84,15 +88,10 @@ namespace QSB.TimeSync
private void SendServerTime()
{
var message = new WakeUpMessage
{
ServerTime = Time.timeSinceLevelLoad,
LoopCount = _localLoopCount
};
_wakeUpHandler.SendToAll(message);
GlobalMessenger<float, int>.FireEvent(EventNames.QSBServerTime, Time.timeSinceLevelLoad, _localLoopCount);
}
private void OnClientReceiveMessage(WakeUpMessage message)
public void OnClientReceiveMessage(ServerTimeMessage message)
{
if (isServer)
{

View File

@ -28,14 +28,12 @@ namespace QSB.Tools
CreateFlashlight();
CreateSignalscope();
CreateProbeLauncher();
CreateTranslator();
CreateTranslator();
}
public static void CreateProbe(Transform body, PlayerInfo player)
{
var newProbe = body.gameObject.AddComponent<QSBProbe>();
newProbe.Init(player);
player.Probe = newProbe;
}
@ -101,7 +99,7 @@ namespace QSB.Tools
var original = GameObject.Find("NomaiTranslatorProp");
original.SetActive(false);
var translatorRoot = GameObject.Instantiate(original);
var translatorRoot = Object.Instantiate(original);
original.SetActive(true);
var group = translatorRoot.transform.Find("TranslatorGroup");
@ -171,9 +169,9 @@ namespace QSB.Tools
launcherRoot.SetActive(true);
}
private static MeshRenderer GetRenderer(GameObject root, string gameobjectName)
private static MeshRenderer GetRenderer(GameObject root, string gameObjectName)
{
return root.GetComponentsInChildren<MeshRenderer>(true).First(x => x.name == gameobjectName);
return root.GetComponentsInChildren<MeshRenderer>(true).First(x => x.name == gameObjectName);
}
}
}

View File

@ -6,7 +6,6 @@ namespace QSB.Tools
public class QSBFlashlight : MonoBehaviour
{
private OWLight2[] _lights;
private OWLight2 _illuminationCheckLight;
private Transform _root;
private Transform _basePivot;
private Transform _wobblePivot;
@ -24,13 +23,24 @@ namespace QSB.Tools
public void Init(Flashlight oldComponent)
{
_lights = oldComponent.GetValue<OWLight2[]>("_lights");
_illuminationCheckLight = oldComponent.GetValue<OWLight2>("_illuminationCheckLight");
_root = oldComponent.GetValue<Transform>("_root");
_basePivot = oldComponent.GetValue<Transform>("_basePivot");
_wobblePivot = oldComponent.GetValue<Transform>("_wobblePivot");
}
public void TurnOn()
public void UpdateState(bool value)
{
if (value)
{
TurnOn();
}
else
{
TurnOff();
}
}
private void TurnOn()
{
if (_flashlightOn)
{
@ -47,7 +57,7 @@ namespace QSB.Tools
_baseForward = _basePivot.forward;
}
public void TurnOff()
private void TurnOff()
{
if (!_flashlightOn)
{

View File

@ -1,28 +1,30 @@
using OWML.Common;
using QSB.Utility;
using UnityEngine;
using UnityEngine;
namespace QSB.Tools
{
public class QSBProbe : MonoBehaviour
{
private PlayerInfo _player;
public void Init(PlayerInfo player)
public void SetState(bool state)
{
_player = player;
if (state)
{
Activate();
}
else
{
Deactivate();
}
}
public void Activate()
private void Activate()
{
DebugLog.ToConsole($"Activating {_player.Name}'s probe.", MessageType.Info);
gameObject.SetActive(true);
}
public void Deactivate()
private void Deactivate()
{
DebugLog.ToConsole($"Deactivating {_player.Name}'s probe.", MessageType.Info);
gameObject.SetActive(false);
}
}
}

View File

@ -1,4 +1,5 @@
using QSB.Tools;
using QSB.Events;
using QSB.Tools;
using UnityEngine;
namespace QSB.TransformSync
@ -22,6 +23,10 @@ namespace QSB.TransformSync
Player.Camera = body.gameObject;
Player.IsReady = true;
GlobalMessenger<bool>.FireEvent(EventNames.QSBPlayerReady, true);
GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest);
return body;
}

View File

@ -1,28 +0,0 @@
using QSB.Messaging;
using UnityEngine.Networking;
namespace QSB.TransformSync
{
public class SectorMessage : QSBMessage
{
public override MessageType MessageType => MessageType.Sector;
public int SectorId;
public string SectorName;
public uint SenderId;
public override void Deserialize(NetworkReader reader)
{
SectorId = reader.ReadInt32();
SectorName = reader.ReadString();
SenderId = reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(SectorId);
writer.Write(SectorName);
writer.Write(SenderId);
}
}
}

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using QSB.Messaging;
using UnityEngine;
using System.Linq;
using QSB.Events;
using QSB.Utility;
namespace QSB.TransformSync
@ -9,7 +9,8 @@ namespace QSB.TransformSync
public class SectorSync : MonoBehaviour
{
private readonly List<Sector> _allSectors = new List<Sector>();
private MessageHandler<SectorMessage> _sectorHandler;
public static SectorSync LocalInstance { get; private set; }
private readonly Sector.Name[] _sectorBlacklist =
{
@ -19,6 +20,7 @@ namespace QSB.TransformSync
private void Awake()
{
LocalInstance = this;
QSB.Helper.Events.Subscribe<Sector>(OWML.Common.Events.AfterAwake);
QSB.Helper.Events.Event += OnEvent;
}
@ -34,67 +36,25 @@ namespace QSB.TransformSync
}
}
private void Start()
{
_sectorHandler = new MessageHandler<SectorMessage>();
_sectorHandler.OnClientReceiveMessage += OnClientReceiveMessage;
_sectorHandler.OnServerReceiveMessage += OnServerReceiveMessage;
}
private void SendSector(uint id, Sector sector)
{
DebugLog.ToScreen($"Sending sector {sector.name} for id {id}");
var msg = new SectorMessage
{
SectorId = (int)sector.GetName(),
SectorName = sector.name,
SenderId = id
};
_sectorHandler.SendToServer(msg);
GlobalMessenger<uint, Sector.Name, string>.FireEvent(EventNames.QSBSectorChange, id, sector.GetName(), sector.name);
}
private Sector FindSectorByName(Sector.Name sectorName, string goName)
public Sector FindSectorByName(Sector.Name sectorName, string goName)
{
if (_allSectors.Count == 0)
{
DebugLog.ToConsole("Error: _allSectors is empty!", OWML.Common.MessageType.Error);
}
return _allSectors
.FirstOrDefault(sector => sector != null &&
sector.GetName() == sectorName &&
sector.name == goName);
}
private void OnClientReceiveMessage(SectorMessage message)
{
var scene = LoadManager.GetCurrentScene();
if (scene != OWScene.SolarSystem && scene != OWScene.EyeOfTheUniverse)
{
return;
}
if (_allSectors.Count == 0)
{
DebugLog.ToConsole("Error: _allSectors is empty!", OWML.Common.MessageType.Error);
return;
}
var sectorName = (Sector.Name)message.SectorId;
var sector = FindSectorByName(sectorName, message.SectorName);
if (sector == null)
{
DebugLog.ToScreen($"Sector {message.SectorName}, {sectorName} not found!");
return;
}
var transformSync = PlayerRegistry.GetTransformSync(message.SenderId);
DebugLog.ToScreen($"{transformSync.GetType().Name} of ID {message.SenderId} set to {message.SectorName}");
transformSync.ReferenceTransform = sector.transform;
}
private void OnServerReceiveMessage(SectorMessage message)
{
_sectorHandler.SendToAll(message);
}
private void Update()
{
if (_allSectors == null || !_allSectors.Any())

View File

@ -1,5 +1,4 @@
using OWML.Common;
using QSB.Events;
using QSB.Utility;
using UnityEngine;
using UnityEngine.Networking;
@ -89,7 +88,7 @@ namespace QSB.TransformSync
DebugLog.ToConsole("Warning - TransformSync at (0,0,0)!", MessageType.Warning);
FullStateRequest.Instance.Request();
//FullStateRequest.Instance.Request();
SyncedTransform.position = Locator.GetAstroObject(AstroObject.Name.Sun).transform.position;

View File

@ -66,11 +66,16 @@ namespace QSB.Utility
NotificationManager.SharedInstance.PostNotification(data);
}
public static void ToAll(params object[] logObjects)
public static void ToAll(MessageType type, params object[] logObjects)
{
ToConsole(JoinAll(logObjects));
ToConsole(JoinAll(logObjects), type);
ToScreen(logObjects);
ToHud(logObjects);
}
public static void ToAll(params object[] logObjects)
{
ToAll(MessageType.Message, logObjects);
}
}
}

View File

@ -1,9 +1,5 @@
using OWML.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using QSB.Events;
namespace QSB.Utility
{
@ -11,14 +7,14 @@ namespace QSB.Utility
{
private static void ProbeAnchor()
{
GlobalMessenger.FireEvent("QSBOnProbeAnchor");
GlobalMessenger.FireEvent(EventNames.QSBOnProbeAnchor);
}
private static bool ProbeWarp(ref bool ____isRetrieving)
{
if (!____isRetrieving)
{
GlobalMessenger.FireEvent("QSBOnProbeWarp");
GlobalMessenger.FireEvent(EventNames.QSBOnProbeWarp);
}
return true;
}

View File

@ -0,0 +1,17 @@
namespace QSB.Utility
{
public static class QSBExtensions
{
public static void ChangeEquipState(this PlayerTool tool, bool equipState)
{
if (equipState)
{
tool.EquipTool();
}
else
{
tool.UnequipTool();
}
}
}
}

View File

@ -0,0 +1,28 @@
using System;
using System.Collections;
using UnityEngine;
namespace QSB.Utility
{
public class UnityHelper : MonoBehaviour
{
public static UnityHelper Instance { get; private set; }
private void Awake()
{
Instance = this;
}
public void RunWhen(Func<bool> when, Action what)
{
StartCoroutine(WaitUntil(when, what));
}
private IEnumerator WaitUntil(Func<bool> when, Action what)
{
yield return new WaitUntil(when);
what();
}
}
}