Merge pull request #218 from misternebula/eye-fixes

instruments <- eye fixes (DRAFT)
This commit is contained in:
Mister_Nebula 2020-12-07 18:50:23 +00:00 committed by GitHub
commit 4e869766b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
176 changed files with 18958 additions and 5034 deletions

View File

@ -5,6 +5,8 @@ VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QSB", "QSB\QSB.csproj", "{1F00090A-C697-4C55-B401-192F3CFB9DC2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuantumUNET", "QuantumUNET\QuantumUNET.csproj", "{C8C53004-1508-4F86-A419-4292C188DC2A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -15,6 +17,10 @@ Global
{1F00090A-C697-4C55-B401-192F3CFB9DC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F00090A-C697-4C55-B401-192F3CFB9DC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F00090A-C697-4C55-B401-192F3CFB9DC2}.Release|Any CPU.Build.0 = Release|Any CPU
{C8C53004-1508-4F86-A419-4292C188DC2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C8C53004-1508-4F86-A419-4292C188DC2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C8C53004-1508-4F86-A419-4292C188DC2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C8C53004-1508-4F86-A419-4292C188DC2A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -3,24 +3,24 @@ using UnityEngine;
namespace QSB.Animation
{
public static class AnimControllerPatch
{
public static RuntimeAnimatorController SuitedAnimController { get; private set; }
public static class AnimControllerPatch
{
public static RuntimeAnimatorController SuitedAnimController { get; private set; }
public static void Init()
{
QSB.Helper.Events.Subscribe<PlayerAnimController>(OWML.Common.Events.BeforeStart);
QSB.Helper.Events.Event += OnEvent;
}
public static void Init()
{
QSB.Helper.Events.Subscribe<PlayerAnimController>(OWML.Common.Events.BeforeStart);
QSB.Helper.Events.Event += OnEvent;
}
private static void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)
{
if (behaviour is PlayerAnimController playerAnimController &&
ev == OWML.Common.Events.BeforeStart &&
SuitedAnimController == null)
{
SuitedAnimController = playerAnimController.GetValue<RuntimeAnimatorController>("_baseAnimController");
}
}
}
private static void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)
{
if (behaviour is PlayerAnimController playerAnimController &&
ev == OWML.Common.Events.BeforeStart &&
SuitedAnimController == null)
{
SuitedAnimController = playerAnimController.GetValue<RuntimeAnimatorController>("_baseAnimController");
}
}
}
}

View File

@ -2,17 +2,17 @@
namespace QSB.Animation
{
public class AnimFloatParam
{
public float Current { get; private set; }
public float Target { get; set; }
public class AnimFloatParam
{
public float Current { get; private set; }
public float Target { get; set; }
private float _velocity;
private float _velocity;
public float Smooth(float smoothTime)
{
Current = Mathf.SmoothDamp(Current, Target, ref _velocity, smoothTime);
return Current;
}
}
public float Smooth(float smoothTime)
{
Current = Mathf.SmoothDamp(Current, Target, ref _velocity, smoothTime);
return Current;
}
}
}

View File

@ -3,242 +3,254 @@ using OWML.ModHelper.Events;
using QSB.EventsCore;
using QSB.Player;
using QSB.Utility;
using QuantumUNET;
using System.Linq;
using UnityEngine;
namespace QSB.Animation
{
public class AnimationSync : PlayerSyncObject
{
private Animator _anim;
private Animator _bodyAnim;
private QSBNetworkAnimator _netAnim;
public class AnimationSync : PlayerSyncObject
{
private Animator _anim;
private Animator _bodyAnim;
private QSBNetworkAnimator _netAnim;
private RuntimeAnimatorController _suitedAnimController;
private AnimatorOverrideController _unsuitedAnimController;
private GameObject _suitedGraphics;
private GameObject _unsuitedGraphics;
private PlayerCharacterController _playerController;
private CrouchSync _crouchSync;
private RuntimeAnimatorController _suitedAnimController;
private AnimatorOverrideController _unsuitedAnimController;
private GameObject _suitedGraphics;
private GameObject _unsuitedGraphics;
private PlayerCharacterController _playerController;
private CrouchSync _crouchSync;
private RuntimeAnimatorController _chertController;
private RuntimeAnimatorController _eskerController;
private RuntimeAnimatorController _feldsparController;
private RuntimeAnimatorController _gabbroController;
private RuntimeAnimatorController _riebeckController;
private RuntimeAnimatorController _chertController;
private RuntimeAnimatorController _eskerController;
private RuntimeAnimatorController _feldsparController;
private RuntimeAnimatorController _gabbroController;
private RuntimeAnimatorController _riebeckController;
public AnimatorMirror Mirror { get; private set; }
public AnimationType CurrentType = AnimationType.PlayerUnsuited;
public Animator Animator
{
get { return _bodyAnim; }
}
public AnimatorMirror Mirror { get; private set; }
public AnimationType CurrentType;
private void Awake()
{
_anim = gameObject.AddComponent<Animator>();
_netAnim = gameObject.AddComponent<QSBNetworkAnimator>();
_netAnim.enabled = false;
_netAnim.animator = _anim;
public Animator Animator
{
get { return _bodyAnim; }
}
QSBSceneManager.OnUniverseSceneLoaded += (OWScene scene) => LoadControllers();
}
private void Awake()
{
_anim = gameObject.AddComponent<Animator>();
_netAnim = gameObject.AddComponent<QSBNetworkAnimator>();
_netAnim.enabled = false;
_netAnim.animator = _anim;
private void OnDestroy()
{
_netAnim.enabled = false;
if (_playerController == null)
{
return;
}
_playerController.OnJump -= OnJump;
_playerController.OnBecomeGrounded -= OnBecomeGrounded;
_playerController.OnBecomeUngrounded -= OnBecomeUngrounded;
QSBSceneManager.OnUniverseSceneLoaded += (OWScene scene) => LoadControllers();
}
QSBSceneManager.OnUniverseSceneLoaded -= (OWScene scene) => LoadControllers();
}
private void OnDestroy()
{
_netAnim.enabled = false;
if (_playerController == null)
{
return;
}
_playerController.OnJump -= OnJump;
_playerController.OnBecomeGrounded -= OnBecomeGrounded;
_playerController.OnBecomeUngrounded -= OnBecomeUngrounded;
private void LoadControllers()
{
var bundle = QSB.InstrumentAssetBundle;
_chertController = bundle.LoadAsset("assets/Chert/Traveller_Chert.controller") as RuntimeAnimatorController;
_riebeckController = bundle.LoadAsset("assets/Riebeck/Traveller_Riebeck.controller") as RuntimeAnimatorController;
}
QSBSceneManager.OnUniverseSceneLoaded -= (OWScene scene) => LoadControllers();
}
private void InitCommon(Transform body)
{
if (QSBSceneManager.IsInUniverse)
{
LoadControllers();
}
_netAnim.enabled = true;
_bodyAnim = body.GetComponent<Animator>();
Mirror = body.gameObject.AddComponent<AnimatorMirror>();
if (isLocalPlayer)
{
Mirror.Init(_bodyAnim, _anim);
}
else
{
Mirror.Init(_anim, _bodyAnim);
}
private void LoadControllers()
{
var bundle = QSB.InstrumentAssetBundle;
_chertController = bundle.LoadAsset("assets/Chert/Traveller_Chert.controller") as RuntimeAnimatorController;
_riebeckController = bundle.LoadAsset("assets/Riebeck/Traveller_Riebeck.controller") as RuntimeAnimatorController;
}
QSBPlayerManager.PlayerSyncObjects.Add(this);
private void InitCommon(Transform body)
{
if (QSBSceneManager.IsInUniverse)
{
LoadControllers();
}
_netAnim.enabled = true;
_bodyAnim = body.GetComponent<Animator>();
Mirror = body.gameObject.AddComponent<AnimatorMirror>();
if (IsLocalPlayer)
{
Mirror.Init(_bodyAnim, _anim);
}
else
{
Mirror.Init(_anim, _bodyAnim);
}
for (var i = 0; i < _anim.parameterCount; i++)
{
_netAnim.SetParameterAutoSend(i, true);
}
QSBPlayerManager.PlayerSyncObjects.Add(this);
var playerAnimController = body.GetComponent<PlayerAnimController>();
_suitedAnimController = AnimControllerPatch.SuitedAnimController;
_unsuitedAnimController = playerAnimController.GetValue<AnimatorOverrideController>("_unsuitedAnimOverride");
_suitedGraphics = playerAnimController.GetValue<GameObject>("_suitedGroup");
_unsuitedGraphics = playerAnimController.GetValue<GameObject>("_unsuitedGroup");
}
for (var i = 0; i < _anim.parameterCount; i++)
{
_netAnim.SetParameterAutoSend(i, true);
}
public void InitLocal(Transform body)
{
InitCommon(body);
var playerAnimController = body.GetComponent<PlayerAnimController>();
_suitedAnimController = AnimControllerPatch.SuitedAnimController;
_unsuitedAnimController = playerAnimController.GetValue<AnimatorOverrideController>("_unsuitedAnimOverride");
_suitedGraphics = playerAnimController.GetValue<GameObject>("_suitedGroup");
_unsuitedGraphics = playerAnimController.GetValue<GameObject>("_unsuitedGroup");
}
_playerController = body.parent.GetComponent<PlayerCharacterController>();
_playerController.OnJump += OnJump;
_playerController.OnBecomeGrounded += OnBecomeGrounded;
_playerController.OnBecomeUngrounded += OnBecomeUngrounded;
public void InitLocal(Transform body)
{
InitCommon(body);
InitCrouchSync();
}
_playerController = body.parent.GetComponent<PlayerCharacterController>();
_playerController.OnJump += OnJump;
_playerController.OnBecomeGrounded += OnBecomeGrounded;
_playerController.OnBecomeUngrounded += OnBecomeUngrounded;
public void InitRemote(Transform body)
{
InitCommon(body);
InitCrouchSync();
}
var playerAnimController = body.GetComponent<PlayerAnimController>();
playerAnimController.enabled = false;
public void InitRemote(Transform body)
{
InitCommon(body);
playerAnimController.SetValue("_suitedGroup", new GameObject());
playerAnimController.SetValue("_unsuitedGroup", new GameObject());
playerAnimController.SetValue("_baseAnimController", null);
playerAnimController.SetValue("_unsuitedAnimOverride", null);
playerAnimController.SetValue("_rightArmHidden", false);
var playerAnimController = body.GetComponent<PlayerAnimController>();
playerAnimController.enabled = false;
var rightArmObjects = playerAnimController.GetValue<GameObject[]>("_rightArmObjects").ToList();
rightArmObjects.ForEach(rightArmObject => rightArmObject.layer = LayerMask.NameToLayer("Default"));
playerAnimController.SetValue("_suitedGroup", new GameObject());
playerAnimController.SetValue("_unsuitedGroup", new GameObject());
playerAnimController.SetValue("_baseAnimController", null);
playerAnimController.SetValue("_unsuitedAnimOverride", null);
playerAnimController.SetValue("_rightArmHidden", false);
body.Find("player_mesh_noSuit:Traveller_HEA_Player/player_mesh_noSuit:Player_Head").gameObject.layer = 0;
body.Find("Traveller_Mesh_v01:Traveller_Geo/Traveller_Mesh_v01:PlayerSuit_Helmet").gameObject.layer = 0;
var rightArmObjects = playerAnimController.GetValue<GameObject[]>("_rightArmObjects").ToList();
rightArmObjects.ForEach(rightArmObject => rightArmObject.layer = LayerMask.NameToLayer("Default"));
InitCrouchSync();
body.Find("player_mesh_noSuit:Traveller_HEA_Player/player_mesh_noSuit:Player_Head").gameObject.layer = 0;
body.Find("Traveller_Mesh_v01:Traveller_Geo/Traveller_Mesh_v01:PlayerSuit_Helmet").gameObject.layer = 0;
var ikSync = body.gameObject.AddComponent<PlayerHeadRotationSync>();
QSB.Helper.Events.Unity.RunWhen(() => Player.Camera != null, () => ikSync.Init(Player.Camera.transform));
}
SetAnimationType(AnimationType.PlayerUnsuited);
private void InitCrouchSync()
{
_crouchSync = gameObject.AddComponent<CrouchSync>();
_crouchSync.Init(this, _playerController, _bodyAnim);
}
InitCrouchSync();
private void OnJump() => _netAnim.SetTrigger("Jump");
private void OnBecomeGrounded() => _netAnim.SetTrigger("Grounded");
private void OnBecomeUngrounded() => _netAnim.SetTrigger("Ungrounded");
var ikSync = body.gameObject.AddComponent<PlayerHeadRotationSync>();
QSB.Helper.Events.Unity.RunWhen(() => Player.Camera != null, () => ikSync.Init(Player.Camera.transform));
}
public void SendCrouch(float value = 0)
{
GlobalMessenger<float>.FireEvent(EventNames.QSBCrouch, value);
}
private void InitCrouchSync()
{
_crouchSync = gameObject.AddComponent<CrouchSync>();
_crouchSync.Init(this, _playerController, _bodyAnim);
}
public void HandleCrouch(float value)
{
_crouchSync.CrouchParam.Target = value;
}
private void OnJump() => _netAnim.SetTrigger("Jump");
private void SuitUp()
{
GlobalMessenger<uint, AnimationType>.FireEvent(EventNames.QSBChangeAnimType, PlayerId, AnimationType.PlayerSuited);
SetAnimationType(AnimationType.PlayerSuited);
}
private void OnBecomeGrounded() => _netAnim.SetTrigger("Grounded");
private void SuitDown()
{
GlobalMessenger<uint, AnimationType>.FireEvent(EventNames.QSBChangeAnimType, PlayerId, AnimationType.PlayerUnsuited);
SetAnimationType(AnimationType.PlayerUnsuited);
}
private void OnBecomeUngrounded() => _netAnim.SetTrigger("Ungrounded");
public void SetSuitState(bool state)
{
if (state)
{
SuitUp();
return;
}
SuitDown();
}
public void SendCrouch(float value = 0)
{
GlobalMessenger<float>.FireEvent(EventNames.QSBCrouch, value);
}
public void SetAnimationType(AnimationType type)
{
if (CurrentType == type)
{
return;
}
CurrentType = type;
if (_unsuitedAnimController == null)
{
DebugLog.DebugWrite($"Error - Unsuited controller is null. ({PlayerId})", MessageType.Error);
}
if (_suitedAnimController == null)
{
DebugLog.DebugWrite($"Error - Suited controller is null. ({PlayerId})", MessageType.Error);
}
RuntimeAnimatorController controller = default;
switch (type)
{
case AnimationType.PlayerSuited:
controller = _suitedAnimController;
_unsuitedGraphics?.SetActive(false);
_suitedGraphics?.SetActive(true);
break;
case AnimationType.PlayerUnsuited:
controller = _unsuitedAnimController;
_unsuitedGraphics?.SetActive(true);
_suitedGraphics?.SetActive(false);
break;
case AnimationType.Chert:
controller = _chertController;
break;
case AnimationType.Esker:
controller = _eskerController;
break;
case AnimationType.Feldspar:
controller = _feldsparController;
break;
case AnimationType.Gabbro:
controller = _gabbroController;
break;
case AnimationType.Riebeck:
controller = _riebeckController;
break;
}
_anim.runtimeAnimatorController = controller;
_bodyAnim.runtimeAnimatorController = controller;
if (type != AnimationType.PlayerSuited && type != AnimationType.PlayerUnsuited)
{
_bodyAnim.SetTrigger("Playing");
_anim.SetTrigger("Playing");
}
else
{
// Avoids "jumping" when exiting instrument and putting on suit
_bodyAnim.SetTrigger("Grounded");
_anim.SetTrigger("Grounded");
}
_netAnim.animator = _anim; // Probably not needed.
Mirror.RebuildFloatParams();
for (var i = 0; i < _anim.parameterCount; i++)
{
_netAnim.SetParameterAutoSend(i, true);
}
}
}
public void HandleCrouch(float value)
{
_crouchSync.CrouchParam.Target = value;
}
private void SuitUp()
{
GlobalMessenger<uint, AnimationType>.FireEvent(EventNames.QSBChangeAnimType, PlayerId, AnimationType.PlayerSuited);
SetAnimationType(AnimationType.PlayerSuited);
}
private void SuitDown()
{
GlobalMessenger<uint, AnimationType>.FireEvent(EventNames.QSBChangeAnimType, PlayerId, AnimationType.PlayerUnsuited);
SetAnimationType(AnimationType.PlayerUnsuited);
}
public void SetSuitState(bool state)
{
if (state)
{
SuitUp();
return;
}
SuitDown();
}
public void SetAnimationType(AnimationType type)
{
if (CurrentType == type)
{
return;
}
CurrentType = type;
if (_unsuitedAnimController == null)
{
DebugLog.DebugWrite($"Error - Unsuited controller is null. ({PlayerId})", MessageType.Error);
}
if (_suitedAnimController == null)
{
DebugLog.DebugWrite($"Error - Suited controller is null. ({PlayerId})", MessageType.Error);
}
RuntimeAnimatorController controller = default;
switch (type)
{
case AnimationType.PlayerSuited:
controller = _suitedAnimController;
_unsuitedGraphics?.SetActive(false);
_suitedGraphics?.SetActive(true);
break;
case AnimationType.PlayerUnsuited:
controller = _unsuitedAnimController;
_unsuitedGraphics?.SetActive(true);
_suitedGraphics?.SetActive(false);
break;
case AnimationType.Chert:
controller = _chertController;
break;
case AnimationType.Esker:
controller = _eskerController;
break;
case AnimationType.Feldspar:
controller = _feldsparController;
break;
case AnimationType.Gabbro:
controller = _gabbroController;
break;
case AnimationType.Riebeck:
controller = _riebeckController;
break;
}
_anim.runtimeAnimatorController = controller;
_bodyAnim.runtimeAnimatorController = controller;
if (type != AnimationType.PlayerSuited && type != AnimationType.PlayerUnsuited)
{
_bodyAnim.SetTrigger("Playing");
_anim.SetTrigger("Playing");
}
else
{
// Avoids "jumping" when exiting instrument and putting on suit
_bodyAnim.SetTrigger("Grounded");
_anim.SetTrigger("Grounded");
}
_netAnim.animator = _anim; // Probably not needed.
Mirror.RebuildFloatParams();
for (var i = 0; i < _anim.parameterCount; i++)
{
_netAnim.SetParameterAutoSend(i, true);
}
}
}
}

View File

@ -1,13 +1,13 @@
namespace QSB.Animation
{
public enum AnimationType
{
Chert,
Esker,
Feldspar,
Gabbro,
PlayerSuited,
PlayerUnsuited,
Riebeck
}
public enum AnimationType
{
Chert,
Esker,
Feldspar,
Gabbro,
PlayerSuited,
PlayerUnsuited,
Riebeck
}
}

View File

@ -7,92 +7,93 @@ using UnityEngine;
namespace QSB.Animation
{
public class AnimatorMirror : MonoBehaviour
{
private const float SmoothTime = 0.05f;
public class AnimatorMirror : MonoBehaviour
{
private const float SmoothTime = 0.05f;
private Animator _from;
private Animator _to;
private Animator _from;
private Animator _to;
private readonly Dictionary<string, AnimFloatParam> _floatParams = new Dictionary<string, AnimFloatParam>();
private readonly Dictionary<string, AnimFloatParam> _floatParams = new Dictionary<string, AnimFloatParam>();
public void Init(Animator from, Animator to)
{
_from = from;
_to = to;
if (_from.runtimeAnimatorController == null)
{
DebugLog.DebugWrite($"Warning - \"From\" ({from.name}) controller is null.", MessageType.Warning);
_from.runtimeAnimatorController = _to.runtimeAnimatorController;
}
else if (_to.runtimeAnimatorController == null)
{
DebugLog.DebugWrite($"Warning - \"To\" ({to.name}) controller is null.", MessageType.Warning);
_to.runtimeAnimatorController = _from.runtimeAnimatorController;
}
foreach (var param in _from.parameters.Where(p => p.type == AnimatorControllerParameterType.Float))
{
_floatParams.Add(param.name, new AnimFloatParam());
}
}
public void Init(Animator from, Animator to)
{
_from = from;
_to = to;
if (_from.runtimeAnimatorController == null)
{
DebugLog.DebugWrite($"Warning - \"From\" ({from.name}) controller is null.", MessageType.Warning);
_from.runtimeAnimatorController = _to.runtimeAnimatorController;
}
else if (_to.runtimeAnimatorController == null)
{
DebugLog.DebugWrite($"Warning - \"To\" ({to.name}) controller is null.", MessageType.Warning);
_to.runtimeAnimatorController = _from.runtimeAnimatorController;
}
foreach (var param in _from.parameters.Where(p => p.type == AnimatorControllerParameterType.Float))
{
_floatParams.Add(param.name, new AnimFloatParam());
}
}
private PlayerInfo GetPlayer()
{
return QSBPlayerManager.GetSyncObjects<AnimationSync>().First(x => x.Mirror == this).Player;
}
private PlayerInfo GetPlayer()
{
return QSBPlayerManager.GetSyncObjects<AnimationSync>().First(x => x.Mirror == this).Player;
}
private void Update()
{
if (_to == null || _from == null)
{
return;
}
if (_to.runtimeAnimatorController != _from.runtimeAnimatorController)
{
_to.runtimeAnimatorController = _from.runtimeAnimatorController;
}
SyncParams();
SmoothFloats();
}
private void Update()
{
if (_to == null || _from == null)
{
return;
}
if (_to.runtimeAnimatorController != _from.runtimeAnimatorController)
{
_to.runtimeAnimatorController = _from.runtimeAnimatorController;
}
SyncParams();
SmoothFloats();
}
private void SyncParams()
{
foreach (var fromParam in _from.parameters)
{
switch (fromParam.type)
{
case AnimatorControllerParameterType.Float:
if (!_floatParams.ContainsKey(fromParam.name))
{
DebugLog.ToConsole($"Warning - Tried to sync anim float that doesn't exist in dict : {fromParam.name}", MessageType.Warning);
RebuildFloatParams();
break;
}
_floatParams[fromParam.name].Target = _from.GetFloat(fromParam.name);
break;
case AnimatorControllerParameterType.Bool:
_to.SetBool(fromParam.name, _from.GetBool(fromParam.name));
break;
}
}
}
private void SyncParams()
{
foreach (var fromParam in _from.parameters)
{
switch (fromParam.type)
{
case AnimatorControllerParameterType.Float:
if (!_floatParams.ContainsKey(fromParam.name))
{
DebugLog.ToConsole($"Warning - Tried to sync anim float that doesn't exist in dict : {fromParam.name}", MessageType.Warning);
RebuildFloatParams();
break;
}
_floatParams[fromParam.name].Target = _from.GetFloat(fromParam.name);
break;
private void SmoothFloats()
{
foreach (var floatParam in _floatParams)
{
var current = floatParam.Value.Smooth(SmoothTime);
_to.SetFloat(floatParam.Key, current);
}
}
case AnimatorControllerParameterType.Bool:
_to.SetBool(fromParam.name, _from.GetBool(fromParam.name));
break;
}
}
}
public void RebuildFloatParams()
{
_floatParams.Clear();
foreach (var param in _from.parameters.Where(p => p.type == AnimatorControllerParameterType.Float))
{
_floatParams.Add(param.name, new AnimFloatParam());
}
}
}
private void SmoothFloats()
{
foreach (var floatParam in _floatParams)
{
var current = floatParam.Value.Smooth(SmoothTime);
_to.SetFloat(floatParam.Key, current);
}
}
public void RebuildFloatParams()
{
_floatParams.Clear();
foreach (var param in _from.parameters.Where(p => p.type == AnimatorControllerParameterType.Float))
{
_floatParams.Add(param.name, new AnimFloatParam());
}
}
}
}

View File

@ -1,72 +1,72 @@
using System;
using QuantumUNET;
using System;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.Animation
{
public class CrouchSync : NetworkBehaviour
{
public AnimFloatParam CrouchParam { get; } = new AnimFloatParam();
public class CrouchSync : QSBNetworkBehaviour
{
public AnimFloatParam CrouchParam { get; } = new AnimFloatParam();
private const float CrouchSendInterval = 0.1f;
private const float CrouchChargeThreshold = 0.01f;
private const float CrouchSmoothTime = 0.05f;
private const int CrouchLayerIndex = 1;
private const float CrouchSendInterval = 0.1f;
private const float CrouchChargeThreshold = 0.01f;
private const float CrouchSmoothTime = 0.05f;
private const int CrouchLayerIndex = 1;
private float _sendTimer;
private float _lastSentJumpChargeFraction;
private float _sendTimer;
private float _lastSentJumpChargeFraction;
private AnimationSync _animationSync;
private PlayerCharacterController _playerController;
private Animator _bodyAnim;
private AnimationSync _animationSync;
private PlayerCharacterController _playerController;
private Animator _bodyAnim;
public void Init(AnimationSync animationSync, PlayerCharacterController playerController, Animator bodyAnim)
{
_animationSync = animationSync;
_playerController = playerController;
_bodyAnim = bodyAnim;
}
public void Init(AnimationSync animationSync, PlayerCharacterController playerController, Animator bodyAnim)
{
_animationSync = animationSync;
_playerController = playerController;
_bodyAnim = bodyAnim;
}
private void Update()
{
if (isLocalPlayer)
{
SyncLocalCrouch();
return;
}
SyncRemoteCrouch();
}
private void Update()
{
if (IsLocalPlayer)
{
SyncLocalCrouch();
return;
}
SyncRemoteCrouch();
}
private void SyncLocalCrouch()
{
if (_playerController == null)
{
return;
}
_sendTimer += Time.unscaledDeltaTime;
if (_sendTimer < CrouchSendInterval)
{
return;
}
var jumpChargeFraction = _playerController.GetJumpChargeFraction();
if (Math.Abs(jumpChargeFraction - _lastSentJumpChargeFraction) < CrouchChargeThreshold)
{
return;
}
_animationSync.SendCrouch(jumpChargeFraction);
_lastSentJumpChargeFraction = jumpChargeFraction;
_sendTimer = 0;
}
private void SyncLocalCrouch()
{
if (_playerController == null)
{
return;
}
_sendTimer += Time.unscaledDeltaTime;
if (_sendTimer < CrouchSendInterval)
{
return;
}
var jumpChargeFraction = _playerController.GetJumpChargeFraction();
if (Math.Abs(jumpChargeFraction - _lastSentJumpChargeFraction) < CrouchChargeThreshold)
{
return;
}
_animationSync.SendCrouch(jumpChargeFraction);
_lastSentJumpChargeFraction = jumpChargeFraction;
_sendTimer = 0;
}
private void SyncRemoteCrouch()
{
if (_bodyAnim == null)
{
return;
}
CrouchParam.Smooth(CrouchSmoothTime);
var jumpChargeFraction = CrouchParam.Current;
_bodyAnim.SetLayerWeight(CrouchLayerIndex, jumpChargeFraction);
}
}
private void SyncRemoteCrouch()
{
if (_bodyAnim == null)
{
return;
}
CrouchParam.Smooth(CrouchSmoothTime);
var jumpChargeFraction = CrouchParam.Current;
_bodyAnim.SetLayerWeight(CrouchLayerIndex, jumpChargeFraction);
}
}
}

View File

@ -5,26 +5,26 @@ using QSB.Player;
namespace QSB.Animation.Events
{
public class ChangeAnimTypeEvent : QSBEvent<EnumMessage<AnimationType>>
{
public override EventType Type => EventType.PlayInstrument;
public class ChangeAnimTypeEvent : QSBEvent<EnumMessage<AnimationType>>
{
public override EventType Type => EventType.PlayInstrument;
public override void SetupListener() => GlobalMessenger<uint, AnimationType>.AddListener(EventNames.QSBChangeAnimType, Handler);
public override void SetupListener() => GlobalMessenger<uint, AnimationType>.AddListener(EventNames.QSBChangeAnimType, Handler);
public override void CloseListener() => GlobalMessenger<uint, AnimationType>.RemoveListener(EventNames.QSBChangeAnimType, Handler);
public override void CloseListener() => GlobalMessenger<uint, AnimationType>.RemoveListener(EventNames.QSBChangeAnimType, Handler);
private void Handler(uint player, AnimationType type) => SendEvent(CreateMessage(player, type));
private void Handler(uint player, AnimationType type) => SendEvent(CreateMessage(player, type));
private EnumMessage<AnimationType> CreateMessage(uint player, AnimationType type) => new EnumMessage<AnimationType>
{
AboutId = player,
Value = type
};
private EnumMessage<AnimationType> CreateMessage(uint player, AnimationType type) => new EnumMessage<AnimationType>
{
AboutId = player,
Value = type
};
public override void OnReceiveRemote(EnumMessage<AnimationType> message)
{
QSBPlayerManager.GetPlayer(message.AboutId).AnimationSync.SetAnimationType(message.Value);
QSBPlayerManager.GetSyncObject<InstrumentsManager>(message.AboutId).CheckInstrumentProps(message.Value);
}
}
public override void OnReceiveRemote(EnumMessage<AnimationType> message)
{
QSBPlayerManager.GetPlayer(message.AboutId).AnimationSync.SetAnimationType(message.Value);
QSBPlayerManager.GetSyncObject<InstrumentsManager>(message.AboutId).CheckInstrumentProps(message.Value);
}
}
}

View File

@ -4,30 +4,30 @@ using QSB.Player;
namespace QSB.Animation.Events
{
public class CrouchEvent : QSBEvent<FloatMessage>
{
public override EventType Type => EventType.AnimTrigger;
public class CrouchEvent : QSBEvent<FloatMessage>
{
public override EventType Type => EventType.AnimTrigger;
public override void SetupListener() => GlobalMessenger<float>.AddListener(EventNames.QSBCrouch, Handler);
public override void SetupListener() => GlobalMessenger<float>.AddListener(EventNames.QSBCrouch, Handler);
public override void CloseListener() => GlobalMessenger<float>.RemoveListener(EventNames.QSBCrouch, Handler);
public override void CloseListener() => GlobalMessenger<float>.RemoveListener(EventNames.QSBCrouch, Handler);
private void Handler(float value) => SendEvent(CreateMessage(value));
private void Handler(float value) => SendEvent(CreateMessage(value));
private FloatMessage CreateMessage(float value) => new FloatMessage
{
AboutId = LocalPlayerId,
Value = value
};
private FloatMessage CreateMessage(float value) => new FloatMessage
{
AboutId = LocalPlayerId,
Value = value
};
public override void OnReceiveRemote(FloatMessage message)
{
var animationSync = QSBPlayerManager.GetSyncObject<AnimationSync>(message.AboutId);
if (animationSync == null)
{
return;
}
animationSync.HandleCrouch(message.Value);
}
}
public override void OnReceiveRemote(FloatMessage message)
{
var animationSync = QSBPlayerManager.GetSyncObject<AnimationSync>(message.AboutId);
if (animationSync == null)
{
return;
}
animationSync.HandleCrouch(message.Value);
}
}
}

View File

@ -4,52 +4,53 @@ using QSB.Player;
namespace QSB.Animation
{
public class PlayerSuitEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.SuitActiveChange;
public class PlayerSuitEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.SuitActiveChange;
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.SuitUp, HandleSuitUp);
GlobalMessenger.AddListener(EventNames.RemoveSuit, HandleSuitDown);
}
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.SuitUp, HandleSuitUp);
GlobalMessenger.AddListener(EventNames.RemoveSuit, HandleSuitDown);
}
public override void CloseListener()
{
GlobalMessenger.RemoveListener(EventNames.SuitUp, HandleSuitUp);
GlobalMessenger.RemoveListener(EventNames.RemoveSuit, HandleSuitDown);
}
public override void CloseListener()
{
GlobalMessenger.RemoveListener(EventNames.SuitUp, HandleSuitUp);
GlobalMessenger.RemoveListener(EventNames.RemoveSuit, HandleSuitDown);
}
private void HandleSuitUp() => SendEvent(CreateMessage(true));
private void HandleSuitDown() => SendEvent(CreateMessage(false));
private void HandleSuitUp() => SendEvent(CreateMessage(true));
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
private void HandleSuitDown() => SendEvent(CreateMessage(false));
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player?.UpdateState(State.Suit, message.ToggleValue);
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
if (!player.IsReady)
{
return;
}
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player?.UpdateState(State.Suit, message.ToggleValue);
var animator = player.AnimationSync;
var type = message.ToggleValue ? AnimationType.PlayerSuited : AnimationType.PlayerUnsuited;
animator.SetAnimationType(type);
}
if (!QSB.HasWokenUp)
{
return;
}
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Suit, message.ToggleValue);
var animator = QSBPlayerManager.LocalPlayer.AnimationSync;
var type = message.ToggleValue ? AnimationType.PlayerSuited : AnimationType.PlayerUnsuited;
animator.CurrentType = type;
}
}
var animator = player.AnimationSync;
var type = message.ToggleValue ? AnimationType.PlayerSuited : AnimationType.PlayerUnsuited;
animator.SetAnimationType(type);
}
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Suit, message.ToggleValue);
var animator = QSBPlayerManager.LocalPlayer.AnimationSync;
var type = message.ToggleValue ? AnimationType.PlayerSuited : AnimationType.PlayerUnsuited;
animator.CurrentType = type;
}
}
}

View File

@ -1,35 +0,0 @@
using UnityEngine.Networking;
namespace QSB.Animation.Events
{
class QSBAnimationMessage : MessageBase
{
public NetworkInstanceId netId;
public int stateHash;
public float normalizedTime;
public byte[] parameters;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
stateHash = (int)reader.ReadPackedUInt32();
normalizedTime = reader.ReadSingle();
parameters = reader.ReadBytesAndSize();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.WritePackedUInt32((uint)stateHash);
writer.Write(normalizedTime);
if (parameters == null)
{
writer.WriteBytesAndSize(parameters, 0);
}
else
{
writer.WriteBytesAndSize(parameters, parameters.Length);
}
}
}
}

View File

@ -1,29 +0,0 @@
using UnityEngine.Networking;
namespace QSB.Animation.Events
{
class QSBAnimationParametersMessage : MessageBase
{
public NetworkInstanceId netId;
public byte[] parameters;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
parameters = reader.ReadBytesAndSize();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
if (parameters == null)
{
writer.WriteBytesAndSize(parameters, 0);
}
else
{
writer.WriteBytesAndSize(parameters, parameters.Length);
}
}
}
}

View File

@ -1,22 +0,0 @@
using UnityEngine.Networking;
namespace QSB.Animation.Events
{
class QSBAnimationTriggerMessage : MessageBase
{
public NetworkInstanceId netId;
public int hash;
public override void Deserialize(NetworkReader reader)
{
netId = reader.ReadNetworkId();
hash = (int)reader.ReadPackedUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(netId);
writer.WritePackedUInt32((uint)hash);
}
}
}

View File

@ -2,23 +2,29 @@
namespace QSB.Animation
{
public class PlayerHeadRotationSync : MonoBehaviour
{
private Animator _attachedAnimator;
private Transform _lookBase;
public class PlayerHeadRotationSync : MonoBehaviour
{
private Animator _attachedAnimator;
private Transform _lookBase;
private bool _isSetUp;
public void Init(Transform lookBase)
{
_attachedAnimator = GetComponent<Animator>();
_lookBase = lookBase;
}
public void Init(Transform lookBase)
{
_attachedAnimator = GetComponent<Animator>();
_lookBase = lookBase;
_isSetUp = true;
}
void LateUpdate()
{
var bone = _attachedAnimator.GetBoneTransform(HumanBodyBones.Head);
// Get the camera's local rotation with respect to the player body
var lookLocalRotation = Quaternion.Inverse(_attachedAnimator.transform.rotation) * _lookBase.rotation;
bone.localRotation = Quaternion.Euler(0f, 0f, lookLocalRotation.eulerAngles.x);
}
}
}
private void LateUpdate()
{
if (!_isSetUp)
{
return;
}
var bone = _attachedAnimator.GetBoneTransform(HumanBodyBones.Head);
// Get the camera's local rotation with respect to the player body
var lookLocalRotation = Quaternion.Inverse(_attachedAnimator.transform.rotation) * _lookBase.rotation;
bone.localRotation = Quaternion.Euler(0f, 0f, lookLocalRotation.eulerAngles.x);
}
}
}

View File

@ -1,375 +0,0 @@
using QSB.Animation.Events;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.Animation
{
// Cleaned up unity code. UNET is so broken I gave up and fixed it myself.
[RequireComponent(typeof(NetworkIdentity))]
[RequireComponent(typeof(Animator))]
class QSBNetworkAnimator : NetworkBehaviour
{
private static QSBAnimationMessage AnimationMessage = new QSBAnimationMessage();
private static QSBAnimationParametersMessage ParametersMessage = new QSBAnimationParametersMessage();
private static QSBAnimationTriggerMessage TriggersMessage = new QSBAnimationTriggerMessage();
private Animator m_Animator;
private uint m_ParameterSendBits;
private int m_AnimationHash;
private int m_TransitionHash;
private NetworkWriter m_ParameterWriter;
private float m_SendTimer;
public Animator animator
{
get
{
return m_Animator;
}
set
{
m_Animator = value;
m_ParameterSendBits = 0U;
}
}
public void SetParameterAutoSend(int index, bool value)
{
if (value)
m_ParameterSendBits |= (uint)(1 << index);
else
m_ParameterSendBits &= (uint)~(1 << index);
}
public bool GetParameterAutoSend(int index)
{
return ((int)m_ParameterSendBits & 1 << index) != 0;
}
public override void OnStartAuthority()
{
m_ParameterWriter = new NetworkWriter();
}
private void FixedUpdate()
{
if (m_ParameterWriter == null)
{
return;
}
CheckSendRate();
if (!CheckAnimStateChanged(out var stateHash, out var normalizedTime))
{
return;
}
var animationMessage = new QSBAnimationMessage
{
netId = netId,
stateHash = stateHash,
normalizedTime = normalizedTime
};
m_ParameterWriter.SeekZero();
WriteParameters(m_ParameterWriter, false);
animationMessage.parameters = m_ParameterWriter.ToArray();
if (hasAuthority || ClientScene.readyConnection != null)
{
ClientScene.readyConnection.Send(40, animationMessage);
}
else
{
if (!isServer || localPlayerAuthority)
{
return;
}
NetworkServer.SendToReady(gameObject, 40, animationMessage);
}
}
private bool CheckAnimStateChanged(out int stateHash, out float normalizedTime)
{
stateHash = 0;
normalizedTime = 0.0f;
if (m_Animator.IsInTransition(0))
{
var animatorTransitionInfo = m_Animator.GetAnimatorTransitionInfo(0);
if (animatorTransitionInfo.fullPathHash == m_TransitionHash)
{
return false;
}
m_TransitionHash = animatorTransitionInfo.fullPathHash;
m_AnimationHash = 0;
return true;
}
var animatorStateInfo = m_Animator.GetCurrentAnimatorStateInfo(0);
if (animatorStateInfo.fullPathHash == m_AnimationHash)
{
return false;
}
if (m_AnimationHash != 0)
{
stateHash = animatorStateInfo.fullPathHash;
normalizedTime = animatorStateInfo.normalizedTime;
}
m_TransitionHash = 0;
m_AnimationHash = animatorStateInfo.fullPathHash;
return true;
}
private void CheckSendRate()
{
if (GetNetworkSendInterval() == 0.0 || m_SendTimer >= Time.time)
{
return;
}
m_SendTimer = Time.time + GetNetworkSendInterval();
var parametersMessage = new QSBAnimationParametersMessage
{
netId = netId
};
m_ParameterWriter.SeekZero();
WriteParameters(m_ParameterWriter, true);
parametersMessage.parameters = m_ParameterWriter.ToArray();
if (hasAuthority && ClientScene.readyConnection != null)
{
ClientScene.readyConnection.Send(41, parametersMessage);
}
else
{
if (!isServer || localPlayerAuthority)
return;
NetworkServer.SendToReady(gameObject, 41, parametersMessage);
}
}
internal void HandleAnimMsg(QSBAnimationMessage msg, NetworkReader reader)
{
if (hasAuthority)
{
return;
}
if (msg.stateHash != 0)
{
m_Animator.Play(msg.stateHash, 0, msg.normalizedTime);
}
ReadParameters(reader, false);
}
internal void HandleAnimParamsMsg(QSBAnimationParametersMessage msg, NetworkReader reader)
{
if (hasAuthority)
{
return;
}
ReadParameters(reader, true);
}
internal void HandleAnimTriggerMsg(int hash)
{
m_Animator.SetTrigger(hash);
}
private void WriteParameters(NetworkWriter writer, bool autoSend)
{
for (int index = 0; index < m_Animator.parameters.Length; ++index)
{
if (!autoSend || GetParameterAutoSend(index))
{
var parameter = m_Animator.parameters[index];
switch (parameter.type)
{
case AnimatorControllerParameterType.Int:
writer.WritePackedUInt32((uint)m_Animator.GetInteger(parameter.nameHash));
break;
case AnimatorControllerParameterType.Float:
writer.Write(m_Animator.GetFloat(parameter.nameHash));
break;
case AnimatorControllerParameterType.Bool:
writer.Write(m_Animator.GetBool(parameter.nameHash));
break;
}
}
}
}
private void ReadParameters(NetworkReader reader, bool autoSend)
{
for (int index = 0; index < m_Animator.parameters.Length; ++index)
{
if (!autoSend || GetParameterAutoSend(index))
{
var parameter = m_Animator.parameters[index];
if (reader.Length == reader.Position)
{
return;
}
switch (parameter.type)
{
case AnimatorControllerParameterType.Int:
var num = (int)reader.ReadPackedUInt32();
m_Animator.SetInteger(parameter.nameHash, num);
break;
case AnimatorControllerParameterType.Float:
var single = reader.ReadSingle();
m_Animator.SetFloat(parameter.nameHash, single);
break;
case AnimatorControllerParameterType.Bool:
var flag = reader.ReadBoolean();
m_Animator.SetBool(parameter.nameHash, flag);
break;
}
}
}
}
public override bool OnSerialize(NetworkWriter writer, bool forceAll)
{
if (!forceAll)
{
return false;
}
if (m_Animator.IsInTransition(0))
{
var animatorStateInfo = m_Animator.GetNextAnimatorStateInfo(0);
writer.Write(animatorStateInfo.fullPathHash);
writer.Write(animatorStateInfo.normalizedTime);
}
else
{
var animatorStateInfo = m_Animator.GetCurrentAnimatorStateInfo(0);
writer.Write(animatorStateInfo.fullPathHash);
writer.Write(animatorStateInfo.normalizedTime);
}
WriteParameters(writer, false);
return true;
}
public override void OnDeserialize(NetworkReader reader, bool initialState)
{
if (!initialState)
{
return;
}
var stateNameHash = reader.ReadInt32();
var normalizedTime = reader.ReadSingle();
ReadParameters(reader, false);
m_Animator.Play(stateNameHash, 0, normalizedTime);
}
public void SetTrigger(string triggerName)
{
SetTrigger(Animator.StringToHash(triggerName));
}
public void SetTrigger(int hash)
{
var animationTriggerMessage = new QSBAnimationTriggerMessage
{
netId = netId,
hash = hash
};
if (hasAuthority && localPlayerAuthority)
{
if (NetworkClient.allClients.Count <= 0)
{
return;
}
var readyConnection = ClientScene.readyConnection;
if (readyConnection == null)
{
return;
}
readyConnection.Send(42, animationTriggerMessage);
}
else
{
if (!isServer || localPlayerAuthority)
{
return;
}
NetworkServer.SendToReady(gameObject, 42, animationTriggerMessage);
}
}
internal static void OnAnimationServerMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(AnimationMessage);
var localObject = NetworkServer.FindLocalObject(AnimationMessage.netId);
if (localObject == null)
{
return;
}
var component = localObject.GetComponent<QSBNetworkAnimator>();
var reader = new NetworkReader(AnimationMessage.parameters);
component?.HandleAnimMsg(AnimationMessage, reader);
NetworkServer.SendToReady(localObject, 40, AnimationMessage);
}
internal static void OnAnimationParametersServerMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(ParametersMessage);
var localObject = NetworkServer.FindLocalObject(ParametersMessage.netId);
if (localObject == null)
{
return;
}
var component = localObject.GetComponent<QSBNetworkAnimator>();
var reader = new NetworkReader(ParametersMessage.parameters);
component?.HandleAnimParamsMsg(ParametersMessage, reader);
NetworkServer.SendToReady(localObject, 41, ParametersMessage);
}
internal static void OnAnimationTriggerServerMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(TriggersMessage);
var localObject = NetworkServer.FindLocalObject(TriggersMessage.netId);
if (localObject == null)
{
return;
}
var component = localObject.GetComponent<QSBNetworkAnimator>();
component?.HandleAnimTriggerMsg(TriggersMessage.hash);
NetworkServer.SendToReady(localObject, 42, TriggersMessage);
}
internal static void OnAnimationClientMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(AnimationMessage);
var localObject = ClientScene.FindLocalObject(AnimationMessage.netId);
if (localObject == null)
return;
var component = localObject.GetComponent<QSBNetworkAnimator>();
if (component == null)
return;
var reader = new NetworkReader(AnimationMessage.parameters);
component.HandleAnimMsg(AnimationMessage, reader);
}
internal static void OnAnimationParametersClientMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(ParametersMessage);
var localObject = ClientScene.FindLocalObject(ParametersMessage.netId);
if (localObject == null)
return;
var component = localObject.GetComponent<QSBNetworkAnimator>();
if (component == null)
return;
var reader = new NetworkReader(ParametersMessage.parameters);
component.HandleAnimParamsMsg(ParametersMessage, reader);
}
internal static void OnAnimationTriggerClientMessage(NetworkMessage netMsg)
{
netMsg.ReadMessage(TriggersMessage);
var localObject = ClientScene.FindLocalObject(TriggersMessage.netId);
if (localObject == null)
return;
var component = localObject.GetComponent<QSBNetworkAnimator>();
if (component == null)
return;
component.HandleAnimTriggerMsg(TriggersMessage.hash);
}
}
}

View File

@ -11,134 +11,135 @@ using UnityEngine.UI;
namespace QSB.ConversationSync
{
public class ConversationManager : MonoBehaviour
{
public static ConversationManager Instance { get; private set; }
public AssetBundle ConversationAssetBundle { get; private set; }
private GameObject BoxPrefab;
public Dictionary<CharacterDialogueTree, GameObject> BoxMappings = new Dictionary<CharacterDialogueTree, GameObject>();
public class ConversationManager : MonoBehaviour
{
public static ConversationManager Instance { get; private set; }
public AssetBundle ConversationAssetBundle { get; private set; }
private GameObject BoxPrefab;
public Dictionary<CharacterDialogueTree, GameObject> BoxMappings = new Dictionary<CharacterDialogueTree, GameObject>();
private void Start()
{
Instance = this;
private void Start()
{
Instance = this;
ConversationAssetBundle = QSB.Helper.Assets.LoadBundle("assets/conversation");
ConversationAssetBundle = QSB.Helper.Assets.LoadBundle("assets/conversation");
BoxPrefab = ConversationAssetBundle.LoadAsset<GameObject>("assets/dialoguebubble.prefab");
var font = (Font)Resources.Load(@"fonts\english - latin\spacemono-bold");
if (font == null)
{
DebugLog.ToConsole("Error - Font is null!", MessageType.Error);
}
BoxPrefab.GetComponent<Text>().font = font;
BoxPrefab.GetComponent<Text>().color = Color.white;
}
BoxPrefab = ConversationAssetBundle.LoadAsset<GameObject>("assets/dialoguebubble.prefab");
// TODO : make dynamic so it can be different sizes!
var font = (Font)Resources.Load(@"fonts\english - latin\spacemono-bold");
if (font == null)
{
DebugLog.ToConsole("Error - Font is null!", MessageType.Error);
}
BoxPrefab.GetComponent<Text>().font = font;
BoxPrefab.GetComponent<Text>().color = Color.white;
}
public uint GetPlayerTalkingToTree(CharacterDialogueTree tree)
{
var treeIndex = WorldRegistry.OldDialogueTrees.IndexOf(tree);
if (!QSBPlayerManager.PlayerList.Any(x => x.CurrentDialogueID == treeIndex))
{
// No player talking to tree
return uint.MaxValue;
}
// .First() should be fine here as only one player should be talking to a character.
return QSBPlayerManager.PlayerList.First(x => x.CurrentDialogueID == treeIndex).PlayerId;
}
public uint GetPlayerTalkingToTree(CharacterDialogueTree tree)
{
var treeIndex = WorldRegistry.OldDialogueTrees.IndexOf(tree);
if (!QSBPlayerManager.PlayerList.Any(x => x.CurrentDialogueID == treeIndex))
{
// No player talking to tree
return uint.MaxValue;
}
// .First() should be fine here as only one player should be talking to a character.
return QSBPlayerManager.PlayerList.First(x => x.CurrentDialogueID == treeIndex).PlayerId;
}
public void SendPlayerOption(string text)
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, QSBPlayerManager.LocalPlayerId, text, ConversationType.Player);
}
public void SendPlayerOption(string text)
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, QSBPlayerManager.LocalPlayerId, text, ConversationType.Player);
}
public void SendCharacterDialogue(int id, string text)
{
if (id == -1)
{
DebugLog.ToConsole("Warning - Tried to send conv. event with char id -1.", MessageType.Warning);
return;
}
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, (uint)id, text, ConversationType.Character);
}
public void SendCharacterDialogue(int id, string text)
{
if (id == -1)
{
DebugLog.ToConsole("Warning - Tried to send conv. event with char id -1.", MessageType.Warning);
return;
}
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, (uint)id, text, ConversationType.Character);
}
public void CloseBoxPlayer()
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, QSBPlayerManager.LocalPlayerId, "", ConversationType.ClosePlayer);
}
public void CloseBoxPlayer()
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, QSBPlayerManager.LocalPlayerId, "", ConversationType.ClosePlayer);
}
public void CloseBoxCharacter(int id)
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, (uint)id, "", ConversationType.CloseCharacter);
}
public void CloseBoxCharacter(int id)
{
GlobalMessenger<uint, string, ConversationType>
.FireEvent(EventNames.QSBConversation, (uint)id, "", ConversationType.CloseCharacter);
}
public void SendConvState(int charId, bool state)
{
if (charId == -1)
{
DebugLog.ToConsole("Warning - Tried to send conv. start/end event with char id -1.", MessageType.Warning);
return;
}
GlobalMessenger<int, uint, bool>
.FireEvent(EventNames.QSBConversationStartEnd, charId, QSBPlayerManager.LocalPlayerId, state);
}
public void SendConvState(int charId, bool state)
{
if (charId == -1)
{
DebugLog.ToConsole("Warning - Tried to send conv. start/end event with char id -1.", MessageType.Warning);
return;
}
GlobalMessenger<int, uint, bool>
.FireEvent(EventNames.QSBConversationStartEnd, charId, QSBPlayerManager.LocalPlayerId, state);
}
public void DisplayPlayerConversationBox(uint playerId, string text)
{
if (playerId == QSBPlayerManager.LocalPlayerId)
{
DebugLog.ToConsole("Error - Cannot display conversation box for local player!", MessageType.Error);
return;
}
public void DisplayPlayerConversationBox(uint playerId, string text)
{
if (playerId == QSBPlayerManager.LocalPlayerId)
{
DebugLog.ToConsole("Error - Cannot display conversation box for local player!", MessageType.Error);
return;
}
var player = QSBPlayerManager.GetPlayer(playerId);
var player = QSBPlayerManager.GetPlayer(playerId);
// Destroy old box if it exists
var playerBox = player.CurrentDialogueBox;
if (playerBox != null)
{
Destroy(playerBox);
}
// Destroy old box if it exists
var playerBox = player.CurrentDialogueBox;
if (playerBox != null)
{
Destroy(playerBox);
}
QSBPlayerManager.GetPlayer(playerId).CurrentDialogueBox = CreateBox(player.Body.transform, 25, text);
}
QSBPlayerManager.GetPlayer(playerId).CurrentDialogueBox = CreateBox(player.Body.transform, 25, text);
}
public void DisplayCharacterConversationBox(int index, string text)
{
if (WorldRegistry.OldDialogueTrees.ElementAtOrDefault(index) == null)
{
DebugLog.ToConsole($"Error - Tried to display character conversation box for id {index}! (Doesn't exist!)", MessageType.Error);
return;
}
public void DisplayCharacterConversationBox(int index, string text)
{
if (WorldRegistry.OldDialogueTrees.ElementAtOrDefault(index) == null)
{
DebugLog.ToConsole($"Error - Tried to display character conversation box for id {index}! (Doesn't exist!)", MessageType.Error);
return;
}
// Remove old box if it exists
var oldDialogueTree = WorldRegistry.OldDialogueTrees[index];
if (BoxMappings.ContainsKey(oldDialogueTree))
{
Destroy(BoxMappings[oldDialogueTree]);
BoxMappings.Remove(oldDialogueTree);
}
// Remove old box if it exists
var oldDialogueTree = WorldRegistry.OldDialogueTrees[index];
if (BoxMappings.ContainsKey(oldDialogueTree))
{
Destroy(BoxMappings[oldDialogueTree]);
BoxMappings.Remove(oldDialogueTree);
}
BoxMappings.Add(oldDialogueTree, CreateBox(oldDialogueTree.gameObject.transform, 2, text));
}
BoxMappings.Add(oldDialogueTree, CreateBox(oldDialogueTree.gameObject.transform, 2, text));
}
private GameObject CreateBox(Transform parent, float vertOffset, string text)
{
var newBox = Instantiate(BoxPrefab);
newBox.SetActive(false);
newBox.transform.parent = parent;
newBox.transform.localPosition = new Vector3(0, vertOffset, 0);
newBox.transform.rotation = parent.rotation;
var lookAt = newBox.AddComponent<FaceActiveCamera>();
lookAt.SetValue("_useLookAt", false);
lookAt.SetValue("_localFacingVector", Vector3.back);
lookAt.SetValue("_localRotationAxis", Vector3.up);
newBox.GetComponent<Text>().text = text;
newBox.SetActive(true);
return newBox;
}
}
}
private GameObject CreateBox(Transform parent, float vertOffset, string text)
{
var newBox = Instantiate(BoxPrefab);
newBox.SetActive(false);
newBox.transform.parent = parent;
newBox.transform.localPosition = new Vector3(0, vertOffset, 0);
newBox.transform.rotation = parent.rotation;
var lookAt = newBox.AddComponent<FaceActiveCamera>();
lookAt.SetValue("_useLookAt", false);
lookAt.SetValue("_localFacingVector", Vector3.back);
lookAt.SetValue("_localRotationAxis", Vector3.up);
newBox.GetComponent<Text>().text = text;
newBox.SetActive(true);
return newBox;
}
}
}

View File

@ -7,108 +7,108 @@ using UnityEngine;
namespace QSB.ConversationSync
{
public class ConversationPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public class ConversationPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public static void StartConversation(CharacterDialogueTree __instance)
{
var index = WorldRegistry.OldDialogueTrees.FindIndex(x => x == __instance);
if (index == -1)
{
DebugLog.ToConsole($"Warning - Index for tree {__instance.name} was -1.", MessageType.Warning);
}
QSBPlayerManager.LocalPlayer.CurrentDialogueID = index;
ConversationManager.Instance.SendConvState(index, true);
}
public static void StartConversation(CharacterDialogueTree __instance)
{
var index = WorldRegistry.OldDialogueTrees.FindIndex(x => x == __instance);
if (index == -1)
{
DebugLog.ToConsole($"Warning - Index for tree {__instance.name} was -1.", MessageType.Warning);
}
QSBPlayerManager.LocalPlayer.CurrentDialogueID = index;
ConversationManager.Instance.SendConvState(index, true);
}
public static bool EndConversation(CharacterDialogueTree __instance)
{
if (!__instance.enabled)
{
return false;
}
if (QSBPlayerManager.LocalPlayer.CurrentDialogueID == -1)
{
DebugLog.ToConsole($"Warning - Ending conversation with CurrentDialogueId of -1! Called from {__instance.name}", MessageType.Warning);
return false;
}
ConversationManager.Instance.SendConvState(QSBPlayerManager.LocalPlayer.CurrentDialogueID, false);
ConversationManager.Instance.CloseBoxCharacter(QSBPlayerManager.LocalPlayer.CurrentDialogueID);
QSBPlayerManager.LocalPlayer.CurrentDialogueID = -1;
ConversationManager.Instance.CloseBoxPlayer();
return true;
}
public static bool EndConversation(CharacterDialogueTree __instance)
{
if (!__instance.enabled)
{
return false;
}
if (QSBPlayerManager.LocalPlayer.CurrentDialogueID == -1)
{
DebugLog.ToConsole($"Warning - Ending conversation with CurrentDialogueId of -1! Called from {__instance.name}", MessageType.Warning);
return false;
}
ConversationManager.Instance.SendConvState(QSBPlayerManager.LocalPlayer.CurrentDialogueID, false);
ConversationManager.Instance.CloseBoxCharacter(QSBPlayerManager.LocalPlayer.CurrentDialogueID);
QSBPlayerManager.LocalPlayer.CurrentDialogueID = -1;
ConversationManager.Instance.CloseBoxPlayer();
return true;
}
public static bool InputDialogueOption(int optionIndex, DialogueBoxVer2 ____currentDialogueBox)
{
if (optionIndex < 0)
{
// in a page where there is no selectable options
ConversationManager.Instance.CloseBoxPlayer();
return true;
}
public static bool InputDialogueOption(int optionIndex, DialogueBoxVer2 ____currentDialogueBox)
{
if (optionIndex < 0)
{
// in a page where there is no selectable options
ConversationManager.Instance.CloseBoxPlayer();
return true;
}
var selectedOption = ____currentDialogueBox.OptionFromUIIndex(optionIndex);
ConversationManager.Instance.SendPlayerOption(selectedOption.Text);
return true;
}
var selectedOption = ____currentDialogueBox.OptionFromUIIndex(optionIndex);
ConversationManager.Instance.SendPlayerOption(selectedOption.Text);
return true;
}
public static void GetNextPage(string ____name, List<string> ____listPagesToDisplay, int ____currentPage)
{
var key = ____name + ____listPagesToDisplay[____currentPage];
// Sending key so translation can be done on client side - should make different language-d clients compatible
QSB.Helper.Events.Unity.RunWhen(() => QSBPlayerManager.LocalPlayer.CurrentDialogueID != -1,
() => ConversationManager.Instance.SendCharacterDialogue(QSBPlayerManager.LocalPlayer.CurrentDialogueID, key));
}
public static void GetNextPage(string ____name, List<string> ____listPagesToDisplay, int ____currentPage)
{
var key = ____name + ____listPagesToDisplay[____currentPage];
// Sending key so translation can be done on client side - should make different language-d clients compatible
QSB.Helper.Events.Unity.RunWhen(() => QSBPlayerManager.LocalPlayer.CurrentDialogueID != -1,
() => ConversationManager.Instance.SendCharacterDialogue(QSBPlayerManager.LocalPlayer.CurrentDialogueID, key));
}
public static bool OnAnimatorIK(float ___headTrackingWeight,
bool ___lookOnlyWhenTalking,
bool ____playerInHeadZone,
bool ____inConversation,
ref float ____currentLookWeight,
ref Vector3 ____currentLookTarget,
DampedSpring3D ___lookSpring,
Animator ____animator,
CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
Vector3 position;
if (playerId == uint.MaxValue)
{
// TODO : Find closest player and track to that camera.
position = Locator.GetActiveCamera().transform.position;
}
else
{
position = QSBPlayerManager.GetPlayer(playerId).Camera.transform.position;
}
float b = ___headTrackingWeight * Mathf.Min(1, (!___lookOnlyWhenTalking) ? ((!____playerInHeadZone) ? 0 : 1) : ((!____inConversation || !____playerInHeadZone) ? 0 : 1));
____currentLookWeight = Mathf.Lerp(____currentLookWeight, b, Time.deltaTime * 2f);
____currentLookTarget = ___lookSpring.Update(____currentLookTarget, position, Time.deltaTime);
____animator.SetLookAtPosition(____currentLookTarget);
____animator.SetLookAtWeight(____currentLookWeight);
return false;
}
public static bool OnAnimatorIK(float ___headTrackingWeight,
bool ___lookOnlyWhenTalking,
bool ____playerInHeadZone,
bool ____inConversation,
ref float ____currentLookWeight,
ref Vector3 ____currentLookTarget,
DampedSpring3D ___lookSpring,
Animator ____animator,
CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
Vector3 position;
if (playerId == uint.MaxValue)
{
// TODO : Find closest player and track to that camera.
position = Locator.GetActiveCamera().transform.position;
}
else
{
position = QSBPlayerManager.GetPlayer(playerId).Camera.transform.position;
}
float b = ___headTrackingWeight * Mathf.Min(1, (!___lookOnlyWhenTalking) ? ((!____playerInHeadZone) ? 0 : 1) : ((!____inConversation || !____playerInHeadZone) ? 0 : 1));
____currentLookWeight = Mathf.Lerp(____currentLookWeight, b, Time.deltaTime * 2f);
____currentLookTarget = ___lookSpring.Update(____currentLookTarget, position, Time.deltaTime);
____animator.SetLookAtPosition(____currentLookTarget);
____animator.SetLookAtWeight(____currentLookWeight);
return false;
}
public static bool OnZoneExit(CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
if (playerId == uint.MaxValue)
{
return true;
}
return false;
}
public static bool OnZoneExit(CharacterDialogueTree ____dialogueTree)
{
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(____dialogueTree);
if (playerId == uint.MaxValue)
{
return true;
}
return false;
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<DialogueNode>("GetNextPage", typeof(ConversationPatches), nameof(GetNextPage));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterDialogueTree>("InputDialogueOption", typeof(ConversationPatches), nameof(InputDialogueOption));
QSB.Helper.HarmonyHelper.AddPostfix<CharacterDialogueTree>("StartConversation", typeof(ConversationPatches), nameof(StartConversation));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterDialogueTree>("EndConversation", typeof(ConversationPatches), nameof(EndConversation));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterAnimController>("OnAnimatorIK", typeof(ConversationPatches), nameof(OnAnimatorIK));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterAnimController>("OnZoneExit", typeof(ConversationPatches), nameof(OnZoneExit));
}
}
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<DialogueNode>("GetNextPage", typeof(ConversationPatches), nameof(GetNextPage));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterDialogueTree>("InputDialogueOption", typeof(ConversationPatches), nameof(InputDialogueOption));
QSB.Helper.HarmonyHelper.AddPostfix<CharacterDialogueTree>("StartConversation", typeof(ConversationPatches), nameof(StartConversation));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterDialogueTree>("EndConversation", typeof(ConversationPatches), nameof(EndConversation));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterAnimController>("OnAnimatorIK", typeof(ConversationPatches), nameof(OnAnimatorIK));
QSB.Helper.HarmonyHelper.AddPrefix<CharacterAnimController>("OnZoneExit", typeof(ConversationPatches), nameof(OnZoneExit));
}
}
}

View File

@ -1,10 +1,10 @@
namespace QSB.ConversationSync
{
public enum ConversationType
{
Character,
Player,
CloseCharacter,
ClosePlayer
}
}
public enum ConversationType
{
Character,
Player,
CloseCharacter,
ClosePlayer
}
}

View File

@ -4,47 +4,50 @@ using QSB.WorldSync;
namespace QSB.ConversationSync.Events
{
public class ConversationEvent : QSBEvent<ConversationMessage>
{
public override EventType Type => EventType.Conversation;
public class ConversationEvent : QSBEvent<ConversationMessage>
{
public override EventType Type => EventType.Conversation;
public override void SetupListener() => GlobalMessenger<uint, string, ConversationType>.AddListener(EventNames.QSBConversation, Handler);
public override void SetupListener() => GlobalMessenger<uint, string, ConversationType>.AddListener(EventNames.QSBConversation, Handler);
public override void CloseListener() => GlobalMessenger<uint, string, ConversationType>.RemoveListener(EventNames.QSBConversation, Handler);
public override void CloseListener() => GlobalMessenger<uint, string, ConversationType>.RemoveListener(EventNames.QSBConversation, Handler);
private void Handler(uint id, string message, ConversationType type) => SendEvent(CreateMessage(id, message, type));
private void Handler(uint id, string message, ConversationType type) => SendEvent(CreateMessage(id, message, type));
private ConversationMessage CreateMessage(uint id, string message, ConversationType type) => new ConversationMessage
{
AboutId = LocalPlayerId,
ObjectId = (int)id,
Type = type,
Message = message
};
private ConversationMessage CreateMessage(uint id, string message, ConversationType type) => new ConversationMessage
{
AboutId = LocalPlayerId,
ObjectId = (int)id,
Type = type,
Message = message
};
public override void OnReceiveRemote(ConversationMessage message)
{
switch (message.Type)
{
case ConversationType.Character:
var translated = TextTranslation.Translate(message.Message).Trim();
ConversationManager.Instance.DisplayCharacterConversationBox(message.ObjectId, translated);
break;
case ConversationType.Player:
ConversationManager.Instance.DisplayPlayerConversationBox((uint)message.ObjectId, message.Message);
break;
case ConversationType.CloseCharacter:
if (message.ObjectId == -1)
{
break;
}
var tree = WorldRegistry.OldDialogueTrees[message.ObjectId];
UnityEngine.Object.Destroy(ConversationManager.Instance.BoxMappings[tree]);
break;
case ConversationType.ClosePlayer:
UnityEngine.Object.Destroy(QSBPlayerManager.GetPlayer((uint)message.ObjectId).CurrentDialogueBox);
break;
}
}
}
}
public override void OnReceiveRemote(ConversationMessage message)
{
switch (message.Type)
{
case ConversationType.Character:
var translated = TextTranslation.Translate(message.Message).Trim();
ConversationManager.Instance.DisplayCharacterConversationBox(message.ObjectId, translated);
break;
case ConversationType.Player:
ConversationManager.Instance.DisplayPlayerConversationBox((uint)message.ObjectId, message.Message);
break;
case ConversationType.CloseCharacter:
if (message.ObjectId == -1)
{
break;
}
var tree = WorldRegistry.OldDialogueTrees[message.ObjectId];
UnityEngine.Object.Destroy(ConversationManager.Instance.BoxMappings[tree]);
break;
case ConversationType.ClosePlayer:
UnityEngine.Object.Destroy(QSBPlayerManager.GetPlayer((uint)message.ObjectId).CurrentDialogueBox);
break;
}
}
}
}

View File

@ -1,28 +1,28 @@
using QSB.Messaging;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.ConversationSync.Events
{
public class ConversationMessage : PlayerMessage
{
public ConversationType Type { get; set; }
public int ObjectId { get; set; }
public string Message { get; set; }
public class ConversationMessage : PlayerMessage
{
public ConversationType Type { get; set; }
public int ObjectId { get; set; }
public string Message { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
ObjectId = reader.ReadInt32();
Type = (ConversationType)reader.ReadInt32();
Message = reader.ReadString();
}
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
ObjectId = reader.ReadInt32();
Type = (ConversationType)reader.ReadInt32();
Message = reader.ReadString();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(ObjectId);
writer.Write((int)Type);
writer.Write(Message);
}
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(ObjectId);
writer.Write((int)Type);
writer.Write(Message);
}
}
}

View File

@ -9,62 +9,62 @@ using UnityEngine;
namespace QSB.ConversationSync.Events
{
public class ConversationStartEndEvent : QSBEvent<ConversationStartEndMessage>
{
public override EventsCore.EventType Type => EventsCore.EventType.ConversationStartEnd;
public class ConversationStartEndEvent : QSBEvent<ConversationStartEndMessage>
{
public override EventsCore.EventType Type => EventsCore.EventType.ConversationStartEnd;
public override void SetupListener() => GlobalMessenger<int, uint, bool>.AddListener(EventNames.QSBConversationStartEnd, Handler);
public override void SetupListener() => GlobalMessenger<int, uint, bool>.AddListener(EventNames.QSBConversationStartEnd, Handler);
public override void CloseListener() => GlobalMessenger<int, uint, bool>.RemoveListener(EventNames.QSBConversationStartEnd, Handler);
public override void CloseListener() => GlobalMessenger<int, uint, bool>.RemoveListener(EventNames.QSBConversationStartEnd, Handler);
private void Handler(int charId, uint playerId, bool state) => SendEvent(CreateMessage(charId, playerId, state));
private void Handler(int charId, uint playerId, bool state) => SendEvent(CreateMessage(charId, playerId, state));
private ConversationStartEndMessage CreateMessage(int charId, uint playerId, bool state) => new ConversationStartEndMessage
{
AboutId = LocalPlayerId,
CharacterId = charId,
PlayerId = playerId,
State = state
};
private ConversationStartEndMessage CreateMessage(int charId, uint playerId, bool state) => new ConversationStartEndMessage
{
AboutId = LocalPlayerId,
CharacterId = charId,
PlayerId = playerId,
State = state
};
public override void OnReceiveRemote(ConversationStartEndMessage message)
{
if (message.CharacterId == -1)
{
DebugLog.ToConsole("Warning - Received conv. start/end event with char id -1.", MessageType.Warning);
return;
}
var dialogueTree = WorldRegistry.OldDialogueTrees[message.CharacterId];
var animController = Resources.FindObjectsOfTypeAll<CharacterAnimController>().FirstOrDefault(x => x.GetValue<CharacterDialogueTree>("_dialogueTree") == dialogueTree);
public override void OnReceiveRemote(ConversationStartEndMessage message)
{
if (message.CharacterId == -1)
{
DebugLog.ToConsole("Warning - Received conv. start/end event with char id -1.", MessageType.Warning);
return;
}
var dialogueTree = WorldRegistry.OldDialogueTrees[message.CharacterId];
var animController = Resources.FindObjectsOfTypeAll<CharacterAnimController>().FirstOrDefault(x => x.GetValue<CharacterDialogueTree>("_dialogueTree") == dialogueTree);
// Make character face player and talk
if (animController != default(CharacterAnimController))
{
if (message.State)
{
// Start talking
QSBPlayerManager.GetPlayer(message.PlayerId).CurrentDialogueID = message.CharacterId;
animController.SetValue("_inConversation", true);
animController.SetValue("_playerInHeadZone", true);
if (animController.GetValue<bool>("_hasTalkAnimation"))
{
animController.GetValue<Animator>("_animator").SetTrigger("Talking");
}
dialogueTree.GetComponent<InteractVolume>().DisableInteraction();
}
else
{
// Stop talking
QSBPlayerManager.GetPlayer(message.PlayerId).CurrentDialogueID = -1;
animController.SetValue("_inConversation", false);
animController.SetValue("_playerInHeadZone", false);
if (animController.GetValue<bool>("_hasTalkAnimation"))
{
animController.GetValue<Animator>("_animator").SetTrigger("Idle");
}
dialogueTree.GetComponent<InteractVolume>().EnableInteraction();
}
}
}
}
}
// Make character face player and talk
if (animController != default(CharacterAnimController))
{
if (message.State)
{
// Start talking
QSBPlayerManager.GetPlayer(message.PlayerId).CurrentDialogueID = message.CharacterId;
animController.SetValue("_inConversation", true);
animController.SetValue("_playerInHeadZone", true);
if (animController.GetValue<bool>("_hasTalkAnimation"))
{
animController.GetValue<Animator>("_animator").SetTrigger("Talking");
}
dialogueTree.GetComponent<InteractVolume>().DisableInteraction();
}
else
{
// Stop talking
QSBPlayerManager.GetPlayer(message.PlayerId).CurrentDialogueID = -1;
animController.SetValue("_inConversation", false);
animController.SetValue("_playerInHeadZone", false);
if (animController.GetValue<bool>("_hasTalkAnimation"))
{
animController.GetValue<Animator>("_animator").SetTrigger("Idle");
}
dialogueTree.GetComponent<InteractVolume>().EnableInteraction();
}
}
}
}
}

View File

@ -1,28 +1,28 @@
using QSB.Messaging;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.ConversationSync.Events
{
public class ConversationStartEndMessage : PlayerMessage
{
public int CharacterId { get; set; }
public uint PlayerId { get; set; }
public bool State { get; set; }
public class ConversationStartEndMessage : PlayerMessage
{
public int CharacterId { get; set; }
public uint PlayerId { get; set; }
public bool State { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
CharacterId = reader.ReadInt32();
PlayerId = reader.ReadUInt32();
State = reader.ReadBoolean();
}
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
CharacterId = reader.ReadInt32();
PlayerId = reader.ReadUInt32();
State = reader.ReadBoolean();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(CharacterId);
writer.Write(PlayerId);
writer.Write(State);
}
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(CharacterId);
writer.Write(PlayerId);
writer.Write(State);
}
}
}

View File

@ -3,34 +3,31 @@ using System.Linq;
namespace QSB.DeathSync
{
public class DeathPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
public class DeathPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
public static bool PreFinishDeathSequence(DeathType deathType)
{
if (RespawnOnDeath.Instance.AllowedDeathTypes.Contains(deathType))
{
// Allow real death
return true;
}
public static bool PreFinishDeathSequence(DeathType deathType)
{
if (RespawnOnDeath.Instance.AllowedDeathTypes.Contains(deathType))
{
// Allow real death
return true;
}
RespawnOnDeath.Instance.ResetShip();
RespawnOnDeath.Instance.ResetPlayer();
RespawnOnDeath.Instance.ResetShip();
RespawnOnDeath.Instance.ResetPlayer();
// Prevent original death method from running.
return false;
}
// Prevent original death method from running.
return false;
}
public static void BroadcastDeath(DeathType deathType)
{
GlobalMessenger<DeathType>.FireEvent(EventNames.QSBPlayerDeath, deathType);
}
public static void BroadcastDeath(DeathType deathType) => GlobalMessenger<DeathType>.FireEvent(EventNames.QSBPlayerDeath, deathType);
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPrefix<DeathManager>("KillPlayer", typeof(DeathPatches), nameof(PreFinishDeathSequence));
QSB.Helper.HarmonyHelper.AddPostfix<DeathManager>("KillPlayer", typeof(DeathPatches), nameof(BroadcastDeath));
}
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPrefix<DeathManager>("KillPlayer", typeof(DeathPatches), nameof(PreFinishDeathSequence));
QSB.Helper.HarmonyHelper.AddPostfix<DeathManager>("KillPlayer", typeof(DeathPatches), nameof(BroadcastDeath));
}
}
}

View File

@ -5,29 +5,29 @@ using QSB.Utility;
namespace QSB.DeathSync.Events
{
public class PlayerDeathEvent : QSBEvent<EnumMessage<DeathType>>
{
public override EventType Type => EventType.PlayerDeath;
public class PlayerDeathEvent : QSBEvent<EnumMessage<DeathType>>
{
public override EventType Type => EventType.PlayerDeath;
public override void SetupListener() => GlobalMessenger<DeathType>.AddListener(EventNames.QSBPlayerDeath, Handler);
public override void SetupListener() => GlobalMessenger<DeathType>.AddListener(EventNames.QSBPlayerDeath, Handler);
public override void CloseListener() => GlobalMessenger<DeathType>.RemoveListener(EventNames.QSBPlayerDeath, Handler);
public override void CloseListener() => GlobalMessenger<DeathType>.RemoveListener(EventNames.QSBPlayerDeath, Handler);
private void Handler(DeathType type) => SendEvent(CreateMessage(type));
private void Handler(DeathType type) => SendEvent(CreateMessage(type));
private EnumMessage<DeathType> CreateMessage(DeathType type) => new EnumMessage<DeathType>
{
AboutId = LocalPlayerId,
Value = type
};
private EnumMessage<DeathType> CreateMessage(DeathType type) => new EnumMessage<DeathType>
{
AboutId = LocalPlayerId,
Value = type
};
public override void OnReceiveRemote(EnumMessage<DeathType> message)
{
var playerName = QSBPlayerManager.GetPlayer(message.AboutId).Name;
var deathMessage = Necronomicon.GetPhrase(message.Value);
DebugLog.ToAll(string.Format(deathMessage, playerName));
}
public override void OnReceiveRemote(EnumMessage<DeathType> message)
{
var playerName = QSBPlayerManager.GetPlayer(message.AboutId).Name;
var deathMessage = Necronomicon.GetPhrase(message.Value);
DebugLog.ToAll(string.Format(deathMessage, playerName));
}
public override void OnReceiveLocal(EnumMessage<DeathType> message) => OnReceiveRemote(message);
}
}
public override void OnReceiveLocal(EnumMessage<DeathType> message) => OnReceiveRemote(message);
}
}

View File

@ -4,102 +4,100 @@ using System.Linq;
namespace QSB.DeathSync
{
public static class Necronomicon
{
public static class Necronomicon
{
private static readonly Dictionary<DeathType, string[]> DeathDictionary = new Dictionary<DeathType, string[]>
{
{ DeathType.Default, new[]
{
"{0} died"
} },
{ DeathType.Impact, new[]
{
"{0} forgot to use retro-rockets",
"{0} bonked into the ground too hard",
"{0} went splat"
} },
{ DeathType.Asphyxiation, new[]
{
"{0} forgot to breathe",
"{0} forgot how to breathe",
"{0} forgot to check their oxygen meter",
"{0} lacked oxygen",
"{0} didn't need air anyway"
} },
{ DeathType.Energy, new[]
{
"{0} was cooked",
"{0} failed the Hotshot achievement",
"{0} forgot to install an AC unit",
"{0} got too hot"
} },
{ DeathType.Supernova, new[]
{
"{0} ran out of time",
"{0} got vaporized",
"{0} lost track of time",
"{0} got front row seats to the supernova",
"{0} heard the End of Times music",
"{0} watched the sun go kaboom",
"{0} became cosmic marshmallow",
"{0} photosynthesized too much"
} },
{ DeathType.Digestion, new[]
{
"{0} was eaten",
"{0} found a fish",
"{0} encountered an evil creature",
"{0} followed the light, then was followed by it",
"{0} messed with the wrong species of fish"
} },
{ DeathType.BigBang, new[]
{
"{0} sacrificed themself for the universe",
"{0} knows the true meaning of sacrifice",
"{0} won at the cost of their life"
} },
{ DeathType.Crushed, new[]
{
"{0} went through the tunnel too slow",
"{0} didn't make it out in time",
"{0} was squished",
"{0} thought the Sunless City was safe",
"{0} was buried"
} },
{ DeathType.Meditation, new[]
{
"{0} took a deep breath and died",
"{0} fell asleep",
"{0} got killed by Gabbro's advice"
} },
{ DeathType.TimeLoop, new[]
{
"{0} ran out of time",
"{0} was caught by a statue",
"{0}'s memories were pilfered",
"{0}'s memories fell into a black hole",
"{0}'s universe was eaten by Grobletombus"
} },
{ DeathType.Lava, new[]
{
"{0} tried to swim in lava",
"{0} didn't know what the glowy orange liquid was",
"{0} slipped in lava",
"{0} became one with the glowing gooey rock"
} },
{ DeathType.BlackHole, new[]
{
"{0} should visit the Ash Twin Project again",
"{0} waited inside the Ash Twin Project",
"{0} chased their memories"
} }
};
private static readonly Dictionary<DeathType, string[]> DeathDictionary = new Dictionary<DeathType, string[]>
{
{ DeathType.Default, new[]
{
"{0} died"
} },
{ DeathType.Impact, new[]
{
"{0} forgot to use retro-rockets",
"{0} bonked into the ground too hard",
"{0} went splat"
} },
{ DeathType.Asphyxiation, new[]
{
"{0} forgot to breathe",
"{0} forgot how to breathe",
"{0} forgot to check their oxygen meter",
"{0} lacked oxygen",
"{0} didn't need air anyway"
} },
{ DeathType.Energy, new[]
{
"{0} was cooked",
"{0} failed the Hotshot achievement",
"{0} forgot to install an AC unit",
"{0} got too hot"
} },
{ DeathType.Supernova, new[]
{
"{0} ran out of time",
"{0} got vaporized",
"{0} lost track of time",
"{0} got front row seats to the supernova",
"{0} heard the End of Times music",
"{0} watched the sun go kaboom",
"{0} became cosmic marshmallow",
"{0} photosynthesized too much"
} },
{ DeathType.Digestion, new[]
{
"{0} was eaten",
"{0} found a fish",
"{0} encountered an evil creature",
"{0} followed the light, then was followed by it",
"{0} messed with the wrong species of fish"
} },
{ DeathType.BigBang, new[]
{
"{0} sacrificed themself for the universe",
"{0} knows the true meaning of sacrifice",
"{0} won at the cost of their life"
} },
{ DeathType.Crushed, new[]
{
"{0} went through the tunnel too slow",
"{0} didn't make it out in time",
"{0} was squished",
"{0} thought the Sunless City was safe",
"{0} was buried"
} },
{ DeathType.Meditation, new[]
{
"{0} took a deep breath and died",
"{0} fell asleep",
"{0} got killed by Gabbro's advice"
} },
{ DeathType.TimeLoop, new[]
{
"{0} ran out of time",
"{0} was caught by a statue",
"{0}'s memories were pilfered",
"{0}'s memories fell into a black hole",
"{0}'s universe was eaten by Grobletombus"
} },
{ DeathType.Lava, new[]
{
"{0} tried to swim in lava",
"{0} didn't know what the glowy orange liquid was",
"{0} slipped in lava",
"{0} became one with the glowing gooey rock"
} },
{ DeathType.BlackHole, new[]
{
"{0} should visit the Ash Twin Project again",
"{0} waited inside the Ash Twin Project",
"{0} chased their memories"
} }
};
public static string GetPhrase(DeathType deathType)
{
return DeathDictionary[deathType].OrderBy(x => Guid.NewGuid()).First();
}
}
}
public static string GetPhrase(DeathType deathType)
{
return DeathDictionary[deathType].OrderBy(x => Guid.NewGuid()).First();
}
}
}

View File

@ -6,38 +6,38 @@ using UnityEngine;
namespace QSB.DeathSync
{
public class PreventShipDestruction : MonoBehaviour
{
private void Awake()
{
QSB.Helper.HarmonyHelper.Transpile<ShipDetachableLeg>("Detach", typeof(Patch), nameof(Patch.ReturnNull));
QSB.Helper.HarmonyHelper.Transpile<ShipDetachableModule>("Detach", typeof(Patch), nameof(Patch.ReturnNull));
public class PreventShipDestruction : MonoBehaviour
{
private void Awake()
{
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.HarmonyHelper.EmptyMethod<ShipEjectionSystem>("OnPressInteract");
QSB.Helper.Events.Subscribe<ShipDamageController>(OWML.Common.Events.AfterAwake);
QSB.Helper.Events.Event += OnEvent;
}
QSB.Helper.Events.Subscribe<ShipDamageController>(OWML.Common.Events.AfterAwake);
QSB.Helper.Events.Event += OnEvent;
}
private void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)
{
if (behaviour is ShipDamageController shipDamageController &&
ev == OWML.Common.Events.AfterAwake)
{
shipDamageController.SetValue("_exploded", true);
}
}
private void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)
{
if (behaviour is ShipDamageController shipDamageController &&
ev == OWML.Common.Events.AfterAwake)
{
shipDamageController.SetValue("_exploded", true);
}
}
private static class Patch
{
public static IEnumerable<CodeInstruction> ReturnNull(IEnumerable<CodeInstruction> instructions)
{
return new List<CodeInstruction>
{
new CodeInstruction(OpCodes.Ldnull),
new CodeInstruction(OpCodes.Ret)
};
}
}
}
}
private static class Patch
{
public static IEnumerable<CodeInstruction> ReturnNull(IEnumerable<CodeInstruction> instructions)
{
return new List<CodeInstruction>
{
new CodeInstruction(OpCodes.Ldnull),
new CodeInstruction(OpCodes.Ret)
};
}
}
}
}

View File

@ -7,133 +7,133 @@ using UnityEngine;
namespace QSB.DeathSync
{
/// <summary>
/// Client-only-side component for managing respawning after death.
/// </summary>
public class RespawnOnDeath : MonoBehaviour
{
public static RespawnOnDeath Instance;
/// <summary>
/// Client-only-side component for managing respawning after death.
/// </summary>
public class RespawnOnDeath : MonoBehaviour
{
public static RespawnOnDeath Instance;
public readonly DeathType[] AllowedDeathTypes = {
DeathType.BigBang,
DeathType.Supernova,
DeathType.TimeLoop
};
public readonly DeathType[] AllowedDeathTypes = {
DeathType.BigBang,
DeathType.Supernova,
DeathType.TimeLoop
};
private SpawnPoint _shipSpawnPoint;
private SpawnPoint _playerSpawnPoint;
private OWRigidbody _shipBody;
private PlayerSpawner _playerSpawner;
private FluidDetector _fluidDetector;
private PlayerResources _playerResources;
private ShipComponent[] _shipComponents;
private HatchController _hatchController;
private ShipCockpitController _cockpitController;
private PlayerSpacesuit _spaceSuit;
private SpawnPoint _shipSpawnPoint;
private SpawnPoint _playerSpawnPoint;
private OWRigidbody _shipBody;
private PlayerSpawner _playerSpawner;
private FluidDetector _fluidDetector;
private PlayerResources _playerResources;
private ShipComponent[] _shipComponents;
private HatchController _hatchController;
private ShipCockpitController _cockpitController;
private PlayerSpacesuit _spaceSuit;
private void Awake()
{
Instance = this;
private void Awake()
{
Instance = this;
QSB.Helper.Events.Subscribe<PlayerResources>(OWML.Common.Events.AfterStart);
QSB.Helper.Events.Event += OnEvent;
}
QSB.Helper.Events.Subscribe<PlayerResources>(OWML.Common.Events.AfterStart);
QSB.Helper.Events.Event += OnEvent;
}
private void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)
{
if (behaviour is PlayerResources && ev == OWML.Common.Events.AfterStart)
{
Init();
}
}
private void OnEvent(MonoBehaviour behaviour, OWML.Common.Events ev)
{
if (behaviour is PlayerResources && ev == OWML.Common.Events.AfterStart)
{
Init();
}
}
public void Init()
{
var playerTransform = Locator.GetPlayerTransform();
_playerResources = playerTransform.GetComponent<PlayerResources>();
_spaceSuit = playerTransform.GetComponentInChildren<PlayerSpacesuit>(true);
_playerSpawner = FindObjectOfType<PlayerSpawner>();
_fluidDetector = Locator.GetPlayerCamera().GetComponentInChildren<FluidDetector>();
public void Init()
{
var playerTransform = Locator.GetPlayerTransform();
_playerResources = playerTransform.GetComponent<PlayerResources>();
_spaceSuit = playerTransform.GetComponentInChildren<PlayerSpacesuit>(true);
_playerSpawner = FindObjectOfType<PlayerSpawner>();
_fluidDetector = Locator.GetPlayerCamera().GetComponentInChildren<FluidDetector>();
var shipTransform = Locator.GetShipTransform();
if (shipTransform == null)
{
return;
}
_shipComponents = shipTransform.GetComponentsInChildren<ShipComponent>();
_hatchController = shipTransform.GetComponentInChildren<HatchController>();
_cockpitController = shipTransform.GetComponentInChildren<ShipCockpitController>();
_shipBody = Locator.GetShipBody();
_shipSpawnPoint = GetSpawnPoint(true);
var shipTransform = Locator.GetShipTransform();
if (shipTransform == null)
{
return;
}
_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;
}
// Move debug spawn point to initial ship position.
_playerSpawnPoint = GetSpawnPoint();
_shipSpawnPoint.transform.position = shipTransform.position;
_shipSpawnPoint.transform.rotation = shipTransform.rotation;
}
public void ResetShip()
{
if (_shipBody == null)
{
return;
}
public void ResetShip()
{
if (_shipBody == null)
{
return;
}
// Reset ship position.
if (_shipSpawnPoint == null)
{
DebugLog.ToConsole("_shipSpawnPoint is null!", MessageType.Warning);
return;
}
_shipBody.SetVelocity(_shipSpawnPoint.GetPointVelocity());
_shipBody.WarpToPositionRotation(_shipSpawnPoint.transform.position, _shipSpawnPoint.transform.rotation);
// Reset ship position.
if (_shipSpawnPoint == null)
{
DebugLog.ToConsole("_shipSpawnPoint is null!", MessageType.Warning);
return;
}
_shipBody.SetVelocity(_shipSpawnPoint.GetPointVelocity());
_shipBody.WarpToPositionRotation(_shipSpawnPoint.transform.position, _shipSpawnPoint.transform.rotation);
// Reset ship damage.
if (Locator.GetShipTransform())
{
foreach (var shipComponent in _shipComponents)
{
shipComponent.SetDamaged(false);
}
}
// Reset ship damage.
if (Locator.GetShipTransform())
{
foreach (var shipComponent in _shipComponents)
{
shipComponent.SetDamaged(false);
}
}
Invoke(nameof(ExitShip), 0.01f);
}
Invoke(nameof(ExitShip), 0.01f);
}
private void ExitShip()
{
_cockpitController.Invoke("ExitFlightConsole");
_cockpitController.Invoke("CompleteExitFlightConsole");
_hatchController.SetValue("_isPlayerInShip", false);
_hatchController.Invoke("OpenHatch");
GlobalMessenger.FireEvent(EventNames.ExitShip);
}
private void ExitShip()
{
_cockpitController.Invoke("ExitFlightConsole");
_cockpitController.Invoke("CompleteExitFlightConsole");
_hatchController.SetValue("_isPlayerInShip", false);
_hatchController.Invoke("OpenHatch");
GlobalMessenger.FireEvent(EventNames.ExitShip);
}
public void ResetPlayer()
{
// Reset player position.
var playerBody = Locator.GetPlayerBody();
playerBody.WarpToPositionRotation(_playerSpawnPoint.transform.position, _playerSpawnPoint.transform.rotation);
playerBody.SetVelocity(_playerSpawnPoint.GetPointVelocity());
_playerSpawnPoint.AddObjectToTriggerVolumes(Locator.GetPlayerDetector().gameObject);
_playerSpawnPoint.AddObjectToTriggerVolumes(_fluidDetector.gameObject);
_playerSpawnPoint.OnSpawnPlayer();
public void ResetPlayer()
{
// Reset player position.
var playerBody = Locator.GetPlayerBody();
playerBody.WarpToPositionRotation(_playerSpawnPoint.transform.position, _playerSpawnPoint.transform.rotation);
playerBody.SetVelocity(_playerSpawnPoint.GetPointVelocity());
_playerSpawnPoint.AddObjectToTriggerVolumes(Locator.GetPlayerDetector().gameObject);
_playerSpawnPoint.AddObjectToTriggerVolumes(_fluidDetector.gameObject);
_playerSpawnPoint.OnSpawnPlayer();
// Stop suffocation sound effect.
_playerResources.SetValue("_isSuffocating", false);
// Stop suffocation sound effect.
_playerResources.SetValue("_isSuffocating", false);
// Reset player health and resources.
_playerResources.DebugRefillResources();
// Reset player health and resources.
_playerResources.DebugRefillResources();
// Remove space suit.
_spaceSuit.RemoveSuit(true);
}
// Remove space suit.
_spaceSuit.RemoveSuit(true);
}
private SpawnPoint GetSpawnPoint(bool isShip = false)
{
return _playerSpawner
.GetValue<SpawnPoint[]>("_spawnList")
.FirstOrDefault(spawnPoint => spawnPoint.GetSpawnLocation() == SpawnLocation.TimberHearth && spawnPoint.IsShipSpawn() == isShip);
}
}
}
private SpawnPoint GetSpawnPoint(bool isShip = false)
{
return _playerSpawner
.GetValue<SpawnPoint[]>("_spawnList")
.FirstOrDefault(spawnPoint => spawnPoint.GetSpawnLocation() == SpawnLocation.TimberHearth && spawnPoint.IsShipSpawn() == isShip);
}
}
}

View File

@ -5,34 +5,34 @@ using UnityEngine;
namespace QSB.ElevatorSync
{
public class ElevatorManager : MonoBehaviour
{
public static ElevatorManager Instance { get; private set; }
public class ElevatorManager : MonoBehaviour
{
public static ElevatorManager Instance { get; private set; }
private List<Elevator> _elevators;
private List<Elevator> _elevators;
private void Awake()
{
Instance = this;
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
}
private void Awake()
{
Instance = this;
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
}
private void OnDestroy()
{
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
}
private void OnDestroy()
{
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
{
_elevators = Resources.FindObjectsOfTypeAll<Elevator>().ToList();
for (var id = 0; id < _elevators.Count; id++)
{
var qsbElevator = WorldRegistry.GetObject<QSBElevator>(id) ?? new QSBElevator();
qsbElevator.Init(_elevators[id], id);
WorldRegistry.AddObject(qsbElevator);
}
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
{
_elevators = Resources.FindObjectsOfTypeAll<Elevator>().ToList();
for (var id = 0; id < _elevators.Count; id++)
{
var qsbElevator = WorldRegistry.GetObject<QSBElevator>(id) ?? new QSBElevator();
qsbElevator.Init(_elevators[id], id);
WorldRegistry.AddObject(qsbElevator);
}
}
public int GetId(Elevator elevator) => _elevators.IndexOf(elevator);
}
}
public int GetId(Elevator elevator) => _elevators.IndexOf(elevator);
}
}

View File

@ -3,20 +3,20 @@ using QSB.EventsCore;
namespace QSB.ElevatorSync
{
public class ElevatorPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
public class ElevatorPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
public static void StartLift(Elevator __instance)
{
var isGoingUp = __instance.GetValue<bool>("_goingToTheEnd");
var id = ElevatorManager.Instance.GetId(__instance);
GlobalMessenger<int, bool>.FireEvent(EventNames.QSBStartLift, id, isGoingUp);
}
public static void StartLift(Elevator __instance)
{
var isGoingUp = __instance.GetValue<bool>("_goingToTheEnd");
var id = ElevatorManager.Instance.GetId(__instance);
GlobalMessenger<int, bool>.FireEvent(EventNames.QSBStartLift, id, isGoingUp);
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<Elevator>("StartLift", typeof(ElevatorPatches), nameof(StartLift));
}
}
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<Elevator>("StartLift", typeof(ElevatorPatches), nameof(StartLift));
}
}
}

View File

@ -4,26 +4,26 @@ using QSB.WorldSync.Events;
namespace QSB.ElevatorSync.Events
{
public class ElevatorEvent : QSBEvent<BoolWorldObjectMessage>
{
public override EventType Type => EventType.Elevator;
public class ElevatorEvent : QSBEvent<BoolWorldObjectMessage>
{
public override EventType Type => EventType.Elevator;
public override void SetupListener() => GlobalMessenger<int, bool>.AddListener(EventNames.QSBStartLift, Handler);
public override void SetupListener() => GlobalMessenger<int, bool>.AddListener(EventNames.QSBStartLift, Handler);
public override void CloseListener() => GlobalMessenger<int, bool>.RemoveListener(EventNames.QSBStartLift, Handler);
public override void CloseListener() => GlobalMessenger<int, bool>.RemoveListener(EventNames.QSBStartLift, Handler);
private void Handler(int id, bool isGoingUp) => SendEvent(CreateMessage(id, isGoingUp));
private void Handler(int id, bool isGoingUp) => SendEvent(CreateMessage(id, isGoingUp));
private BoolWorldObjectMessage CreateMessage(int id, bool isGoingUp) => new BoolWorldObjectMessage
{
State = isGoingUp,
ObjectId = id
};
private BoolWorldObjectMessage CreateMessage(int id, bool isGoingUp) => new BoolWorldObjectMessage
{
State = isGoingUp,
ObjectId = id
};
public override void OnReceiveRemote(BoolWorldObjectMessage message)
{
var elevator = WorldRegistry.GetObject<QSBElevator>(message.ObjectId);
elevator?.RemoteCall(message.State);
}
}
}
public override void OnReceiveRemote(BoolWorldObjectMessage message)
{
var elevator = WorldRegistry.GetObject<QSBElevator>(message.ObjectId);
elevator?.RemoteCall(message.State);
}
}
}

View File

@ -4,54 +4,54 @@ using UnityEngine;
namespace QSB.ElevatorSync
{
public class QSBElevator : WorldObject
{
private Elevator _elevator;
private Vector3 _startLocalPos;
private Vector3 _endLocalPos;
public class QSBElevator : WorldObject
{
private Elevator _elevator;
private Vector3 _startLocalPos;
private Vector3 _endLocalPos;
private SingleInteractionVolume _interactVolume;
private OWAudioSource _owAudioSourceOneShot;
private OWAudioSource _owAudioSourceLP;
private SingleInteractionVolume _interactVolume;
private OWAudioSource _owAudioSourceOneShot;
private OWAudioSource _owAudioSourceLP;
public void Init(Elevator elevator, int id)
{
_elevator = elevator;
ObjectId = id;
QSB.Helper.Events.Unity.RunWhen(() => _elevator.GetValue<SingleInteractionVolume>("_interactVolume") != null, InitValues);
}
public void Init(Elevator elevator, int id)
{
_elevator = elevator;
ObjectId = id;
QSB.Helper.Events.Unity.RunWhen(() => _elevator.GetValue<SingleInteractionVolume>("_interactVolume") != null, InitValues);
}
private void InitValues()
{
_startLocalPos = _elevator.GetValue<Vector3>("_startLocalPos");
_endLocalPos = _elevator.GetValue<Vector3>("_endLocalPos");
_interactVolume = _elevator.GetValue<SingleInteractionVolume>("_interactVolume");
_owAudioSourceOneShot = _elevator.GetValue<OWAudioSource>("_owAudioSourceOneShot");
_owAudioSourceLP = _elevator.GetValue<OWAudioSource>("_owAudioSourceLP");
}
private void InitValues()
{
_startLocalPos = _elevator.GetValue<Vector3>("_startLocalPos");
_endLocalPos = _elevator.GetValue<Vector3>("_endLocalPos");
_interactVolume = _elevator.GetValue<SingleInteractionVolume>("_interactVolume");
_owAudioSourceOneShot = _elevator.GetValue<OWAudioSource>("_owAudioSourceOneShot");
_owAudioSourceLP = _elevator.GetValue<OWAudioSource>("_owAudioSourceLP");
}
public void RemoteCall(bool isGoingUp)
{
SetDirection(isGoingUp);
RemoteStartLift();
}
public void RemoteCall(bool isGoingUp)
{
SetDirection(isGoingUp);
RemoteStartLift();
}
private void SetDirection(bool isGoingUp)
{
var targetPos = isGoingUp ? _endLocalPos : _startLocalPos;
_elevator.SetValue("_goingToTheEnd", isGoingUp);
_elevator.SetValue("_targetLocalPos", targetPos);
_interactVolume.transform.Rotate(0f, 180f, 0f);
}
private void SetDirection(bool isGoingUp)
{
var targetPos = isGoingUp ? _endLocalPos : _startLocalPos;
_elevator.SetValue("_goingToTheEnd", isGoingUp);
_elevator.SetValue("_targetLocalPos", targetPos);
_interactVolume.transform.Rotate(0f, 180f, 0f);
}
private void RemoteStartLift()
{
_elevator.enabled = true;
_elevator.SetValue("_initLocalPos", _elevator.transform.localPosition);
_elevator.SetValue("_initLiftTime", Time.time);
_owAudioSourceOneShot.PlayOneShot(AudioType.TH_LiftActivate);
_owAudioSourceLP.FadeIn(0.5f);
_interactVolume.DisableInteraction();
}
}
}
private void RemoteStartLift()
{
_elevator.enabled = true;
_elevator.SetValue("_initLocalPos", _elevator.transform.localPosition);
_elevator.SetValue("_initLiftTime", Time.time);
_owAudioSourceOneShot.PlayOneShot(AudioType.TH_LiftActivate);
_owAudioSourceLP.FadeIn(0.5f);
_interactVolume.DisableInteraction();
}
}
}

View File

@ -1,40 +1,40 @@
namespace QSB.EventsCore
{
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 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";
public static string QSBStartLift = "QSBStartLift";
public static string QSBGeyserState = "QSBGeyserState";
public static string QSBCrouch = "QSBAnimTrigger";
public static string QSBOrbSlot = "QSBOrbSlot";
public static string QSBOrbUser = "QSBOrbUser";
public static string QSBConversation = "QSBConversation";
public static string QSBConversationStartEnd = "QSBConversationStartEnd";
public static string QSBChangeAnimType = "QSBPlayInstrument";
public static string QSBServerSendPlayerStates = "QSBServerSendPlayerStates";
}
}
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";
public static string QSBStartLift = "QSBStartLift";
public static string QSBGeyserState = "QSBGeyserState";
public static string QSBCrouch = "QSBAnimTrigger";
public static string QSBOrbSlot = "QSBOrbSlot";
public static string QSBOrbUser = "QSBOrbUser";
public static string QSBConversation = "QSBConversation";
public static string QSBConversationStartEnd = "QSBConversationStartEnd";
public static string QSBChangeAnimType = "QSBPlayInstrument";
public static string QSBServerSendPlayerStates = "QSBServerSendPlayerStates";
}
}

View File

@ -1,29 +1,29 @@
namespace QSB.EventsCore
{
public enum EventType
{
Sector,
ServerTime,
AnimTrigger,
PlayerState,
PlayerStatesRequest,
FlashlightActiveChange,
SignalscopeActiveChange,
TranslatorActiveChange,
ProbeLauncherActiveChange,
SuitActiveChange,
PlayerJoin,
PlayerLeave,
PlayerDeath,
PlayerSectorChange,
PlayerReady,
ProbeActiveChange,
Elevator,
Geyser,
OrbSlot,
OrbUser,
Conversation,
ConversationStartEnd,
PlayInstrument
}
}
public enum EventType
{
Sector,
ServerTime,
AnimTrigger,
PlayerState,
PlayerStatesRequest,
FlashlightActiveChange,
SignalscopeActiveChange,
TranslatorActiveChange,
ProbeLauncherActiveChange,
SuitActiveChange,
PlayerJoin,
PlayerLeave,
PlayerDeath,
PlayerSectorChange,
PlayerReady,
ProbeActiveChange,
Elevator,
Geyser,
OrbSlot,
OrbUser,
Conversation,
ConversationStartEnd,
PlayInstrument
}
}

View File

@ -1,8 +1,9 @@
namespace QSB.EventsCore
{
public interface IQSBEvent
{
void SetupListener();
void CloseListener();
}
}
public interface IQSBEvent
{
void SetupListener();
void CloseListener();
}
}

View File

@ -1,68 +1,68 @@
using QSB.Messaging;
using QSB.Player;
using QSB.TransformSync;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.EventsCore
{
public abstract class QSBEvent<T> : IQSBEvent where T : PlayerMessage, new()
{
public abstract EventType Type { get; }
public uint LocalPlayerId => QSBPlayerManager.LocalPlayerId;
private readonly MessageHandler<T> _eventHandler;
public abstract class QSBEvent<T> : IQSBEvent where T : PlayerMessage, new()
{
public abstract EventType Type { get; }
public uint LocalPlayerId => QSBPlayerManager.LocalPlayerId;
private readonly MessageHandler<T> _eventHandler;
protected QSBEvent()
{
_eventHandler = new MessageHandler<T>(Type);
_eventHandler.OnClientReceiveMessage += OnClientReceive;
_eventHandler.OnServerReceiveMessage += OnServerReceive;
}
protected QSBEvent()
{
_eventHandler = new MessageHandler<T>(Type);
_eventHandler.OnClientReceiveMessage += OnClientReceive;
_eventHandler.OnServerReceiveMessage += OnServerReceive;
}
public abstract void SetupListener();
public abstract void SetupListener();
public abstract void CloseListener();
public abstract void CloseListener();
public virtual void OnReceiveRemote(T message)
{
}
public virtual void OnReceiveRemote(T message)
{
}
public virtual void OnReceiveLocal(T message)
{
}
public virtual void OnReceiveLocal(T message)
{
}
public virtual void OnServerReceive(T message)
{
_eventHandler.SendToAll(message);
}
public virtual void OnServerReceive(T message)
{
_eventHandler.SendToAll(message);
}
public void SendEvent(T message)
{
message.FromId = QSBPlayerManager.LocalPlayerId;
QSB.Helper.Events.Unity.RunWhen(() => PlayerTransformSync.LocalInstance != null, () => Send(message));
}
public void SendEvent(T message)
{
message.FromId = QSBPlayerManager.LocalPlayerId;
QSB.Helper.Events.Unity.RunWhen(() => PlayerTransformSync.LocalInstance != null, () => Send(message));
}
private void Send(T message)
{
if (NetworkServer.active)
{
_eventHandler.SendToAll(message);
}
else
{
_eventHandler.SendToServer(message);
}
}
private void Send(T message)
{
if (QSBNetworkServer.active)
{
_eventHandler.SendToAll(message);
}
else
{
_eventHandler.SendToServer(message);
}
}
private void OnClientReceive(T message)
{
if (message.FromId == QSBPlayerManager.LocalPlayerId ||
QSBPlayerManager.IsBelongingToLocalPlayer(message.AboutId))
{
OnReceiveLocal(message);
return;
}
private void OnClientReceive(T message)
{
if (message.FromId == QSBPlayerManager.LocalPlayerId ||
QSBPlayerManager.IsBelongingToLocalPlayer(message.AboutId))
{
OnReceiveLocal(message);
return;
}
OnReceiveRemote(message);
}
}
}
OnReceiveRemote(message);
}
}
}

View File

@ -14,54 +14,54 @@ using System.Collections.Generic;
namespace QSB.EventsCore
{
public static class QSBEventManager
{
public static bool Ready { get; private set; }
public static class QSBEventManager
{
public static bool Ready { get; private set; }
private static List<IQSBEvent> _eventList = new List<IQSBEvent>();
private static List<IQSBEvent> _eventList = new List<IQSBEvent>();
public static void Init()
{
_eventList = new List<IQSBEvent>
{
new PlayerReadyEvent(),
new PlayerJoinEvent(),
new PlayerSuitEvent(),
new PlayerFlashlightEvent(),
new PlayerSignalscopeEvent(),
new PlayerTranslatorEvent(),
new PlayerProbeLauncherEvent(),
new PlayerProbeEvent(),
new PlayerSectorEvent(),
new PlayerLeaveEvent(),
new PlayerDeathEvent(),
new PlayerStatesRequestEvent(),
new ElevatorEvent(),
new GeyserEvent(),
new ServerTimeEvent(),
new CrouchEvent(),
new OrbSlotEvent(),
new OrbUserEvent(),
new ConversationEvent(),
new ConversationStartEndEvent(),
new ChangeAnimTypeEvent(),
new ServerSendPlayerStatesEvent()
};
public static void Init()
{
_eventList = new List<IQSBEvent>
{
new PlayerReadyEvent(),
new PlayerJoinEvent(),
new PlayerSuitEvent(),
new PlayerFlashlightEvent(),
new PlayerSignalscopeEvent(),
new PlayerTranslatorEvent(),
new PlayerProbeLauncherEvent(),
new PlayerProbeEvent(),
new PlayerSectorEvent(),
new PlayerLeaveEvent(),
new PlayerDeathEvent(),
new PlayerStatesRequestEvent(),
new ElevatorEvent(),
new GeyserEvent(),
new ServerTimeEvent(),
new CrouchEvent(),
new OrbSlotEvent(),
new OrbUserEvent(),
new ConversationEvent(),
new ConversationStartEndEvent(),
new ChangeAnimTypeEvent(),
new ServerSendPlayerStatesEvent()
};
_eventList.ForEach(ev => ev.SetupListener());
_eventList.ForEach(ev => ev.SetupListener());
Ready = true;
Ready = true;
DebugLog.DebugWrite("Event Manager ready.", MessageType.Success);
}
DebugLog.DebugWrite("Event Manager ready.", MessageType.Success);
}
public static void Reset()
{
Ready = false;
public static void Reset()
{
Ready = false;
_eventList.ForEach(ev => ev.CloseListener());
_eventList.ForEach(ev => ev.CloseListener());
_eventList = new List<IQSBEvent>();
}
}
}
_eventList = new List<IQSBEvent>();
}
}
}

View File

@ -4,33 +4,33 @@ using QSB.WorldSync.Events;
namespace QSB.GeyserSync.Events
{
public class GeyserEvent : QSBEvent<BoolWorldObjectMessage>
{
public override EventType Type => EventType.Geyser;
public class GeyserEvent : QSBEvent<BoolWorldObjectMessage>
{
public override EventType Type => EventType.Geyser;
public override void SetupListener()
{
GlobalMessenger<int, bool>.AddListener(EventNames.QSBGeyserState, Handler);
}
public override void SetupListener()
{
GlobalMessenger<int, bool>.AddListener(EventNames.QSBGeyserState, Handler);
}
public override void CloseListener()
{
GlobalMessenger<int, bool>.RemoveListener(EventNames.QSBGeyserState, Handler);
}
public override void CloseListener()
{
GlobalMessenger<int, bool>.RemoveListener(EventNames.QSBGeyserState, Handler);
}
private void Handler(int id, bool state) => SendEvent(CreateMessage(id, state));
private void Handler(int id, bool state) => SendEvent(CreateMessage(id, state));
private BoolWorldObjectMessage CreateMessage(int id, bool state) => new BoolWorldObjectMessage
{
AboutId = LocalPlayerId,
ObjectId = id,
State = state
};
private BoolWorldObjectMessage CreateMessage(int id, bool state) => new BoolWorldObjectMessage
{
AboutId = LocalPlayerId,
ObjectId = id,
State = state
};
public override void OnReceiveRemote(BoolWorldObjectMessage message)
{
var geyser = WorldRegistry.GetObject<QSBGeyser>(message.ObjectId);
geyser?.SetState(message.State);
}
}
}
public override void OnReceiveRemote(BoolWorldObjectMessage message)
{
var geyser = WorldRegistry.GetObject<QSBGeyser>(message.ObjectId);
geyser?.SetState(message.State);
}
}
}

View File

@ -4,41 +4,41 @@ using UnityEngine;
namespace QSB.GeyserSync
{
public class GeyserManager : MonoBehaviour
{
public static GeyserManager Instance { get; private set; }
public class GeyserManager : MonoBehaviour
{
public static GeyserManager Instance { get; private set; }
private void Awake()
{
Instance = this;
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
QSBPatchManager.OnPatchType += OnPatchType;
}
private void Awake()
{
Instance = this;
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
QSBPatchManager.OnPatchType += OnPatchType;
}
private void OnDestroy()
{
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
QSBPatchManager.OnPatchType -= OnPatchType;
}
private void OnDestroy()
{
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
QSBPatchManager.OnPatchType -= OnPatchType;
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
{
var geyserControllers = Resources.FindObjectsOfTypeAll<GeyserController>();
for (var id = 0; id < geyserControllers.Length; id++)
{
var qsbGeyser = WorldRegistry.GetObject<QSBGeyser>(id) ?? new QSBGeyser();
qsbGeyser.Init(geyserControllers[id], id);
WorldRegistry.AddObject(qsbGeyser);
}
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
{
var geyserControllers = Resources.FindObjectsOfTypeAll<GeyserController>();
for (var id = 0; id < geyserControllers.Length; id++)
{
var qsbGeyser = WorldRegistry.GetObject<QSBGeyser>(id) ?? new QSBGeyser();
qsbGeyser.Init(geyserControllers[id], id);
WorldRegistry.AddObject(qsbGeyser);
}
}
public void OnPatchType(QSBPatchTypes type)
{
if (type != QSBPatchTypes.OnNonServerClientConnect)
{
return;
}
QSB.Helper.HarmonyHelper.EmptyMethod<GeyserController>("Update");
}
}
public void OnPatchType(QSBPatchTypes type)
{
if (type != QSBPatchTypes.OnNonServerClientConnect)
{
return;
}
QSB.Helper.HarmonyHelper.EmptyMethod<GeyserController>("Update");
}
}
}

View File

@ -1,40 +1,40 @@
using QSB.EventsCore;
using QSB.WorldSync;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.GeyserSync
{
public class QSBGeyser : WorldObject
{
private GeyserController _geyserController;
public class QSBGeyser : WorldObject
{
private GeyserController _geyserController;
public void Init(GeyserController geyserController, int id)
{
ObjectId = id;
_geyserController = geyserController;
public void Init(GeyserController geyserController, int id)
{
ObjectId = id;
_geyserController = geyserController;
geyserController.OnGeyserActivateEvent += () => HandleEvent(true);
geyserController.OnGeyserDeactivateEvent += () => HandleEvent(false);
}
geyserController.OnGeyserActivateEvent += () => HandleEvent(true);
geyserController.OnGeyserDeactivateEvent += () => HandleEvent(false);
}
private void HandleEvent(bool state)
{
if (NetworkServer.active)
{
GlobalMessenger<int, bool>.FireEvent(EventNames.QSBGeyserState, ObjectId, state);
}
}
private void HandleEvent(bool state)
{
if (QSBNetworkServer.active)
{
GlobalMessenger<int, bool>.FireEvent(EventNames.QSBGeyserState, ObjectId, state);
}
}
public void SetState(bool state)
{
if (state)
{
_geyserController?.ActivateGeyser();
}
else
{
_geyserController?.DeactivateGeyser();
}
}
}
}
public void SetState(bool state)
{
if (state)
{
_geyserController?.ActivateGeyser();
}
else
{
_geyserController?.DeactivateGeyser();
}
}
}
}

View File

@ -8,121 +8,130 @@ using UnityEngine;
namespace QSB.Instruments
{
public class InstrumentsManager : PlayerSyncObject
{
private Transform rootObj;
private AnimationType _savedType;
private GameObject ChertDrum;
public class InstrumentsManager : PlayerSyncObject
{
private Transform rootObj;
private AnimationType _savedType;
private GameObject ChertDrum;
public void InitLocal(Transform root)
{
rootObj = root;
gameObject.AddComponent<CameraManager>();
public void InitLocal(Transform root)
{
rootObj = root;
gameObject.AddComponent<CameraManager>();
QSBInputManager.ChertTaunt += () => StartInstrument(AnimationType.Chert);
QSBInputManager.EskerTaunt += () => StartInstrument(AnimationType.Esker);
QSBInputManager.FeldsparTaunt += () => StartInstrument(AnimationType.Feldspar);
QSBInputManager.GabbroTaunt += () => StartInstrument(AnimationType.Gabbro);
QSBInputManager.RiebeckTaunt += () => StartInstrument(AnimationType.Riebeck);
QSBInputManager.ExitTaunt += () => ReturnToPlayer();
QSBInputManager.ChertTaunt += () => StartInstrument(AnimationType.Chert);
QSBInputManager.EskerTaunt += () => StartInstrument(AnimationType.Esker);
QSBInputManager.FeldsparTaunt += () => StartInstrument(AnimationType.Feldspar);
QSBInputManager.GabbroTaunt += () => StartInstrument(AnimationType.Gabbro);
QSBInputManager.RiebeckTaunt += () => StartInstrument(AnimationType.Riebeck);
QSBInputManager.ExitTaunt += () => ReturnToPlayer();
QSB.Helper.Events.Unity.RunWhen(() => Locator.GetPlayerBody() != null, SetupInstruments);
QSB.Helper.Events.Unity.RunWhen(() => Locator.GetPlayerBody() != null, SetupInstruments);
QSBPlayerManager.PlayerSyncObjects.Add(this);
}
QSBPlayerManager.PlayerSyncObjects.Add(this);
}
public void InitRemote(Transform root)
{
rootObj = root;
QSB.Helper.Events.Unity.RunWhen(() => Locator.GetPlayerBody() != null, SetupInstruments);
public void InitRemote(Transform root)
{
rootObj = root;
QSB.Helper.Events.Unity.RunWhen(() => Locator.GetPlayerBody() != null, SetupInstruments);
QSBPlayerManager.PlayerSyncObjects.Add(this);
}
QSBPlayerManager.PlayerSyncObjects.Add(this);
}
private void OnDestroy()
{
if (!isLocalPlayer)
{
return;
}
DebugLog.DebugWrite($"OnDestroy {PlayerId}");
QSBInputManager.ChertTaunt -= () => StartInstrument(AnimationType.Chert);
QSBInputManager.EskerTaunt -= () => StartInstrument(AnimationType.Esker);
QSBInputManager.FeldsparTaunt -= () => StartInstrument(AnimationType.Feldspar);
QSBInputManager.GabbroTaunt -= () => StartInstrument(AnimationType.Gabbro);
QSBInputManager.RiebeckTaunt -= () => StartInstrument(AnimationType.Riebeck);
QSBInputManager.ExitTaunt -= () => ReturnToPlayer();
}
private void OnDestroy()
{
if (!IsLocalPlayer)
{
return;
}
DebugLog.DebugWrite($"OnDestroy {PlayerId}");
QSBInputManager.ChertTaunt -= () => StartInstrument(AnimationType.Chert);
QSBInputManager.EskerTaunt -= () => StartInstrument(AnimationType.Esker);
QSBInputManager.FeldsparTaunt -= () => StartInstrument(AnimationType.Feldspar);
QSBInputManager.GabbroTaunt -= () => StartInstrument(AnimationType.Gabbro);
QSBInputManager.RiebeckTaunt -= () => StartInstrument(AnimationType.Riebeck);
QSBInputManager.ExitTaunt -= () => ReturnToPlayer();
}
private void SetupInstruments()
{
var bundle = QSB.InstrumentAssetBundle;
ChertDrum = MakeChertDrum(bundle);
}
private void SetupInstruments()
{
var bundle = QSB.InstrumentAssetBundle;
ChertDrum = MakeChertDrum(bundle);
}
// EyeCompatibility : Need to find right object.
private GameObject MakeChertDrum(AssetBundle bundle)
{
var drum = new GameObject();
var mf = drum.AddComponent<MeshFilter>();
mf.sharedMesh = bundle.LoadAsset("assets/Chert/hourglasstwinsmeshescharacters2.asset") as Mesh;
var mr = drum.AddComponent<MeshRenderer>();
mr.sharedMaterial = GameObject.Find("NewDrum:polySurface2").GetComponent<MeshRenderer>().material;
drum.transform.parent = rootObj;
drum.transform.rotation = rootObj.rotation;
drum.transform.localPosition = Vector3.zero;
drum.transform.localScale = new Vector3(16.0f, 16.5f, 16.0f);
drum.SetActive(false);
private GameObject MakeChertDrum(AssetBundle bundle)
{
var drum = new GameObject();
var mf = drum.AddComponent<MeshFilter>();
mf.sharedMesh = bundle.LoadAsset("assets/Chert/hourglasstwinsmeshescharacters2.asset") as Mesh;
var mr = drum.AddComponent<MeshRenderer>();
if (QSBSceneManager.CurrentScene == OWScene.SolarSystem)
{
mr.sharedMaterial = GameObject.Find("NewDrum:polySurface2").GetComponent<MeshRenderer>().material;
}
else if (QSBSceneManager.CurrentScene == OWScene.EyeOfTheUniverse)
{
//mr.sharedMaterial = GameObject.Find("Props_HEA_Drums").GetComponent<MeshRenderer>().material;
// TODO : fix for instrument release
mr.sharedMaterial = null;
}
drum.transform.parent = rootObj;
drum.transform.rotation = rootObj.rotation;
drum.transform.localPosition = Vector3.zero;
drum.transform.localScale = new Vector3(16.0f, 16.5f, 16.0f);
drum.SetActive(false);
return drum;
}
return drum;
}
public void StartInstrument(AnimationType type)
{
if (!isLocalPlayer)
{
DebugLog.DebugWrite("Error - Tried to start instrument on non-local player!", MessageType.Error);
return;
}
if (Player.PlayingInstrument || !Locator.GetPlayerController().IsGrounded())
{
return;
}
_savedType = Player.AnimationSync.CurrentType;
CameraManager.Instance.SwitchTo3rdPerson();
SwitchToType(type);
}
public void StartInstrument(AnimationType type)
{
if (!IsLocalPlayer)
{
DebugLog.DebugWrite("Error - Tried to start instrument on non-local player!", MessageType.Error);
return;
}
if (Player.PlayingInstrument || !Locator.GetPlayerController().IsGrounded())
{
return;
}
_savedType = Player.AnimationSync.CurrentType;
CameraManager.Instance.SwitchTo3rdPerson();
SwitchToType(type);
}
public void ReturnToPlayer()
{
if (!Player.PlayingInstrument)
{
return;
}
CameraManager.Instance.SwitchTo1stPerson();
SwitchToType(_savedType);
}
public void ReturnToPlayer()
{
if (!Player.PlayingInstrument)
{
return;
}
CameraManager.Instance.SwitchTo1stPerson();
SwitchToType(_savedType);
}
public void SwitchToType(AnimationType type)
{
DebugLog.DebugWrite($"switch to type {type} player {PlayerId}");
GlobalMessenger<uint, AnimationType>.FireEvent(EventNames.QSBChangeAnimType, QSBPlayerManager.LocalPlayerId, type);
QSBPlayerManager.LocalPlayer.AnimationSync.SetAnimationType(type);
CheckInstrumentProps(type);
}
public void SwitchToType(AnimationType type)
{
DebugLog.DebugWrite($"switch to type {type} player {PlayerId}");
GlobalMessenger<uint, AnimationType>.FireEvent(EventNames.QSBChangeAnimType, QSBPlayerManager.LocalPlayerId, type);
QSBPlayerManager.LocalPlayer.AnimationSync.SetAnimationType(type);
CheckInstrumentProps(type);
}
public void CheckInstrumentProps(AnimationType type)
{
switch (type)
{
case AnimationType.Chert:
ChertDrum.SetActive(true);
break;
case AnimationType.PlayerSuited:
case AnimationType.PlayerUnsuited:
ChertDrum.SetActive(false);
break;
}
}
}
}
public void CheckInstrumentProps(AnimationType type)
{
switch (type)
{
case AnimationType.Chert:
ChertDrum.SetActive(true);
break;
case AnimationType.PlayerSuited:
case AnimationType.PlayerUnsuited:
ChertDrum.SetActive(false);
break;
}
}
}
}

View File

@ -2,78 +2,79 @@
namespace QSB.Instruments.QSBCamera
{
class CameraController : MonoBehaviour
{
private float _degreesX;
private float _degreesY;
private Quaternion _rotationX;
private Quaternion _rotationY;
internal class CameraController : MonoBehaviour
{
private float _degreesX;
private float _degreesY;
private Quaternion _rotationX;
private Quaternion _rotationY;
// How far along the ray to move the camera. Avoids clipping into the walls.
private const float PercentToMove = 0.80f;
// Maximum distance for camera clipping
private const float RayLength = 5f;
// How far along the ray to move the camera. Avoids clipping into the walls.
private const float PercentToMove = 0.80f;
public GameObject CameraObject;
// Maximum distance for camera clipping
private const float RayLength = 5f;
void FixedUpdate()
{
if (CameraManager.Instance.Mode != CameraMode.ThirdPerson)
{
return;
}
UpdatePosition();
UpdateInput();
UpdateRotation();
}
public GameObject CameraObject;
private void UpdatePosition()
{
var origin = transform.position;
var localDirection = CameraObject.transform.localPosition.normalized;
Vector3 localTargetPoint;
if (Physics.Raycast(origin, transform.TransformDirection(localDirection), out var outRay, RayLength, LayerMask.GetMask("Default")))
{
// Raycast hit collider, get target from hitpoint.
localTargetPoint = transform.InverseTransformPoint(outRay.point) * PercentToMove;
}
else
{
// Raycast didn't hit collider, get target from camera direction
localTargetPoint = localDirection * RayLength * PercentToMove;
}
var targetDistance = Vector3.Distance(origin, transform.TransformPoint(localTargetPoint));
var currentDistance = Vector3.Distance(origin, CameraObject.transform.position);
Vector3 movement;
if (targetDistance < currentDistance)
{
// Snap to target to avoid clipping
movement = localTargetPoint;
}
else
{
// Move camera out slowly
movement = Vector3.MoveTowards(CameraObject.transform.localPosition, localTargetPoint, Time.fixedDeltaTime * 2f);
}
CameraObject.transform.localPosition = movement;
}
private void FixedUpdate()
{
if (CameraManager.Instance.Mode != CameraMode.ThirdPerson)
{
return;
}
UpdatePosition();
UpdateInput();
UpdateRotation();
}
private void UpdateInput()
{
var input = OWInput.GetValue(InputLibrary.look, false, InputMode.All);
_degreesX += input.x * 180f * Time.fixedDeltaTime;
_degreesY += input.y * 180f * Time.fixedDeltaTime;
}
private void UpdatePosition()
{
var origin = transform.position;
var localDirection = CameraObject.transform.localPosition.normalized;
Vector3 localTargetPoint;
if (Physics.Raycast(origin, transform.TransformDirection(localDirection), out var outRay, RayLength, LayerMask.GetMask("Default")))
{
// Raycast hit collider, get target from hitpoint.
localTargetPoint = transform.InverseTransformPoint(outRay.point) * PercentToMove;
}
else
{
// Raycast didn't hit collider, get target from camera direction
localTargetPoint = localDirection * RayLength * PercentToMove;
}
var targetDistance = Vector3.Distance(origin, transform.TransformPoint(localTargetPoint));
var currentDistance = Vector3.Distance(origin, CameraObject.transform.position);
Vector3 movement;
if (targetDistance < currentDistance)
{
// Snap to target to avoid clipping
movement = localTargetPoint;
}
else
{
// Move camera out slowly
movement = Vector3.MoveTowards(CameraObject.transform.localPosition, localTargetPoint, Time.fixedDeltaTime * 2f);
}
CameraObject.transform.localPosition = movement;
}
private void UpdateRotation()
{
_degreesX %= 360f;
_degreesY %= 360f;
_degreesY = Mathf.Clamp(_degreesY, -80f, 80f);
_rotationX = Quaternion.AngleAxis(_degreesX, Vector3.up);
_rotationY = Quaternion.AngleAxis(_degreesY, Vector3.left);
var localRotation = _rotationX * _rotationY * Quaternion.identity;
transform.localRotation = localRotation;
}
}
}
private void UpdateInput()
{
var input = OWInput.GetValue(InputLibrary.look, false, InputMode.All);
_degreesX += input.x * 180f * Time.fixedDeltaTime;
_degreesY += input.y * 180f * Time.fixedDeltaTime;
}
private void UpdateRotation()
{
_degreesX %= 360f;
_degreesY %= 360f;
_degreesY = Mathf.Clamp(_degreesY, -80f, 80f);
_rotationX = Quaternion.AngleAxis(_degreesX, Vector3.up);
_rotationY = Quaternion.AngleAxis(_degreesY, Vector3.left);
var localRotation = _rotationX * _rotationY * Quaternion.identity;
transform.localRotation = localRotation;
}
}
}

View File

@ -5,110 +5,110 @@ using UnityEngine.PostProcessing;
namespace QSB.Instruments.QSBCamera
{
public class CameraManager : MonoBehaviour
{
public static CameraManager Instance;
private GameObject CameraBase;
private GameObject CameraObj;
private Camera Camera;
private OWCamera OWCamera;
public bool IsSetUp { get; private set; }
public CameraMode Mode { get; private set; }
public class CameraManager : MonoBehaviour
{
public static CameraManager Instance;
private GameObject CameraBase;
private GameObject CameraObj;
private Camera Camera;
private OWCamera OWCamera;
public bool IsSetUp { get; private set; }
public CameraMode Mode { get; private set; }
public void Start()
{
Instance = this;
SetupCamera();
}
public void Start()
{
Instance = this;
SetupCamera();
}
private void SetupCamera()
{
CameraBase = new GameObject();
CameraBase.SetActive(false);
CameraBase.AddComponent<Transform>();
CameraBase.transform.parent = Locator.GetPlayerTransform();
CameraBase.transform.localPosition = Vector3.zero;
CameraBase.transform.localRotation = Quaternion.Euler(0, 0, 0);
private void SetupCamera()
{
CameraBase = new GameObject();
CameraBase.SetActive(false);
CameraBase.AddComponent<Transform>();
CameraBase.transform.parent = Locator.GetPlayerTransform();
CameraBase.transform.localPosition = Vector3.zero;
CameraBase.transform.localRotation = Quaternion.Euler(0, 0, 0);
CameraObj = new GameObject();
CameraObj.transform.parent = CameraBase.transform;
CameraObj.transform.localPosition = new Vector3(0, 0, -5f);
CameraObj.transform.localRotation = Quaternion.Euler(0, 0, 0);
Camera = CameraObj.AddComponent<Camera>();
Camera.cullingMask = Locator.GetPlayerCamera().mainCamera.cullingMask & ~(1 << 27) | (1 << 22);
Camera.clearFlags = CameraClearFlags.Color;
Camera.backgroundColor = Color.black;
Camera.fieldOfView = 90f;
Camera.nearClipPlane = 0.1f;
Camera.farClipPlane = 40000f;
Camera.depth = 0f;
Camera.enabled = false;
OWCamera = CameraObj.AddComponent<OWCamera>();
OWCamera.renderSkybox = true;
CameraObj = new GameObject();
CameraObj.transform.parent = CameraBase.transform;
CameraObj.transform.localPosition = new Vector3(0, 0, -5f);
CameraObj.transform.localRotation = Quaternion.Euler(0, 0, 0);
Camera = CameraObj.AddComponent<Camera>();
Camera.cullingMask = Locator.GetPlayerCamera().mainCamera.cullingMask & ~(1 << 27) | (1 << 22);
Camera.clearFlags = CameraClearFlags.Color;
Camera.backgroundColor = Color.black;
Camera.fieldOfView = 90f;
Camera.nearClipPlane = 0.1f;
Camera.farClipPlane = 40000f;
Camera.depth = 0f;
Camera.enabled = false;
OWCamera = CameraObj.AddComponent<OWCamera>();
OWCamera.renderSkybox = true;
CameraBase.AddComponent<CameraController>().CameraObject = CameraObj;
CameraBase.AddComponent<CameraController>().CameraObject = CameraObj;
var screenGrab = CameraObj.AddComponent<FlashbackScreenGrabImageEffect>();
screenGrab._downsampleShader = Locator.GetPlayerCamera().gameObject.GetComponent<FlashbackScreenGrabImageEffect>()._downsampleShader;
var screenGrab = CameraObj.AddComponent<FlashbackScreenGrabImageEffect>();
screenGrab._downsampleShader = Locator.GetPlayerCamera().gameObject.GetComponent<FlashbackScreenGrabImageEffect>()._downsampleShader;
var fogImage = CameraObj.AddComponent<PlanetaryFogImageEffect>();
fogImage.fogShader = Locator.GetPlayerCamera().gameObject.GetComponent<PlanetaryFogImageEffect>().fogShader;
var fogImage = CameraObj.AddComponent<PlanetaryFogImageEffect>();
fogImage.fogShader = Locator.GetPlayerCamera().gameObject.GetComponent<PlanetaryFogImageEffect>().fogShader;
CameraBase.SetActive(true);
CameraBase.SetActive(true);
IsSetUp = true;
}
IsSetUp = true;
}
public void SwitchTo3rdPerson()
{
if (!IsSetUp)
{
DebugLog.ToConsole("Warning - Camera not set up!", MessageType.Warning);
OWInput.ChangeInputMode(InputMode.None);
Mode = CameraMode.ThirdPerson;
return;
}
if (Mode == CameraMode.ThirdPerson)
{
DebugLog.ToConsole("Warning - Already in 3rd person!", MessageType.Warning);
return;
}
if (OWInput.GetInputMode() != InputMode.Character)
{
DebugLog.ToConsole("Warning - Cannot change to 3rd person while not in Character inputmode!", MessageType.Warning);
return;
}
OWInput.ChangeInputMode(InputMode.None);
GlobalMessenger<OWCamera>.FireEvent("SwitchActiveCamera", OWCamera);
Locator.GetPlayerCamera().mainCamera.enabled = false;
if (CameraObj.GetComponent<PostProcessingBehaviour>() == null)
{
var postProcessing = CameraObj.AddComponent<PostProcessingBehaviour>();
postProcessing.profile = Locator.GetPlayerCamera().gameObject.GetComponent<PostProcessingBehaviour>().profile;
}
Camera.enabled = true;
Mode = CameraMode.ThirdPerson;
}
public void SwitchTo3rdPerson()
{
if (!IsSetUp)
{
DebugLog.ToConsole("Warning - Camera not set up!", MessageType.Warning);
OWInput.ChangeInputMode(InputMode.None);
Mode = CameraMode.ThirdPerson;
return;
}
if (Mode == CameraMode.ThirdPerson)
{
DebugLog.ToConsole("Warning - Already in 3rd person!", MessageType.Warning);
return;
}
if (OWInput.GetInputMode() != InputMode.Character)
{
DebugLog.ToConsole("Warning - Cannot change to 3rd person while not in Character inputmode!", MessageType.Warning);
return;
}
OWInput.ChangeInputMode(InputMode.None);
GlobalMessenger<OWCamera>.FireEvent("SwitchActiveCamera", OWCamera);
Locator.GetPlayerCamera().mainCamera.enabled = false;
if (CameraObj.GetComponent<PostProcessingBehaviour>() == null)
{
var postProcessing = CameraObj.AddComponent<PostProcessingBehaviour>();
postProcessing.profile = Locator.GetPlayerCamera().gameObject.GetComponent<PostProcessingBehaviour>().profile;
}
Camera.enabled = true;
Mode = CameraMode.ThirdPerson;
}
public void SwitchTo1stPerson()
{
if (!IsSetUp)
{
DebugLog.ToConsole("Warning - Camera not set up!", MessageType.Warning);
OWInput.ChangeInputMode(InputMode.Character);
Mode = CameraMode.FirstPerson;
return;
}
if (Mode == CameraMode.FirstPerson)
{
DebugLog.ToConsole("Warning - Already in 1st person!", MessageType.Warning);
return;
}
OWInput.ChangeInputMode(InputMode.Character);
GlobalMessenger<OWCamera>.FireEvent("SwitchActiveCamera", Locator.GetPlayerCamera());
Locator.GetActiveCamera().mainCamera.enabled = true;
Camera.enabled = false;
Mode = CameraMode.FirstPerson;
}
}
}
public void SwitchTo1stPerson()
{
if (!IsSetUp)
{
DebugLog.ToConsole("Warning - Camera not set up!", MessageType.Warning);
OWInput.ChangeInputMode(InputMode.Character);
Mode = CameraMode.FirstPerson;
return;
}
if (Mode == CameraMode.FirstPerson)
{
DebugLog.ToConsole("Warning - Already in 1st person!", MessageType.Warning);
return;
}
OWInput.ChangeInputMode(InputMode.Character);
GlobalMessenger<OWCamera>.FireEvent("SwitchActiveCamera", Locator.GetPlayerCamera());
Locator.GetActiveCamera().mainCamera.enabled = true;
Camera.enabled = false;
Mode = CameraMode.FirstPerson;
}
}
}

View File

@ -1,8 +1,8 @@
namespace QSB.Instruments.QSBCamera
{
public enum CameraMode
{
FirstPerson,
ThirdPerson
}
}
public enum CameraMode
{
FirstPerson,
ThirdPerson
}
}

View File

@ -1,22 +1,22 @@
using QSB.Messaging;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.MessagesCore
{
public class EnumMessage<T> : PlayerMessage
{
public T Value;
public class EnumMessage<T> : PlayerMessage
{
public T Value;
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
Value = (T)(object)reader.ReadInt32();
}
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
Value = (T)(object)reader.ReadInt32();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write((int)(object)Value);
}
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write((int)(object)Value);
}
}
}

View File

@ -1,22 +1,22 @@
using QSB.Messaging;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.MessagesCore
{
public class FloatMessage : PlayerMessage
{
public float Value;
public class FloatMessage : PlayerMessage
{
public float Value;
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
Value = reader.ReadSingle();
}
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
Value = reader.ReadSingle();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(Value);
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(Value);
}
}
}

View File

@ -1,74 +1,75 @@
using OWML.Common;
using QSB.EventsCore;
using QSB.Utility;
using QuantumUNET;
using System;
using System.Linq;
using UnityEngine.Networking;
namespace QSB.Messaging
{
// Extend this to create new message handlers.
public class MessageHandler<T> where T : MessageBase, new()
{
public event Action<T> OnClientReceiveMessage;
public event Action<T> OnServerReceiveMessage;
// Extend this to create new message handlers.
public class MessageHandler<T> where T : QSBMessageBase, new()
{
public event Action<T> OnClientReceiveMessage;
private readonly EventType _eventType;
public event Action<T> OnServerReceiveMessage;
public MessageHandler(EventType eventType)
{
_eventType = eventType + MsgType.Highest + 1;
if (QSBNetworkManager.Instance.IsReady)
{
Init();
}
else
{
QSBNetworkManager.Instance.OnNetworkManagerReady += Init;
}
}
private readonly EventType _eventType;
private void Init()
{
var eventName = Enum.GetName(typeof(EventType), _eventType - 1 - MsgType.Highest).ToUpper();
if (NetworkServer.handlers.Keys.Contains((short)_eventType))
{
DebugLog.ToConsole($"Warning - NetworkServer already contains a handler for EventType {_eventType}", MessageType.Warning);
NetworkServer.handlers.Remove((short)_eventType);
}
NetworkServer.RegisterHandler((short)_eventType, OnServerReceiveMessageHandler);
NetworkManager.singleton.client.RegisterHandler((short)_eventType, OnClientReceiveMessageHandler);
}
public MessageHandler(EventType eventType)
{
_eventType = eventType + MsgType.Highest + 1;
if (QSBNetworkManager.Instance.IsReady)
{
Init();
}
else
{
QSBNetworkManager.Instance.OnNetworkManagerReady += Init;
}
}
public void SendToAll(T message)
{
if (!QSBNetworkManager.Instance.IsReady)
{
return;
}
NetworkServer.SendToAll((short)_eventType, message);
}
private void Init()
{
var eventName = Enum.GetName(typeof(EventType), _eventType - 1 - MsgType.Highest).ToUpper();
if (QSBNetworkServer.handlers.Keys.Contains((short)_eventType))
{
DebugLog.ToConsole($"Warning - NetworkServer already contains a handler for EventType {_eventType}", MessageType.Warning);
QSBNetworkServer.handlers.Remove((short)_eventType);
}
QSBNetworkServer.RegisterHandler((short)_eventType, OnServerReceiveMessageHandler);
QSBNetworkManager.singleton.client.RegisterHandler((short)_eventType, OnClientReceiveMessageHandler);
}
public void SendToServer(T message)
{
if (!QSBNetworkManager.Instance.IsReady)
{
return;
}
NetworkManager.singleton.client.Send((short)_eventType, message);
}
public void SendToAll(T message)
{
if (!QSBNetworkManager.Instance.IsReady)
{
return;
}
QSBNetworkServer.SendToAll((short)_eventType, message);
}
private void OnClientReceiveMessageHandler(NetworkMessage netMsg)
{
var message = netMsg.ReadMessage<T>();
OnClientReceiveMessage?.Invoke(message);
}
public void SendToServer(T message)
{
if (!QSBNetworkManager.Instance.IsReady)
{
return;
}
QSBNetworkManager.singleton.client.Send((short)_eventType, message);
}
private void OnServerReceiveMessageHandler(NetworkMessage netMsg)
{
var message = netMsg.ReadMessage<T>();
OnServerReceiveMessage?.Invoke(message);
}
private void OnClientReceiveMessageHandler(QSBNetworkMessage netMsg)
{
var message = netMsg.ReadMessage<T>();
OnClientReceiveMessage?.Invoke(message);
}
}
}
private void OnServerReceiveMessageHandler(QSBNetworkMessage netMsg)
{
var message = netMsg.ReadMessage<T>();
OnServerReceiveMessage?.Invoke(message);
}
}
}

View File

@ -1,22 +1,22 @@
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.Messaging
{
public class PlayerMessage : MessageBase
{
public uint FromId { get; set; }
public uint AboutId { get; set; }
public class PlayerMessage : QSBMessageBase
{
public uint FromId { get; set; }
public uint AboutId { get; set; }
public override void Deserialize(NetworkReader reader)
{
FromId = reader.ReadUInt32();
AboutId = reader.ReadUInt32();
}
public override void Deserialize(QSBNetworkReader reader)
{
FromId = reader.ReadUInt32();
AboutId = reader.ReadUInt32();
}
public override void Serialize(NetworkWriter writer)
{
writer.Write(FromId);
writer.Write(AboutId);
}
}
}
public override void Serialize(QSBNetworkWriter writer)
{
writer.Write(FromId);
writer.Write(AboutId);
}
}
}

View File

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

View File

@ -1,30 +1,32 @@
using QSB.EventsCore;
using QSB.Utility;
using QSB.WorldSync;
using QSB.WorldSync.Events;
namespace QSB.OrbSync.Events
{
public class OrbSlotEvent : QSBEvent<BoolWorldObjectMessage>
{
public override EventType Type => EventType.OrbSlot;
public class OrbSlotEvent : QSBEvent<OrbSlotMessage>
{
public override EventType Type => EventType.OrbSlot;
public override void SetupListener() => GlobalMessenger<int, bool>.AddListener(EventNames.QSBOrbSlot, Handler);
public override void SetupListener() => GlobalMessenger<int, int, bool>.AddListener(EventNames.QSBOrbSlot, Handler);
public override void CloseListener() => GlobalMessenger<int, bool>.RemoveListener(EventNames.QSBOrbSlot, Handler);
public override void CloseListener() => GlobalMessenger<int, int, bool>.RemoveListener(EventNames.QSBOrbSlot, Handler);
private void Handler(int id, bool state) => SendEvent(CreateMessage(id, state));
private void Handler(int slotId, int orbId, bool slotState) => SendEvent(CreateMessage(slotId, orbId, slotState));
private BoolWorldObjectMessage CreateMessage(int id, bool state) => new BoolWorldObjectMessage
{
AboutId = LocalPlayerId,
ObjectId = id,
State = state
};
private OrbSlotMessage CreateMessage(int slotId, int orbId, bool slotState) => new OrbSlotMessage
{
AboutId = LocalPlayerId,
SlotId = slotId,
OrbId = orbId,
SlotState = slotState
};
public override void OnReceiveRemote(BoolWorldObjectMessage message)
{
var orbSlot = WorldRegistry.GetObject<QSBOrbSlot>(message.ObjectId);
orbSlot?.SetState(message.State);
}
}
}
public override void OnReceiveRemote(OrbSlotMessage message)
{
var orbSlot = WorldRegistry.GetObject<QSBOrbSlot>(message.SlotId);
orbSlot?.SetState(message.SlotState, message.OrbId);
}
}
}

View File

@ -0,0 +1,32 @@
using QSB.Messaging;
using QuantumUNET;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace QSB.OrbSync.Events
{
public class OrbSlotMessage : PlayerMessage
{
public int SlotId { get; set; }
public int OrbId { get; set; }
public bool SlotState { get; set; }
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
SlotId = reader.ReadInt32();
OrbId = reader.ReadInt32();
SlotState = reader.ReadBoolean();
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(SlotId);
writer.Write(OrbId);
writer.Write(SlotState);
}
}
}

View File

@ -1,73 +1,80 @@
using OWML.Common;
using QSB.EventsCore;
using QSB.TransformSync;
using QSB.Utility;
using QSB.WorldSync;
using QSB.WorldSync.Events;
using QuantumUNET;
using System.Linq;
using UnityEngine.Networking;
namespace QSB.OrbSync.Events
{
public class OrbUserEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.OrbUser;
public class OrbUserEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.OrbUser;
public override void SetupListener() => GlobalMessenger<int>.AddListener(EventNames.QSBOrbUser, Handler);
public override void SetupListener() => GlobalMessenger<int>.AddListener(EventNames.QSBOrbUser, Handler);
public override void CloseListener() => GlobalMessenger<int>.RemoveListener(EventNames.QSBOrbUser, Handler);
public override void CloseListener() => GlobalMessenger<int>.RemoveListener(EventNames.QSBOrbUser, Handler);
private void Handler(int id) => SendEvent(CreateMessage(id));
private void Handler(int id) => SendEvent(CreateMessage(id));
private WorldObjectMessage CreateMessage(int id) => new WorldObjectMessage
{
AboutId = LocalPlayerId,
ObjectId = id
};
private WorldObjectMessage CreateMessage(int id) => new WorldObjectMessage
{
AboutId = LocalPlayerId,
ObjectId = id
};
public override void OnServerReceive(WorldObjectMessage message)
{
var fromPlayer = NetworkServer.connections
.First(x => x.playerControllers[0].gameObject.GetComponent<PlayerTransformSync>().netId.Value == message.FromId);
if (WorldRegistry.OrbSyncList.Count == 0)
{
DebugLog.ToConsole($"Error - OrbSyncList is empty. (ID {message.ObjectId})", MessageType.Error);
return;
}
var orb = WorldRegistry.OrbSyncList
.First(x => x.AttachedOrb == WorldRegistry.OldOrbList[message.ObjectId]);
if (orb == null)
{
DebugLog.ToConsole($"Error - No orb found for user event. (ID {message.ObjectId})", MessageType.Error);
return;
}
var orbIdentity = orb.GetComponent<NetworkIdentity>();
if (orbIdentity == null)
{
DebugLog.ToConsole($"Error - Orb identity is null. (ID {message.ObjectId})", MessageType.Error);
return;
}
if (orbIdentity.clientAuthorityOwner != null)
{
orbIdentity.RemoveClientAuthority(orbIdentity.clientAuthorityOwner);
}
orbIdentity.AssignClientAuthority(fromPlayer);
orb.enabled = true;
}
public override void OnServerReceive(WorldObjectMessage message)
{
var fromPlayer = QSBNetworkServer.connections.First(x => x.GetPlayer().PlayerId == message.FromId);
if (WorldRegistry.OrbSyncList.Count == 0)
{
DebugLog.ToConsole($"Error - OrbSyncList is empty. (ID {message.ObjectId})", MessageType.Error);
return;
}
if (fromPlayer == null)
{
DebugLog.DebugWrite("Error - FromPlayer is null!", MessageType.Error);
}
var orb = WorldRegistry.OrbSyncList
.First(x => x.AttachedOrb == WorldRegistry.OldOrbList[message.ObjectId]);
if (orb == null)
{
DebugLog.ToConsole($"Error - No orb found for user event. (ID {message.ObjectId})", MessageType.Error);
return;
}
var orbIdentity = orb.GetComponent<QSBNetworkIdentity>();
if (orbIdentity == null)
{
DebugLog.ToConsole($"Error - Orb identity is null. (ID {message.ObjectId})", MessageType.Error);
return;
}
if (orbIdentity.ClientAuthorityOwner != null && orbIdentity.ClientAuthorityOwner != fromPlayer)
{
orbIdentity.RemoveClientAuthority(orbIdentity.ClientAuthorityOwner);
}
orbIdentity.AssignClientAuthority(fromPlayer);
orb.enabled = true;
}
public override void OnReceiveRemote(WorldObjectMessage message)
{
var orb = WorldRegistry.OrbSyncList
.First(x => x.AttachedOrb == WorldRegistry.OldOrbList[message.ObjectId]);
orb.enabled = true;
}
public override void OnReceiveRemote(WorldObjectMessage message)
{
if (WorldRegistry.OrbSyncList.Count < message.ObjectId)
{
DebugLog.DebugWrite($"Error - Orb id {message.ObjectId} out of range of orb sync list {WorldRegistry.OrbSyncList.Count}.", MessageType.Error);
return;
}
var orb = WorldRegistry.OrbSyncList
.First(x => x.AttachedOrb == WorldRegistry.OldOrbList[message.ObjectId]);
orb.enabled = true;
}
public override void OnReceiveLocal(WorldObjectMessage message)
{
if (NetworkServer.active)
{
OnServerReceive(message);
}
}
}
}
public override void OnReceiveLocal(WorldObjectMessage message)
{
if (QSBNetworkServer.active)
{
OnServerReceive(message);
}
}
}
}

View File

@ -1,59 +1,60 @@
using OWML.Common;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.OrbSync
{
public class OrbManager : MonoBehaviour
{
public static OrbManager Instance { get; private set; }
public class OrbManager : MonoBehaviour
{
public static OrbManager Instance { get; private set; }
private void Awake()
{
Instance = this;
}
private void Awake()
{
Instance = this;
}
private void BuildOrbSlots()
{
DebugLog.DebugWrite("Building QSBOrbSlots...");
private void BuildOrbSlots()
{
DebugLog.DebugWrite("Building QSBOrbSlots...", MessageType.Info);
WorldRegistry.RemoveObjects<QSBOrbSlot>();
var orbSlots = Resources.FindObjectsOfTypeAll<NomaiInterfaceSlot>();
for (var id = 0; id < orbSlots.Length; id++)
{
var qsbOrbSlot = WorldRegistry.GetObject<QSBOrbSlot>(id) ?? new QSBOrbSlot();
qsbOrbSlot.Init(orbSlots[id], id);
}
var orbSlots = Resources.FindObjectsOfTypeAll<NomaiInterfaceSlot>();
for (var id = 0; id < orbSlots.Length; id++)
{
var qsbOrbSlot = WorldRegistry.GetObject<QSBOrbSlot>(id) ?? new QSBOrbSlot();
qsbOrbSlot.Init(orbSlots[id], id);
}
DebugLog.DebugWrite($"Finished orb slot build with {orbSlots.Length} slots.", MessageType.Success);
}
DebugLog.DebugWrite($"Finished orb build with {WorldRegistry.OldOrbList.Count} interface orbs and {WorldRegistry.OrbSyncList.Count} orb syncs.", MessageType.Success);
}
public void BuildOrbs()
{
DebugLog.DebugWrite("Building orb syncs...", MessageType.Info);
WorldRegistry.OldOrbList.Clear();
WorldRegistry.OldOrbList = Resources.FindObjectsOfTypeAll<NomaiInterfaceOrb>().ToList();
if (QSBNetworkServer.active)
{
DebugLog.DebugWrite("- Is server, instantiating orb prefabs.");
WorldRegistry.OrbSyncList.ForEach(x => QSBNetworkServer.Destroy(x.gameObject));
WorldRegistry.OrbSyncList.Clear();
WorldRegistry.OldOrbList.ForEach(x => QSBNetworkServer.Spawn(Instantiate(QSBNetworkManager.Instance.OrbPrefab)));
}
DebugLog.DebugWrite($"Finished orb build with {WorldRegistry.OldOrbList.Count} orbs.", MessageType.Success);
}
public void BuildOrbs()
{
DebugLog.DebugWrite("Building orb syncs...");
WorldRegistry.OldOrbList.Clear();
public void QueueBuildSlots()
{
DebugLog.DebugWrite("Queueing build of QSBOrbSlots...", MessageType.Info);
QSB.Helper.Events.Unity.RunWhen(() => QSB.HasWokenUp, BuildOrbSlots);
}
WorldRegistry.OldOrbList = Resources.FindObjectsOfTypeAll<NomaiInterfaceOrb>().ToList();
if (NetworkServer.active)
{
DebugLog.DebugWrite("IS SERVER - INSTANTIATING!");
WorldRegistry.OrbSyncList.Clear();
WorldRegistry.OldOrbList.ForEach(x => NetworkServer.Spawn(Instantiate(QSBNetworkManager.Instance.OrbPrefab)));
}
}
public void QueueBuildSlots()
{
DebugLog.DebugWrite("Queueing build of QSBOrbSlots...");
QSB.Helper.Events.Unity.RunWhen(() => QSB.HasWokenUp, BuildOrbSlots);
}
public void QueueBuildOrbs()
{
DebugLog.DebugWrite("Queueing build of NetworkOrbs...");
QSB.Helper.Events.Unity.RunWhen(() => NetworkServer.active, BuildOrbs);
}
}
public void QueueBuildOrbs()
{
DebugLog.DebugWrite("Queueing build of NetworkOrbs...", MessageType.Info);
QSB.Helper.Events.Unity.RunWhen(() => QSBNetworkServer.active, BuildOrbs);
}
}
}

View File

@ -4,60 +4,60 @@ using UnityEngine;
namespace QSB.OrbSync
{
public class OrbPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public class OrbPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
public static void StartDragCallEvent(bool __result, NomaiInterfaceOrb __instance)
{
if (__result)
{
GlobalMessenger<int>.FireEvent(EventNames.QSBOrbUser, WorldRegistry.OldOrbList.FindIndex(x => x == __instance));
}
}
public static void StartDragCallEvent(bool __result, NomaiInterfaceOrb __instance)
{
if (__result)
{
GlobalMessenger<int>.FireEvent(EventNames.QSBOrbUser, WorldRegistry.OldOrbList.FindIndex(x => x == __instance));
}
}
public static bool CheckOrbCollision(ref bool __result, NomaiInterfaceSlot __instance, NomaiInterfaceOrb orb,
bool ____ignoreDraggedOrbs, float ____radius, float ____exitRadius, ref NomaiInterfaceOrb ____occupyingOrb)
{
if (____ignoreDraggedOrbs && orb.IsBeingDragged())
{
__result = false;
return false;
}
var orbDistance = Vector3.Distance(orb.transform.position, __instance.transform.position);
var triggerRadius = orb.IsBeingDragged() ? ____exitRadius : ____radius;
if (____occupyingOrb == null && orbDistance < ____radius)
{
____occupyingOrb = orb;
if (Time.timeSinceLevelLoad > 1f)
{
WorldRegistry.HandleSlotStateChange(__instance, orb, true);
WorldRegistry.RaiseEvent(__instance, "OnSlotActivated");
}
__result = true;
return false;
}
if (____occupyingOrb == null || ____occupyingOrb != orb)
{
__result = false;
return false;
}
if (orbDistance > triggerRadius)
{
WorldRegistry.HandleSlotStateChange(__instance, orb, false);
____occupyingOrb = null;
WorldRegistry.RaiseEvent(__instance, "OnSlotDeactivated");
__result = false;
return false;
}
__result = true;
return false;
}
public static bool CheckOrbCollision(ref bool __result, NomaiInterfaceSlot __instance, NomaiInterfaceOrb orb,
bool ____ignoreDraggedOrbs, float ____radius, float ____exitRadius, ref NomaiInterfaceOrb ____occupyingOrb)
{
if (____ignoreDraggedOrbs && orb.IsBeingDragged())
{
__result = false;
return false;
}
var orbDistance = Vector3.Distance(orb.transform.position, __instance.transform.position);
var triggerRadius = orb.IsBeingDragged() ? ____exitRadius : ____radius;
if (____occupyingOrb == null && orbDistance < ____radius)
{
____occupyingOrb = orb;
if (Time.timeSinceLevelLoad > 1f)
{
WorldRegistry.HandleSlotStateChange(__instance, orb, true);
WorldRegistry.RaiseEvent(__instance, "OnSlotActivated");
}
__result = true;
return false;
}
if (____occupyingOrb == null || ____occupyingOrb != orb)
{
__result = false;
return false;
}
if (orbDistance > triggerRadius)
{
WorldRegistry.HandleSlotStateChange(__instance, orb, false);
____occupyingOrb = null;
WorldRegistry.RaiseEvent(__instance, "OnSlotDeactivated");
__result = false;
return false;
}
__result = true;
return false;
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<NomaiInterfaceOrb>("StartDragFromPosition", typeof(OrbPatches), nameof(StartDragCallEvent));
QSB.Helper.HarmonyHelper.AddPrefix<NomaiInterfaceSlot>("CheckOrbCollision", typeof(OrbPatches), nameof(CheckOrbCollision));
}
}
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<NomaiInterfaceOrb>("StartDragFromPosition", typeof(OrbPatches), nameof(StartDragCallEvent));
QSB.Helper.HarmonyHelper.AddPrefix<NomaiInterfaceSlot>("CheckOrbCollision", typeof(OrbPatches), nameof(CheckOrbCollision));
}
}
}

View File

@ -1,38 +1,43 @@
using QSB.EventsCore;
using OWML.ModHelper.Events;
using QSB.EventsCore;
using QSB.WorldSync;
namespace QSB.OrbSync
{
public class QSBOrbSlot : WorldObject
{
public NomaiInterfaceSlot InterfaceSlot { get; private set; }
public class QSBOrbSlot : WorldObject
{
public NomaiInterfaceSlot InterfaceSlot { get; private set; }
public bool Activated { get; private set; }
private bool _initialized;
private bool _initialized;
public void Init(NomaiInterfaceSlot slot, int id)
{
ObjectId = id;
InterfaceSlot = slot;
_initialized = true;
WorldRegistry.AddObject(this);
}
public void Init(NomaiInterfaceSlot slot, int id)
{
ObjectId = id;
InterfaceSlot = slot;
_initialized = true;
WorldRegistry.AddObject(this);
}
public void HandleEvent(bool state)
{
if (QSB.HasWokenUp)
{
GlobalMessenger<int, bool>.FireEvent(EventNames.QSBOrbSlot, ObjectId, state);
}
}
public void HandleEvent(bool state, int orbId)
{
if (QSB.HasWokenUp)
{
GlobalMessenger<int, int, bool>.FireEvent(EventNames.QSBOrbSlot, ObjectId, orbId, state);
}
}
public void SetState(bool state)
{
if (!_initialized)
{
return;
}
var ev = state ? "OnSlotActivated" : "OnSlotDeactivated";
WorldRegistry.RaiseEvent(InterfaceSlot, ev);
}
}
}
public void SetState(bool state, int orbId)
{
if (!_initialized)
{
return;
}
var occOrb = state ? WorldRegistry.OldOrbList[orbId] : null;
InterfaceSlot.SetValue("_occupyingOrb", occOrb);
var ev = state ? "OnSlotActivated" : "OnSlotDeactivated";
WorldRegistry.RaiseEvent(InterfaceSlot, ev);
Activated = state;
}
}
}

View File

@ -1,9 +1,9 @@
namespace QSB
{
public abstract class QSBPatch
{
public abstract QSBPatchTypes Type { get; }
public abstract class QSBPatch
{
public abstract QSBPatchTypes Type { get; }
public abstract void DoPatches();
}
}
public abstract void DoPatches();
}
}

View File

@ -12,38 +12,38 @@ using System.Linq;
namespace QSB.Patches
{
public delegate void PatchEvent(QSBPatchTypes type);
public delegate void PatchEvent(QSBPatchTypes type);
public static class QSBPatchManager
{
public static List<QSBPatch> _patchList = new List<QSBPatch>();
public static class QSBPatchManager
{
public static List<QSBPatch> _patchList = new List<QSBPatch>();
public static event PatchEvent OnPatchType;
public static event PatchEvent OnPatchType;
public static void Init()
{
_patchList = new List<QSBPatch>
{
new ConversationPatches(),
new DeathPatches(),
new ElevatorPatches(),
new OrbPatches(),
new WakeUpPatches(),
new ProbePatches()
};
public static void Init()
{
_patchList = new List<QSBPatch>
{
new ConversationPatches(),
new DeathPatches(),
new ElevatorPatches(),
new OrbPatches(),
new WakeUpPatches(),
new ProbePatches()
};
DebugLog.DebugWrite("Patch Manager ready.", MessageType.Success);
}
DebugLog.DebugWrite("Patch Manager ready.", MessageType.Success);
}
public static void DoPatchType(QSBPatchTypes type)
{
OnPatchType?.Invoke(type);
DebugLog.DebugWrite($"Patch block {Enum.GetName(typeof(QSBPatchTypes), type)}", MessageType.Info);
foreach (var patch in _patchList.Where(x => x.Type == type))
{
DebugLog.DebugWrite($" - Patching in {patch.GetType().Name}", MessageType.Info);
patch.DoPatches();
}
}
}
}
public static void DoPatchType(QSBPatchTypes type)
{
OnPatchType?.Invoke(type);
DebugLog.DebugWrite($"Patch block {Enum.GetName(typeof(QSBPatchTypes), type)}", MessageType.Info);
foreach (var patch in _patchList.Where(x => x.Type == type))
{
DebugLog.DebugWrite($" - Patching in {patch.GetType().Name}", MessageType.Info);
patch.DoPatches();
}
}
}
}

View File

@ -1,9 +1,9 @@
namespace QSB
{
public enum QSBPatchTypes
{
OnModStart,
OnClientConnect,
OnNonServerClientConnect
}
}
public enum QSBPatchTypes
{
OnModStart,
OnClientConnect,
OnNonServerClientConnect
}
}

View File

@ -4,36 +4,36 @@ using QSB.Utility;
namespace QSB.Player.Events
{
public class PlayerJoinEvent : QSBEvent<PlayerJoinMessage>
{
public override EventType Type => EventType.PlayerJoin;
public class PlayerJoinEvent : QSBEvent<PlayerJoinMessage>
{
public override EventType Type => EventType.PlayerJoin;
public override void SetupListener() => GlobalMessenger<string>.AddListener(EventNames.QSBPlayerJoin, Handler);
public override void SetupListener() => GlobalMessenger<string>.AddListener(EventNames.QSBPlayerJoin, Handler);
public override void CloseListener() => GlobalMessenger<string>.RemoveListener(EventNames.QSBPlayerJoin, Handler);
public override void CloseListener() => GlobalMessenger<string>.RemoveListener(EventNames.QSBPlayerJoin, Handler);
private void Handler(string name) => SendEvent(CreateMessage(name));
private void Handler(string name) => SendEvent(CreateMessage(name));
private PlayerJoinMessage CreateMessage(string name) => new PlayerJoinMessage
{
AboutId = LocalPlayerId,
PlayerName = name
};
private PlayerJoinMessage CreateMessage(string name) => new PlayerJoinMessage
{
AboutId = LocalPlayerId,
PlayerName = name
};
public override void OnReceiveRemote(PlayerJoinMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.Name = message.PlayerName;
DebugLog.ToHud($"{player.Name} joined!");
DebugLog.DebugWrite($"{player.Name} joined as id {player.PlayerId}", MessageType.Info);
}
public override void OnReceiveRemote(PlayerJoinMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.Name = message.PlayerName;
DebugLog.ToHud($"{player.Name} joined!");
DebugLog.DebugWrite($"{player.Name} joined as id {player.PlayerId}", MessageType.Info);
}
public override void OnReceiveLocal(PlayerJoinMessage message)
{
var player = QSBPlayerManager.GetPlayer(QSBPlayerManager.LocalPlayerId);
player.Name = message.PlayerName;
var text = $"Connected to server as {player.Name}.";
DebugLog.ToAll(text, MessageType.Info);
}
}
}
public override void OnReceiveLocal(PlayerJoinMessage message)
{
var player = QSBPlayerManager.GetPlayer(QSBPlayerManager.LocalPlayerId);
player.Name = message.PlayerName;
var text = $"Connected to server as {player.Name}.";
DebugLog.ToAll(text, MessageType.Info);
}
}
}

View File

@ -1,22 +1,22 @@
using QSB.Messaging;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.Player.Events
{
public class PlayerJoinMessage : PlayerMessage
{
public string PlayerName { get; set; }
public class PlayerJoinMessage : PlayerMessage
{
public string PlayerName { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
PlayerName = reader.ReadString();
}
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
PlayerName = reader.ReadString();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(PlayerName);
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(PlayerName);
}
}
}

View File

@ -5,29 +5,29 @@ using System.Linq;
namespace QSB.Player.Events
{
public class PlayerLeaveEvent : QSBEvent<PlayerLeaveMessage>
{
public override EventType Type => EventType.PlayerLeave;
public class PlayerLeaveEvent : QSBEvent<PlayerLeaveMessage>
{
public override EventType Type => EventType.PlayerLeave;
public override void SetupListener() => GlobalMessenger<uint, uint[]>.AddListener(EventNames.QSBPlayerLeave, Handler);
public override void SetupListener() => GlobalMessenger<uint, uint[]>.AddListener(EventNames.QSBPlayerLeave, Handler);
public override void CloseListener() => GlobalMessenger<uint, uint[]>.RemoveListener(EventNames.QSBPlayerLeave, Handler);
public override void CloseListener() => GlobalMessenger<uint, uint[]>.RemoveListener(EventNames.QSBPlayerLeave, Handler);
private void Handler(uint playerId, uint[] netIds) => SendEvent(CreateMessage(playerId, netIds));
private void Handler(uint playerId, uint[] netIds) => SendEvent(CreateMessage(playerId, netIds));
private PlayerLeaveMessage CreateMessage(uint playerId, uint[] netIds) => new PlayerLeaveMessage
{
AboutId = playerId,
NetIds = netIds
};
private PlayerLeaveMessage CreateMessage(uint playerId, uint[] netIds) => new PlayerLeaveMessage
{
AboutId = playerId,
NetIds = netIds
};
public override void OnReceiveRemote(PlayerLeaveMessage message)
{
var playerName = QSBPlayerManager.GetPlayer(message.AboutId).Name;
DebugLog.ToAll($"{playerName} disconnected.", MessageType.Info);
QSBPlayerManager.GetPlayer(message.AboutId).HudMarker?.Remove();
QSBPlayerManager.RemovePlayer(message.AboutId);
message.NetIds.ToList().ForEach(netId => QSBNetworkManager.Instance.CleanupNetworkBehaviour(netId));
}
}
}
public override void OnReceiveRemote(PlayerLeaveMessage message)
{
var playerName = QSBPlayerManager.GetPlayer(message.AboutId).Name;
DebugLog.ToAll($"{playerName} disconnected.", MessageType.Info);
QSBPlayerManager.GetPlayer(message.AboutId).HudMarker?.Remove();
QSBPlayerManager.RemovePlayer(message.AboutId);
message.NetIds.ToList().ForEach(netId => QSBNetworkManager.Instance.CleanupNetworkBehaviour(netId));
}
}
}

View File

@ -1,24 +1,24 @@
using QSB.Messaging;
using QuantumUNET;
using System;
using System.Linq;
using UnityEngine.Networking;
namespace QSB.Player.Events
{
public class PlayerLeaveMessage : PlayerMessage
{
public uint[] NetIds { get; set; }
public class PlayerLeaveMessage : PlayerMessage
{
public uint[] NetIds { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
NetIds = reader.ReadString().Split(',').Select(x => Convert.ToUInt32(x)).ToArray();
}
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
NetIds = reader.ReadString().Split(',').Select(x => Convert.ToUInt32(x)).ToArray();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(string.Join(",", NetIds.Select(x => x.ToString()).ToArray()));
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(string.Join(",", NetIds.Select(x => x.ToString()).ToArray()));
}
}
}

View File

@ -7,46 +7,46 @@ using System.Linq;
namespace QSB.Player.Events
{
public class PlayerReadyEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.PlayerReady;
public class PlayerReadyEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.PlayerReady;
public override void SetupListener() => GlobalMessenger<bool>.AddListener(EventNames.QSBPlayerReady, Handler);
public override void SetupListener() => GlobalMessenger<bool>.AddListener(EventNames.QSBPlayerReady, Handler);
public override void CloseListener() => GlobalMessenger<bool>.RemoveListener(EventNames.QSBPlayerReady, Handler);
public override void CloseListener() => GlobalMessenger<bool>.RemoveListener(EventNames.QSBPlayerReady, Handler);
private void Handler(bool ready) => SendEvent(CreateMessage(ready));
private void Handler(bool ready) => SendEvent(CreateMessage(ready));
private ToggleMessage CreateMessage(bool ready) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = ready
};
private ToggleMessage CreateMessage(bool ready) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = ready
};
public override void OnServerReceive(ToggleMessage message)
{
DebugLog.DebugWrite($"[S] Get ready event from {message.FromId}", MessageType.Success);
if (message.FromId == QSBPlayerManager.LocalPlayerId)
{
return;
}
QSBPlayerManager.GetPlayer(message.AboutId).IsReady = message.ToggleValue;
GlobalMessenger.FireEvent(EventNames.QSBServerSendPlayerStates);
}
public override void OnServerReceive(ToggleMessage message)
{
DebugLog.DebugWrite($"[S] Get ready event from {message.FromId}", MessageType.Success);
if (message.FromId == QSBPlayerManager.LocalPlayerId)
{
return;
}
QSBPlayerManager.GetPlayer(message.AboutId).IsReady = message.ToggleValue;
GlobalMessenger.FireEvent(EventNames.QSBServerSendPlayerStates);
}
public override void OnReceiveRemote(ToggleMessage message)
{
DebugLog.DebugWrite($"Get ready event from {message.FromId}", MessageType.Success);
if (!QSBPlayerManager.PlayerExists(message.FromId))
{
DebugLog.ToConsole("Error - Got ready event for non-existent player! Did we not send a PlayerStatesRequestEvent? Or was it not handled?", MessageType.Error);
return;
}
foreach (var item in QSBPlayerManager.GetSyncObjects<TransformSync.TransformSync>()
.Where(x => x != null && x.IsReady && x.ReferenceSector != null && x.PlayerId == LocalPlayerId))
{
GlobalMessenger<uint, QSBSector>.FireEvent(EventNames.QSBSectorChange, item.netId.Value, item.ReferenceSector);
}
}
}
}
public override void OnReceiveRemote(ToggleMessage message)
{
DebugLog.DebugWrite($"Get ready event from {message.FromId}", MessageType.Success);
if (!QSBPlayerManager.PlayerExists(message.FromId))
{
DebugLog.ToConsole("Error - Got ready event for non-existent player! Did we not send a PlayerStatesRequestEvent? Or was it not handled?", MessageType.Error);
return;
}
foreach (var item in QSBPlayerManager.GetSyncObjects<TransformSync.TransformSync>()
.Where(x => x != null && x.IsReady && x.ReferenceSector != null && x.PlayerId == LocalPlayerId))
{
GlobalMessenger<uint, QSBSector>.FireEvent(EventNames.QSBSectorChange, item.NetId.Value, item.ReferenceSector);
}
}
}
}

View File

@ -7,47 +7,46 @@ using QSB.WorldSync.Events;
namespace QSB.Player.Events
{
public class PlayerSectorEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.PlayerSectorChange;
public class PlayerSectorEvent : QSBEvent<WorldObjectMessage>
{
public override EventType Type => EventType.PlayerSectorChange;
public override void SetupListener()
{
GlobalMessenger<uint, QSBSector>.AddListener(EventNames.QSBSectorChange, Handler);
}
public override void SetupListener()
{
GlobalMessenger<uint, QSBSector>.AddListener(EventNames.QSBSectorChange, Handler);
}
public override void CloseListener()
{
GlobalMessenger<uint, QSBSector>.RemoveListener(EventNames.QSBSectorChange, Handler);
}
public override void CloseListener()
{
GlobalMessenger<uint, QSBSector>.RemoveListener(EventNames.QSBSectorChange, Handler);
}
private void Handler(uint netId, QSBSector sector) => SendEvent(CreateMessage(netId, sector));
private void Handler(uint netId, QSBSector sector) => SendEvent(CreateMessage(netId, sector));
private WorldObjectMessage CreateMessage(uint netId, QSBSector sector) => new WorldObjectMessage
{
AboutId = netId,
ObjectId = sector.ObjectId
};
private WorldObjectMessage CreateMessage(uint netId, QSBSector sector) => new WorldObjectMessage
{
AboutId = netId,
ObjectId = sector.ObjectId
};
public override void OnReceiveRemote(WorldObjectMessage message)
{
if (!QSBSceneManager.IsInUniverse)
{
return;
}
var sector = WorldRegistry.GetObject<QSBSector>(message.ObjectId);
public override void OnReceiveRemote(WorldObjectMessage message)
{
if (!QSBSceneManager.IsInUniverse)
{
return;
}
var sector = WorldRegistry.GetObject<QSBSector>(message.ObjectId);
if (sector == null)
{
DebugLog.ToConsole($"Sector with order id {message.ObjectId} not found!", MessageType.Warning);
return;
}
if (sector == null)
{
DebugLog.ToConsole($"Sector with order id {message.ObjectId} not found!", MessageType.Warning);
return;
}
var transformSync = QSBPlayerManager.GetSyncObject<TransformSync.TransformSync>(message.AboutId);
var transformSync = QSBPlayerManager.GetSyncObject<TransformSync.TransformSync>(message.AboutId);
QSB.Helper.Events.Unity.RunWhen(() => transformSync?.SyncedTransform != null,
() => transformSync?.SetReferenceSector(sector));
}
}
}
QSB.Helper.Events.Unity.RunWhen(() => transformSync?.SyncedTransform != null,
() => transformSync?.SetReferenceSector(sector));
}
}
}

View File

@ -1,34 +1,34 @@
using QSB.Messaging;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.Player.Events
{
public class PlayerStateMessage : PlayerMessage
{
public string PlayerName { get; set; }
public bool PlayerReady { get; set; }
public State PlayerState { get; set; }
public Sector.Name SectorID { get; set; }
public string SectorName { get; set; }
public class PlayerStateMessage : PlayerMessage
{
public string PlayerName { get; set; }
public bool PlayerReady { get; set; }
public State PlayerState { get; set; }
public Sector.Name SectorID { get; set; }
public string SectorName { get; set; }
public override void Deserialize(NetworkReader reader)
{
base.Deserialize(reader);
PlayerName = reader.ReadString();
PlayerReady = reader.ReadBoolean();
PlayerState = (State)reader.ReadInt32();
SectorID = (Sector.Name)reader.ReadInt32();
SectorName = reader.ReadString();
}
public override void Deserialize(QSBNetworkReader reader)
{
base.Deserialize(reader);
PlayerName = reader.ReadString();
PlayerReady = reader.ReadBoolean();
PlayerState = (State)reader.ReadInt32();
SectorID = (Sector.Name)reader.ReadInt32();
SectorName = reader.ReadString();
}
public override void Serialize(NetworkWriter writer)
{
base.Serialize(writer);
writer.Write(PlayerName);
writer.Write(PlayerReady);
writer.Write((int)PlayerState);
writer.Write((int)SectorID);
writer.Write(SectorName);
}
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(PlayerName);
writer.Write(PlayerReady);
writer.Write((int)PlayerState);
writer.Write((int)SectorID);
writer.Write(SectorName);
}
}
}

View File

@ -6,30 +6,30 @@ using System.Linq;
namespace QSB.Player.Events
{
public class PlayerStatesRequestEvent : QSBEvent<PlayerMessage>
{
public override EventType Type => EventType.PlayerStatesRequest;
public class PlayerStatesRequestEvent : QSBEvent<PlayerMessage>
{
public override EventType Type => EventType.PlayerStatesRequest;
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBPlayerStatesRequest, Handler);
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBPlayerStatesRequest, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBPlayerStatesRequest, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBPlayerStatesRequest, Handler);
private void Handler() => SendEvent(CreateMessage());
private void Handler() => SendEvent(CreateMessage());
private PlayerMessage CreateMessage() => new PlayerMessage
{
AboutId = LocalPlayerId
};
private PlayerMessage CreateMessage() => new PlayerMessage
{
AboutId = LocalPlayerId
};
public override void OnServerReceive(PlayerMessage message)
{
DebugLog.DebugWrite($"[S] Get state request from {message.FromId}");
GlobalMessenger.FireEvent(EventNames.QSBServerSendPlayerStates);
foreach (var item in QSBPlayerManager.GetSyncObjects<TransformSync.TransformSync>()
.Where(x => x != null && x.IsReady && x.ReferenceSector != null))
{
GlobalMessenger<uint, QSBSector>.FireEvent(EventNames.QSBSectorChange, item.netId.Value, item.ReferenceSector);
}
}
}
}
public override void OnServerReceive(PlayerMessage message)
{
DebugLog.DebugWrite($"[S] Get state request from {message.FromId}");
GlobalMessenger.FireEvent(EventNames.QSBServerSendPlayerStates);
foreach (var item in QSBPlayerManager.GetSyncObjects<TransformSync.TransformSync>()
.Where(x => x != null && x.IsReady && x.ReferenceSector != null))
{
GlobalMessenger<uint, QSBSector>.FireEvent(EventNames.QSBSectorChange, item.NetId.Value, item.ReferenceSector);
}
}
}
}

View File

@ -4,37 +4,37 @@ using QSB.Utility;
namespace QSB.Player.Events
{
public class ServerSendPlayerStatesEvent : QSBEvent<PlayerStateMessage>
{
public override EventType Type => EventType.PlayerState;
public class ServerSendPlayerStatesEvent : QSBEvent<PlayerStateMessage>
{
public override EventType Type => EventType.PlayerState;
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBServerSendPlayerStates, Handler);
public override void SetupListener() => GlobalMessenger.AddListener(EventNames.QSBServerSendPlayerStates, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBServerSendPlayerStates, Handler);
public override void CloseListener() => GlobalMessenger.RemoveListener(EventNames.QSBServerSendPlayerStates, Handler);
private void Handler()
{
foreach (var player in QSBPlayerManager.PlayerList)
{
DebugLog.DebugWrite($" - Sending playerstate of player ID {player.PlayerId}", MessageType.Info);
SendEvent(CreateMessage(player));
}
}
private void Handler()
{
foreach (var player in QSBPlayerManager.PlayerList)
{
DebugLog.DebugWrite($" - Sending playerstate of player ID {player.PlayerId}", MessageType.Info);
SendEvent(CreateMessage(player));
}
}
private PlayerStateMessage CreateMessage(PlayerInfo player) => new PlayerStateMessage
{
AboutId = player.PlayerId,
PlayerName = player.Name,
PlayerReady = player.IsReady,
PlayerState = player.State
};
private PlayerStateMessage CreateMessage(PlayerInfo player) => new PlayerStateMessage
{
AboutId = player.PlayerId,
PlayerName = player.Name,
PlayerReady = player.IsReady,
PlayerState = player.State
};
public override void OnReceiveRemote(PlayerStateMessage message)
{
DebugLog.DebugWrite($"Received playerstate of player ID {message.AboutId}", MessageType.Info);
QSB.Helper.Events.Unity.RunWhen(
() => QSBPlayerManager.GetSyncObject<TransformSync.TransformSync>(message.AboutId) != null,
() => QSBPlayerManager.HandleFullStateMessage(message));
}
}
}
public override void OnReceiveRemote(PlayerStateMessage message)
{
DebugLog.DebugWrite($"Received playerstate of player ID {message.AboutId}", MessageType.Info);
QSB.Helper.Events.Unity.RunWhen(
() => QSBPlayerManager.GetSyncObject<TransformSync.TransformSync>(message.AboutId) != null,
() => QSBPlayerManager.HandleFullStateMessage(message));
}
}
}

View File

@ -2,58 +2,57 @@
namespace QSB.Player
{
public class PlayerHUDMarker : HUDDistanceMarker
{
private PlayerInfo _player;
private bool _isReady;
public class PlayerHUDMarker : HUDDistanceMarker
{
private PlayerInfo _player;
private bool _isReady;
protected override void InitCanvasMarker()
{
_markerRadius = 2f;
protected override void InitCanvasMarker()
{
_markerRadius = 2f;
_markerTarget = new GameObject().transform;
_markerTarget.parent = transform;
_markerTarget = new GameObject().transform;
_markerTarget.parent = transform;
_markerTarget.localPosition = Vector3.up * 2;
}
_markerTarget.localPosition = Vector3.up * 2;
}
public void Init(PlayerInfo player)
{
_player = player;
_player.HudMarker = this;
_isReady = true;
}
public void Init(PlayerInfo player)
{
_player = player;
_player.HudMarker = this;
_isReady = true;
}
protected override void RefreshOwnVisibility()
{
if (_canvasMarker != null)
{
_canvasMarker.SetVisibility(true);
}
}
protected override void RefreshOwnVisibility()
{
if (_canvasMarker != null)
{
_canvasMarker.SetVisibility(true);
}
}
private void Update()
{
if (!_isReady || !_player.IsReady)
{
return;
}
_markerLabel = _player.Name.ToUpper();
_isReady = false;
private void Update()
{
if (!_isReady || !_player.IsReady)
{
return;
}
_markerLabel = _player.Name.ToUpper();
_isReady = false;
base.InitCanvasMarker();
}
base.InitCanvasMarker();
}
public void Remove()
{
// do N O T destroy the parent - it completely breaks the ENTIRE GAME
if (_canvasMarker?.gameObject != null)
{
_canvasMarker.DestroyMarker();
}
Destroy(_markerTarget.gameObject);
Destroy(this);
}
}
}
public void Remove()
{
// do N O T destroy the parent - it completely breaks the ENTIRE GAME
if (_canvasMarker?.gameObject != null)
{
_canvasMarker.DestroyMarker();
}
Destroy(_markerTarget.gameObject);
Destroy(this);
}
}
}

View File

@ -6,79 +6,82 @@ using UnityEngine;
namespace QSB.Player
{
public class PlayerInfo
{
public uint PlayerId { get; }
public string Name { get; set; }
public bool IsReady { get; set; }
public PlayerHUDMarker HudMarker { get; set; }
public State State { get; set; }
public class PlayerInfo
{
public uint PlayerId { get; }
public string Name { get; set; }
public bool IsReady { get; set; }
public PlayerHUDMarker HudMarker { get; set; }
public State State { get; set; }
// Body Objects
public GameObject Camera { get; set; }
public GameObject Body { get; set; }
// Body Objects
public GameObject Camera { get; set; }
// Tools
public GameObject ProbeBody { get; set; }
public QSBProbe Probe { get; set; }
public QSBFlashlight FlashLight => Camera?.GetComponentInChildren<QSBFlashlight>();
public QSBTool Signalscope => GetToolByType(ToolType.Signalscope);
public QSBTool Translator => GetToolByType(ToolType.Translator);
public QSBTool ProbeLauncher => GetToolByType(ToolType.ProbeLauncher);
public GameObject Body { get; set; }
// Conversation
public int CurrentDialogueID { get; set; }
public GameObject CurrentDialogueBox { get; set; }
// Tools
public GameObject ProbeBody { get; set; }
// Animation
public AnimationSync AnimationSync => QSBPlayerManager.GetSyncObject<AnimationSync>(PlayerId);
public bool PlayingInstrument => AnimationSync.CurrentType != AnimationType.PlayerSuited
&& AnimationSync.CurrentType != AnimationType.PlayerUnsuited;
public QSBProbe Probe { get; set; }
public QSBFlashlight FlashLight => Camera?.GetComponentInChildren<QSBFlashlight>();
public QSBTool Signalscope => GetToolByType(ToolType.Signalscope);
public QSBTool Translator => GetToolByType(ToolType.Translator);
public QSBTool ProbeLauncher => GetToolByType(ToolType.ProbeLauncher);
public PlayerInfo(uint id)
{
DebugLog.DebugWrite($"Creating PlayerInfo with id {id}");
PlayerId = id;
CurrentDialogueID = -1;
}
// Conversation
public int CurrentDialogueID { get; set; }
public void UpdateState(State state, bool value)
{
var states = State;
if (value)
{
FlagsHelper.Set(ref states, state);
}
else
{
FlagsHelper.Unset(ref states, state);
}
State = states;
}
public GameObject CurrentDialogueBox { get; set; }
public void UpdateStateObjects()
{
if (OWInput.GetInputMode() == InputMode.None)
{
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));
QSB.Helper.Events.Unity.RunWhen(() => QSBPlayerManager.GetSyncObject<AnimationSync>(PlayerId) != null,
() => QSBPlayerManager.GetSyncObject<AnimationSync>(PlayerId).SetSuitState(FlagsHelper.IsSet(State, State.Suit)));
}
// Animation
public AnimationSync AnimationSync => QSBPlayerManager.GetSyncObject<AnimationSync>(PlayerId);
public bool GetState(State state)
{
return FlagsHelper.IsSet(State, state);
}
public bool PlayingInstrument => AnimationSync.CurrentType != AnimationType.PlayerSuited
&& AnimationSync.CurrentType != AnimationType.PlayerUnsuited;
private QSBTool GetToolByType(ToolType type)
{
return Camera?.GetComponentsInChildren<QSBTool>()
.FirstOrDefault(x => x.Type == type);
}
}
public PlayerInfo(uint id)
{
PlayerId = id;
CurrentDialogueID = -1;
}
public void UpdateState(State state, bool value)
{
var states = State;
if (value)
{
FlagsHelper.Set(ref states, state);
}
else
{
FlagsHelper.Unset(ref states, state);
}
State = states;
}
public void UpdateStateObjects()
{
if (OWInput.GetInputMode() == InputMode.None)
{
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));
QSB.Helper.Events.Unity.RunWhen(() => QSBPlayerManager.GetSyncObject<AnimationSync>(PlayerId) != null,
() => QSBPlayerManager.GetSyncObject<AnimationSync>(PlayerId).SetSuitState(FlagsHelper.IsSet(State, State.Suit)));
}
public bool GetState(State state)
{
return FlagsHelper.IsSet(State, state);
}
private QSBTool GetToolByType(ToolType type)
{
return Camera?.GetComponentsInChildren<QSBTool>()
.FirstOrDefault(x => x.Type == type);
}
}
}

View File

@ -1,12 +1,12 @@
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.Player
{
public abstract class PlayerSyncObject : NetworkBehaviour
{
public uint AttachedNetId => GetComponent<NetworkIdentity>()?.netId.Value ?? uint.MaxValue;
public uint PlayerId => this.GetPlayerOfObject();
public uint PreviousPlayerId { get; set; }
public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId);
}
}
public abstract class PlayerSyncObject : QSBNetworkBehaviour
{
public uint AttachedNetId => GetComponent<QSBNetworkIdentity>()?.NetId.Value ?? uint.MaxValue;
public uint PlayerId => this.GetPlayerOfObject();
public uint PreviousPlayerId { get; set; }
public PlayerInfo Player => QSBPlayerManager.GetPlayer(PlayerId);
}
}

View File

@ -2,148 +2,148 @@
using QSB.Player.Events;
using QSB.TransformSync;
using QSB.Utility;
using QuantumUNET;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Networking;
namespace QSB.Player
{
public static class QSBPlayerManager
{
public static uint LocalPlayerId => PlayerTransformSync.LocalInstance.GetComponent<NetworkIdentity>()?.netId.Value ?? uint.MaxValue;
public static PlayerInfo LocalPlayer => GetPlayer(LocalPlayerId);
public static List<PlayerInfo> PlayerList { get; } = new List<PlayerInfo>();
public static class QSBPlayerManager
{
public static uint LocalPlayerId => PlayerTransformSync.LocalInstance.GetComponent<QSBNetworkIdentity>()?.NetId.Value ?? uint.MaxValue;
public static PlayerInfo LocalPlayer => GetPlayer(LocalPlayerId);
public static List<PlayerInfo> PlayerList { get; } = new List<PlayerInfo>();
public static List<PlayerSyncObject> PlayerSyncObjects { get; } = new List<PlayerSyncObject>();
public static List<PlayerSyncObject> PlayerSyncObjects { get; } = new List<PlayerSyncObject>();
public static PlayerInfo GetPlayer(uint id)
{
if (id == uint.MaxValue || id == 0U)
{
return default;
}
var player = PlayerList.FirstOrDefault(x => x.PlayerId == id);
if (player != null)
{
return player;
}
DebugLog.DebugWrite($"Creating player id {id}", MessageType.Info);
player = new PlayerInfo(id);
PlayerList.Add(player);
return player;
}
public static PlayerInfo GetPlayer(uint id)
{
if (id == uint.MaxValue || id == 0U)
{
return default;
}
var player = PlayerList.FirstOrDefault(x => x.PlayerId == id);
if (player != null)
{
return player;
}
DebugLog.DebugWrite($"Creating player id {id}", MessageType.Info);
player = new PlayerInfo(id);
PlayerList.Add(player);
return player;
}
public static void RemovePlayer(uint id)
{
DebugLog.DebugWrite($"Removing player {GetPlayer(id).Name} id {id}", MessageType.Info);
PlayerList.Remove(GetPlayer(id));
}
public static void RemovePlayer(uint id)
{
DebugLog.DebugWrite($"Removing player {GetPlayer(id).Name} id {id}", MessageType.Info);
PlayerList.Remove(GetPlayer(id));
}
public static void RemoveAllPlayers()
{
DebugLog.DebugWrite($"Removing all players.", MessageType.Info);
PlayerList.Clear();
}
public static void RemoveAllPlayers()
{
DebugLog.DebugWrite($"Removing all players.", MessageType.Info);
PlayerList.Clear();
}
public static bool PlayerExists(uint id)
{
return id != uint.MaxValue && PlayerList.Any(x => x.PlayerId == id);
}
public static bool PlayerExists(uint id)
{
return id != uint.MaxValue && PlayerList.Any(x => x.PlayerId == id);
}
public static void HandleFullStateMessage(PlayerStateMessage message)
{
var player = GetPlayer(message.AboutId);
player.Name = message.PlayerName;
player.IsReady = message.PlayerReady;
player.State = message.PlayerState;
if (LocalPlayer.IsReady)
{
player.UpdateStateObjects();
}
}
public static void HandleFullStateMessage(PlayerStateMessage message)
{
var player = GetPlayer(message.AboutId);
player.Name = message.PlayerName;
player.IsReady = message.PlayerReady;
player.State = message.PlayerState;
if (LocalPlayer.IsReady)
{
player.UpdateStateObjects();
}
}
public static IEnumerable<T> GetSyncObjects<T>() where T : PlayerSyncObject
{
return PlayerSyncObjects.OfType<T>().Where(x => x != null);
}
public static IEnumerable<T> GetSyncObjects<T>() where T : PlayerSyncObject
{
return PlayerSyncObjects.OfType<T>().Where(x => x != null);
}
public static T GetSyncObject<T>(uint id) where T : PlayerSyncObject
{
return GetSyncObjects<T>().FirstOrDefault(x => x != null && x.AttachedNetId == id);
}
public static T GetSyncObject<T>(uint id) where T : PlayerSyncObject
{
return GetSyncObjects<T>().FirstOrDefault(x => x != null && x.AttachedNetId == id);
}
public static bool IsBelongingToLocalPlayer(uint id)
{
return id == LocalPlayerId ||
PlayerSyncObjects.Any(x => x != null && x.AttachedNetId == id && x.isLocalPlayer);
}
public static bool IsBelongingToLocalPlayer(uint id)
{
return id == LocalPlayerId ||
PlayerSyncObjects.Any(x => x != null && x.AttachedNetId == id && x.IsLocalPlayer);
}
public static uint GetPlayerOfObject(this PlayerSyncObject syncObject)
{
if (PlayerList.Count == 0)
{
DebugLog.ToConsole($"Error - No players exist to find owner of object. (Attached NetID : {syncObject.AttachedNetId})", MessageType.Error);
syncObject.PreviousPlayerId = uint.MaxValue;
return uint.MaxValue;
}
// Get all Player IDs
var playerIds = PlayerList.Select(x => x.PlayerId).ToList();
// Get highest ID below the given syncobject's netid. A netid cannot belong to a playerid above it, only below or equal to it.
var lowerBound = playerIds.Where(x => x <= syncObject.AttachedNetId).ToList().Max();
if (playerIds.Min() > syncObject.AttachedNetId)
{
DebugLog.ToConsole($"Warning - Minimum playerid is greater than syncobject's netid. (Attached NetID : {syncObject.AttachedNetId})", MessageType.Warning);
syncObject.PreviousPlayerId = uint.MaxValue;
return uint.MaxValue;
}
// If the player list count is not the same as the count of the same type syncobject (eg. 3 players and 4 PlayerTransformSyncs)
// and the highest ID below the syncobject's id is the same as the highest player id.
if (PlayerList.Count != PlayerSyncObjects.Count(x => x.GetType() == syncObject.GetType()) && lowerBound == playerIds.Max())
{
// If the previous player id was not the error value, return it. To smooth over discrepancies between player list and object list.
if (syncObject.PreviousPlayerId != uint.MaxValue)
{
return syncObject.PreviousPlayerId;
}
// If the syncobject is a PlayerTransformSync, make a player.
if (syncObject.GetType() == typeof(PlayerTransformSync) && syncObject.AttachedNetId != 0U)
{
return GetPlayer(syncObject.AttachedNetId).PlayerId;
}
DebugLog.ToConsole($"Warning - Unequal player:syncobject count. ({PlayerList.Count}:{PlayerSyncObjects.Count(x => x.GetType() == syncObject.GetType())}) (Attached NetID : {syncObject.AttachedNetId})", MessageType.Warning);
syncObject.PreviousPlayerId = uint.MaxValue;
return uint.MaxValue;
}
if (syncObject.PreviousPlayerId == uint.MaxValue)
{
DebugLog.ToConsole($"Warning - Syncobject previously had uint.MaxValue as it's playerid. (Attached NetID : {syncObject.AttachedNetId})", MessageType.Warning);
}
syncObject.PreviousPlayerId = lowerBound;
return lowerBound;
}
public static uint GetPlayerOfObject(this PlayerSyncObject syncObject)
{
if (PlayerList.Count == 0)
{
DebugLog.ToConsole($"Error - No players exist to find owner of object. (Attached NetID : {syncObject.AttachedNetId})", MessageType.Error);
syncObject.PreviousPlayerId = uint.MaxValue;
return uint.MaxValue;
}
// Get all Player IDs
var playerIds = PlayerList.Select(x => x.PlayerId).ToList();
// Get highest ID below the given syncobject's netid. A netid cannot belong to a playerid above it, only below or equal to it.
var lowerBound = playerIds.Where(x => x <= syncObject.AttachedNetId).ToList().Max();
if (playerIds.Min() > syncObject.AttachedNetId)
{
DebugLog.ToConsole($"Warning - Minimum playerid is greater than syncobject's netid. (Attached NetID : {syncObject.AttachedNetId})", MessageType.Warning);
syncObject.PreviousPlayerId = uint.MaxValue;
return uint.MaxValue;
}
// If the player list count is not the same as the count of the same type syncobject (eg. 3 players and 4 PlayerTransformSyncs)
// and the highest ID below the syncobject's id is the same as the highest player id.
if (PlayerList.Count != PlayerSyncObjects.Count(x => x.GetType() == syncObject.GetType()) && lowerBound == playerIds.Max())
{
// If the previous player id was not the error value, return it. To smooth over discrepancies between player list and object list.
if (syncObject.PreviousPlayerId != uint.MaxValue)
{
return syncObject.PreviousPlayerId;
}
// If the syncobject is a PlayerTransformSync, make a player.
if (syncObject.GetType() == typeof(PlayerTransformSync) && syncObject.AttachedNetId != 0U)
{
return GetPlayer(syncObject.AttachedNetId).PlayerId;
}
DebugLog.ToConsole($"Warning - Unequal player:syncobject count. ({PlayerList.Count}:{PlayerSyncObjects.Count(x => x.GetType() == syncObject.GetType())}) (Attached NetID : {syncObject.AttachedNetId})", MessageType.Warning);
syncObject.PreviousPlayerId = uint.MaxValue;
return uint.MaxValue;
}
if (syncObject.PreviousPlayerId == uint.MaxValue)
{
DebugLog.ToConsole($"Warning - Syncobject previously had uint.MaxValue as it's playerid. (Attached NetID : {syncObject.AttachedNetId})", MessageType.Warning);
}
syncObject.PreviousPlayerId = lowerBound;
return lowerBound;
}
public static List<uint> GetPlayerNetIds(PlayerInfo player)
{
if (PlayerSyncObjects.Count == 0)
{
return default;
}
int count = 0;
int totalCount = PlayerSyncObjects.Count;
PlayerSyncObjects.RemoveAll(x => x == null);
PlayerSyncObjects.RemoveAll(x => x.GetComponent<NetworkIdentity>() == null);
if (PlayerSyncObjects.Count != totalCount)
{
DebugLog.ToConsole($"Warning - Removed {totalCount - PlayerSyncObjects.Count} items from PlayerSyncObjects.", MessageType.Warning);
}
foreach (var item in PlayerSyncObjects.DistinctBy(x => x.AttachedNetId))
{
if (item.PlayerId == player.PlayerId)
{
count++;
}
}
return Enumerable.Range((int)player.PlayerId, count).Select(x => (uint)x).ToList();
}
}
}
public static List<uint> GetPlayerNetIds(PlayerInfo player)
{
if (PlayerSyncObjects.Count == 0)
{
return default;
}
int count = 0;
int totalCount = PlayerSyncObjects.Count;
PlayerSyncObjects.RemoveAll(x => x == null);
PlayerSyncObjects.RemoveAll(x => x.GetComponent<QSBNetworkIdentity>() == null);
if (PlayerSyncObjects.Count != totalCount)
{
DebugLog.ToConsole($"Warning - Removed {totalCount - PlayerSyncObjects.Count} items from PlayerSyncObjects.", MessageType.Warning);
}
foreach (var item in PlayerSyncObjects.DistinctBy(x => x.AttachedNetId))
{
if (item.PlayerId == player.PlayerId)
{
count++;
}
}
return Enumerable.Range((int)player.PlayerId, count).Select(x => (uint)x).ToList();
}
}
}

View File

@ -2,16 +2,16 @@
namespace QSB.Player
{
[Flags]
public enum State
{
None = 0,
Flashlight = 1,
Suit = 2,
ProbeLauncher = 4,
Signalscope = 8,
Translator = 16,
ProbeActive = 32
//Increment these in binary to add more states
}
[Flags]
public enum State
{
None = 0,
Flashlight = 1,
Suit = 2,
ProbeLauncher = 4,
Signalscope = 8,
Translator = 16,
ProbeActive = 32
//Increment these in binary to add more states
}
}

View File

@ -32,4 +32,4 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -9,72 +9,77 @@ using QSB.Patches;
using QSB.SectorSync;
using QSB.TimeSync;
using QSB.Utility;
using QuantumUNET;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB
{
public class QSB : ModBehaviour
{
public static IModBehaviour ModBehaviour { get; private set; }
public static IModHelper Helper { get; private set; }
public static string DefaultServerIP { get; private set; }
public static int Port { get; private set; }
public static bool DebugMode { get; private set; }
public static AssetBundle NetworkAssetBundle { get; private set; }
public static AssetBundle InstrumentAssetBundle { get; private set; }
public static bool HasWokenUp { get; set; }
public class QSB : ModBehaviour
{
public static IModBehaviour ModBehaviour { get; private set; }
public static IModHelper Helper { get; private set; }
public static string DefaultServerIP { get; private set; }
public static int Port { get; private set; }
public static bool DebugMode { get; private set; }
public static AssetBundle NetworkAssetBundle { get; private set; }
public static AssetBundle InstrumentAssetBundle { get; private set; }
public static bool HasWokenUp { get; set; }
private void Awake()
{
Application.runInBackground = true;
private void Awake()
{
Application.runInBackground = true;
var instance = TextTranslation.Get().GetValue<TextTranslation.TranslationTable>("m_table");
instance.theUITable[(int)UITextType.PleaseUseController] =
"<color=orange>Quantum Space Buddies</color> is best experienced with friends...";
var instance = TextTranslation.Get().GetValue<TextTranslation.TranslationTable>("m_table");
instance.theUITable[(int)UITextType.PleaseUseController] =
"<color=orange>Quantum Space Buddies</color> is best experienced with friends...";
ModBehaviour = this;
}
ModBehaviour = this;
private void Start()
{
Helper = ModHelper;
DebugLog.ToConsole($"* Start of QSB version {Helper.Manifest.Version} - authored by {Helper.Manifest.Author}", MessageType.Info);
LogFilter.currentLogLevel = LogFilter.Debug;
}
NetworkAssetBundle = Helper.Assets.LoadBundle("assets/network");
InstrumentAssetBundle = Helper.Assets.LoadBundle("assets/instruments");
private void Start()
{
Helper = ModHelper;
DebugLog.ToConsole($"* Start of QSB version {Helper.Manifest.Version} - authored by {Helper.Manifest.Author}", MessageType.Info);
QSBPatchManager.Init();
NetworkAssetBundle = Helper.Assets.LoadBundle("assets/network");
InstrumentAssetBundle = Helper.Assets.LoadBundle("assets/instruments");
QSBPatchManager.DoPatchType(QSBPatchTypes.OnModStart);
QSBPatchManager.Init();
// Turns out these are very finicky about what order they go. QSBNetworkManager seems to
// want to go first-ish, otherwise the NetworkManager complains about the PlayerPrefab being
// null (even though it isn't...)
gameObject.AddComponent<QSBNetworkManager>();
gameObject.AddComponent<NetworkManagerHUD>();
gameObject.AddComponent<DebugActions>();
gameObject.AddComponent<ElevatorManager>();
gameObject.AddComponent<GeyserManager>();
gameObject.AddComponent<OrbManager>();
gameObject.AddComponent<QSBSectorManager>();
gameObject.AddComponent<ConversationManager>();
gameObject.AddComponent<QSBInputManager>();
gameObject.AddComponent<TimeSyncUI>();
QSBPatchManager.DoPatchType(QSBPatchTypes.OnModStart);
// Stop players being able to pause
Helper.HarmonyHelper.EmptyMethod(typeof(OWTime).GetMethod("Pause"));
}
gameObject.AddComponent<QSBNetworkManager>();
gameObject.AddComponent<QSBNetworkManagerHUD>();
gameObject.AddComponent<DebugActions>();
gameObject.AddComponent<ElevatorManager>();
gameObject.AddComponent<GeyserManager>();
gameObject.AddComponent<OrbManager>();
gameObject.AddComponent<QSBSectorManager>();
gameObject.AddComponent<ConversationManager>();
gameObject.AddComponent<QSBInputManager>();
gameObject.AddComponent<TimeSyncUI>();
public override void Configure(IModConfig config)
{
DefaultServerIP = config.GetSettingsValue<string>("defaultServerIP");
Port = config.GetSettingsValue<int>("port");
if (QSBNetworkManager.Instance != null)
{
QSBNetworkManager.Instance.networkPort = Port;
}
DebugMode = config.GetSettingsValue<bool>("debugMode");
}
}
}
// Stop players being able to pause
Helper.HarmonyHelper.EmptyMethod(typeof(OWTime).GetMethod("Pause"));
}
private void Update()
{
QSBNetworkIdentity.UNetStaticUpdate();
}
public override void Configure(IModConfig config)
{
DefaultServerIP = config.GetSettingsValue<string>("defaultServerIP");
Port = config.GetSettingsValue<int>("port");
if (QSBNetworkManager.Instance != null)
{
QSBNetworkManager.Instance.networkPort = Port;
}
DebugMode = config.GetSettingsValue<bool>("debugMode");
}
}
}

View File

@ -127,11 +127,7 @@
<Compile Include="Animation\AnimControllerPatch.cs" />
<Compile Include="Animation\AnimFloatParam.cs" />
<Compile Include="Animation\CrouchSync.cs" />
<Compile Include="Animation\Events\QSBAnimationMessage.cs" />
<Compile Include="Animation\Events\QSBAnimationParametersMessage.cs" />
<Compile Include="Animation\Events\QSBAnimationTriggerMessage.cs" />
<Compile Include="Animation\PlayerHeadRotationSync.cs" />
<Compile Include="Animation\QSBNetworkAnimator.cs" />
<Compile Include="ConversationSync\Events\ConversationEvent.cs" />
<Compile Include="ConversationSync\Events\ConversationMessage.cs" />
<Compile Include="ConversationSync\ConversationPatches.cs" />
@ -154,6 +150,7 @@
<Compile Include="Instruments\InstrumentsManager.cs" />
<Compile Include="MessagesCore\EnumMessage.cs" />
<Compile Include="MessagesCore\FloatMessage.cs" />
<Compile Include="OrbSync\Events\OrbSlotMessage.cs" />
<Compile Include="OrbSync\OrbManager.cs" />
<Compile Include="OrbSync\Events\OrbSlotEvent.cs" />
<Compile Include="OrbSync\OrbPatches.cs" />
@ -195,6 +192,7 @@
<Compile Include="TransformSync\TransformSync.cs" />
<Compile Include="Utility\GOExtensions.cs" />
<Compile Include="Utility\ListExtensions.cs" />
<Compile Include="Utility\UnetExtensions.cs" />
<Compile Include="WorldSync\Events\BoolWorldObjectMessage.cs" />
<Compile Include="WorldSync\Events\WorldObjectMessage.cs" />
<Compile Include="Tools\QSBFlashlight.cs" />
@ -238,7 +236,12 @@
<None Include="manifest.json" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\QuantumUNET\QuantumUNET.csproj">
<Project>{C8C53004-1508-4F86-A419-4292C188DC2A}</Project>
<Name>QuantumUNET</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>md "$(OwmlDir)\Mods\$(ProjectName)"

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>E:\Epic\Epic Games\OuterWilds</GameDir>
<GameDir>D:\EpicGames\OuterWilds</GameDir>
<OwmlDir>C:\Users\Henry\AppData\Roaming\OuterWildsModManager\OWML</OwmlDir>
<ProjectView>ShowAllFiles</ProjectView>
</PropertyGroup>

View File

@ -2,56 +2,57 @@
namespace QSB
{
public delegate void InputEvent();
public delegate void InputEvent();
public class QSBInputManager : MonoBehaviour
{
public static QSBInputManager Instance;
public class QSBInputManager : MonoBehaviour
{
public static event InputEvent ChertTaunt;
public static event InputEvent ChertTaunt;
public static event InputEvent EskerTaunt;
public static event InputEvent RiebeckTaunt;
public static event InputEvent GabbroTaunt;
public static event InputEvent FeldsparTaunt;
public static event InputEvent ExitTaunt;
public static event InputEvent EskerTaunt;
public void Awake()
{
Instance = this;
}
public static event InputEvent RiebeckTaunt;
public void Update()
{
if (Input.GetKey(KeyCode.T))
{
// Listed order is from sun to dark bramble
if (Input.GetKeyDown(KeyCode.Alpha1))
{
ChertTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha2))
{
EskerTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha5))
{
RiebeckTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha4))
{
GabbroTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha3))
{
FeldsparTaunt?.Invoke();
}
}
public static event InputEvent GabbroTaunt;
if (OWInput.GetValue(InputLibrary.moveXZ, InputMode.None) != Vector2.zero
|| OWInput.GetValue(InputLibrary.jump, InputMode.None) != 0f)
{
ExitTaunt?.Invoke();
}
}
}
}
public static event InputEvent FeldsparTaunt;
public static event InputEvent ExitTaunt;
// TODO : finish instruments - disabled for 0.7.0 release
/*
public void Update()
{
if (Input.GetKey(KeyCode.T))
{
// Listed order is from sun to dark bramble
if (Input.GetKeyDown(KeyCode.Alpha1))
{
ChertTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha2))
{
EskerTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha5))
{
RiebeckTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha4))
{
GabbroTaunt?.Invoke();
}
else if (Input.GetKeyDown(KeyCode.Alpha3))
{
FeldsparTaunt?.Invoke();
}
}
if (OWInput.GetValue(InputLibrary.moveXZ, InputMode.None) != Vector2.zero
|| OWInput.GetValue(InputLibrary.jump, InputMode.None) != 0f)
{
ExitTaunt?.Invoke();
}
}
*/
}
}

View File

@ -6,65 +6,65 @@ using UnityEngine.Networking;
namespace QSB
{
public class QSBNetworkLobby : NetworkBehaviour
{
public bool CanEditName { get; set; }
public string PlayerName { get; private set; }
public class QSBNetworkLobby : NetworkBehaviour
{
public bool CanEditName { get; set; }
public string PlayerName { get; private set; }
private readonly string[] _defaultNames = {
"Arkose",
"Chert",
"Esker",
"Hal",
"Hornfels",
"Feldspar",
"Gabbro",
"Galena",
"Gneiss",
"Gossan",
"Marl",
"Mica",
"Moraine",
"Porphy",
"Riebeck",
"Rutile",
"Slate",
"Spinel",
"Tektite",
"Tephra",
"Tuff",
"Jinha"
};
private readonly string[] _defaultNames = {
"Arkose",
"Chert",
"Esker",
"Hal",
"Hornfels",
"Feldspar",
"Gabbro",
"Galena",
"Gneiss",
"Gossan",
"Marl",
"Mica",
"Moraine",
"Porphy",
"Riebeck",
"Rutile",
"Slate",
"Spinel",
"Tektite",
"Tephra",
"Tuff",
"Jinha"
};
private void Awake()
{
PlayerName = GetPlayerName();
CanEditName = true;
QSB.Helper.HarmonyHelper.EmptyMethod<NetworkManagerHUD>("Update");
}
private void Awake()
{
PlayerName = GetPlayerName();
CanEditName = true;
QSB.Helper.HarmonyHelper.EmptyMethod<NetworkManagerHUD>("Update");
}
private string GetPlayerName()
{
var profileManager = StandaloneProfileManager.SharedInstance;
profileManager.Initialize();
var profile = profileManager.GetValue<StandaloneProfileManager.ProfileData>("_currentProfile");
var profileName = profile?.profileName;
return !string.IsNullOrEmpty(profileName)
? profileName
: _defaultNames.OrderBy(x => Guid.NewGuid()).First();
}
private string GetPlayerName()
{
var profileManager = StandaloneProfileManager.SharedInstance;
profileManager.Initialize();
var profile = profileManager.GetValue<StandaloneProfileManager.ProfileData>("_currentProfile");
var profileName = profile?.profileName;
return !string.IsNullOrEmpty(profileName)
? profileName
: _defaultNames.OrderBy(x => Guid.NewGuid()).First();
}
private void OnGUI()
{
GUI.Label(new Rect(10, 10, 200f, 20f), "Name:");
if (CanEditName)
{
PlayerName = GUI.TextField(new Rect(60, 10, 145, 20f), PlayerName);
}
else
{
GUI.Label(new Rect(60, 10, 145, 20f), PlayerName);
}
}
}
}
private void OnGUI()
{
GUI.Label(new Rect(10, 10, 200f, 20f), "Name:");
if (CanEditName)
{
PlayerName = GUI.TextField(new Rect(60, 10, 145, 20f), PlayerName);
}
else
{
GUI.Label(new Rect(60, 10, 145, 20f), PlayerName);
}
}
}
}

View File

@ -14,6 +14,7 @@ using QSB.TimeSync;
using QSB.TransformSync;
using QSB.Utility;
using QSB.WorldSync;
using QuantumUNET;
using System;
using System.Linq;
using UnityEngine;
@ -21,276 +22,298 @@ using UnityEngine.Networking;
namespace QSB
{
public class QSBNetworkManager : NetworkManager
{
private const int MaxConnections = 128;
private const int MaxBufferedPackets = 64;
public class QSBNetworkManager : QSBNetworkManagerUNET
{
private const int MaxConnections = 128;
private const int MaxBufferedPackets = 64;
public static QSBNetworkManager Instance { get; private set; }
public static QSBNetworkManager Instance { get; private set; }
public event Action OnNetworkManagerReady;
public bool IsReady { get; private set; }
public event Action OnNetworkManagerReady;
private QSBNetworkLobby _lobby;
private AssetBundle _assetBundle;
private GameObject _shipPrefab;
private GameObject _cameraPrefab;
private GameObject _probePrefab;
public GameObject OrbPrefab;
public bool IsReady { get; private set; }
private void Awake()
{
Instance = this;
private QSBNetworkLobby _lobby;
private AssetBundle _assetBundle;
private GameObject _shipPrefab;
private GameObject _cameraPrefab;
private GameObject _probePrefab;
public GameObject OrbPrefab;
_lobby = gameObject.AddComponent<QSBNetworkLobby>();
_assetBundle = QSB.NetworkAssetBundle;
private void Awake()
{
Instance = this;
playerPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkplayer.prefab");
playerPrefab.AddComponent<PlayerTransformSync>();
playerPrefab.AddComponent<AnimationSync>();
playerPrefab.AddComponent<WakeUpSync>();
playerPrefab.AddComponent<InstrumentsManager>();
_lobby = gameObject.AddComponent<QSBNetworkLobby>();
_assetBundle = QSB.NetworkAssetBundle;
_shipPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkship.prefab");
_shipPrefab.AddComponent<ShipTransformSync>();
spawnPrefabs.Add(_shipPrefab);
playerPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkplayer.prefab");
var ident = playerPrefab.AddComponent<QSBNetworkIdentity>();
ident.LocalPlayerAuthority = true;
ident.SetValue("m_AssetId", playerPrefab.GetComponent<NetworkIdentity>().assetId);
ident.SetValue("m_SceneId", playerPrefab.GetComponent<NetworkIdentity>().sceneId);
Destroy(playerPrefab.GetComponent<NetworkTransform>());
Destroy(playerPrefab.GetComponent<NetworkIdentity>());
var transform = playerPrefab.AddComponent<QSBNetworkTransform>();
transform.SendInterval = 0.1f;
transform.SyncRotationAxis = QSBNetworkTransform.AxisSyncMode.AxisXYZ;
playerPrefab.AddComponent<PlayerTransformSync>();
playerPrefab.AddComponent<AnimationSync>();
playerPrefab.AddComponent<WakeUpSync>();
playerPrefab.AddComponent<InstrumentsManager>();
_cameraPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkcameraroot.prefab");
_cameraPrefab.AddComponent<PlayerCameraSync>();
spawnPrefabs.Add(_cameraPrefab);
_shipPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkship.prefab");
ident = _shipPrefab.AddComponent<QSBNetworkIdentity>();
ident.LocalPlayerAuthority = true;
ident.SetValue("m_AssetId", _shipPrefab.GetComponent<NetworkIdentity>().assetId);
ident.SetValue("m_SceneId", _shipPrefab.GetComponent<NetworkIdentity>().sceneId);
Destroy(_shipPrefab.GetComponent<NetworkTransform>());
Destroy(_shipPrefab.GetComponent<NetworkIdentity>());
transform = _shipPrefab.AddComponent<QSBNetworkTransform>();
transform.SendInterval = 0.1f;
transform.SyncRotationAxis = QSBNetworkTransform.AxisSyncMode.AxisXYZ;
_shipPrefab.AddComponent<ShipTransformSync>();
spawnPrefabs.Add(_shipPrefab);
_probePrefab = _assetBundle.LoadAsset<GameObject>("assets/networkprobe.prefab");
_probePrefab.AddComponent<PlayerProbeSync>();
spawnPrefabs.Add(_probePrefab);
_cameraPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkcameraroot.prefab");
ident = _cameraPrefab.AddComponent<QSBNetworkIdentity>();
ident.LocalPlayerAuthority = true;
ident.SetValue("m_AssetId", _cameraPrefab.GetComponent<NetworkIdentity>().assetId);
ident.SetValue("m_SceneId", _cameraPrefab.GetComponent<NetworkIdentity>().sceneId);
Destroy(_cameraPrefab.GetComponent<NetworkTransform>());
Destroy(_cameraPrefab.GetComponent<NetworkIdentity>());
transform = _cameraPrefab.AddComponent<QSBNetworkTransform>();
transform.SendInterval = 0.1f;
transform.SyncRotationAxis = QSBNetworkTransform.AxisSyncMode.AxisXYZ;
_cameraPrefab.AddComponent<PlayerCameraSync>();
spawnPrefabs.Add(_cameraPrefab);
OrbPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkorb.prefab");
OrbPrefab.AddComponent<NomaiOrbTransformSync>();
spawnPrefabs.Add(OrbPrefab);
_probePrefab = _assetBundle.LoadAsset<GameObject>("assets/networkprobe.prefab");
ident = _probePrefab.AddComponent<QSBNetworkIdentity>();
ident.LocalPlayerAuthority = true;
ident.SetValue("m_AssetId", _probePrefab.GetComponent<NetworkIdentity>().assetId);
ident.SetValue("m_SceneId", _probePrefab.GetComponent<NetworkIdentity>().sceneId);
Destroy(_probePrefab.GetComponent<NetworkTransform>());
Destroy(_probePrefab.GetComponent<NetworkIdentity>());
transform = _probePrefab.AddComponent<QSBNetworkTransform>();
transform.SendInterval = 0.1f;
transform.SyncRotationAxis = QSBNetworkTransform.AxisSyncMode.AxisXYZ;
_probePrefab.AddComponent<PlayerProbeSync>();
spawnPrefabs.Add(_probePrefab);
ConfigureNetworkManager();
QSBSceneManager.OnUniverseSceneLoaded += OnSceneLoaded;
}
OrbPrefab = _assetBundle.LoadAsset<GameObject>("assets/networkorb.prefab");
ident = OrbPrefab.AddComponent<QSBNetworkIdentity>();
ident.LocalPlayerAuthority = true;
ident.SetValue("m_AssetId", OrbPrefab.GetComponent<NetworkIdentity>().assetId);
ident.SetValue("m_SceneId", OrbPrefab.GetComponent<NetworkIdentity>().sceneId);
Destroy(OrbPrefab.GetComponent<NetworkTransform>());
Destroy(OrbPrefab.GetComponent<NetworkIdentity>());
transform = OrbPrefab.AddComponent<QSBNetworkTransform>();
transform.SendInterval = 0.1f;
transform.SyncRotationAxis = QSBNetworkTransform.AxisSyncMode.AxisXYZ;
OrbPrefab.AddComponent<NomaiOrbTransformSync>();
spawnPrefabs.Add(OrbPrefab);
private void OnDestroy()
{
QSBSceneManager.OnUniverseSceneLoaded -= OnSceneLoaded;
}
ConfigureNetworkManager();
QSBSceneManager.OnUniverseSceneLoaded += OnSceneLoaded;
}
private void OnSceneLoaded(OWScene scene)
{
OrbManager.Instance.BuildOrbs();
WorldRegistry.OldDialogueTrees.Clear();
WorldRegistry.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
}
private void OnDestroy()
=> QSBSceneManager.OnUniverseSceneLoaded -= OnSceneLoaded;
private void ConfigureNetworkManager()
{
networkAddress = QSB.DefaultServerIP;
networkPort = QSB.Port;
maxConnections = MaxConnections;
customConfig = true;
connectionConfig.AddChannel(QosType.Reliable);
connectionConfig.AddChannel(QosType.Unreliable);
this.SetValue("m_MaxBufferedPackets", MaxBufferedPackets);
channels.Add(QosType.Reliable);
channels.Add(QosType.Unreliable);
private void OnSceneLoaded(OWScene scene)
{
DebugLog.DebugWrite("scene loaded");
OrbManager.Instance.BuildOrbs();
OrbManager.Instance.QueueBuildSlots();
WorldRegistry.OldDialogueTrees.Clear();
WorldRegistry.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
}
DebugLog.DebugWrite("Network Manager ready.", MessageType.Success);
}
private void ConfigureNetworkManager()
{
networkAddress = QSB.DefaultServerIP;
networkPort = QSB.Port;
maxConnections = MaxConnections;
customConfig = true;
connectionConfig.AddChannel(QosType.Reliable);
connectionConfig.AddChannel(QosType.Unreliable);
this.SetValue("m_MaxBufferedPackets", MaxBufferedPackets);
channels.Add(QosType.Reliable);
channels.Add(QosType.Unreliable);
public override void OnStartServer()
{
DebugLog.DebugWrite("~~ ON START SERVER ~~", MessageType.Info);
if (WorldRegistry.OrbSyncList.Count == 0 && QSBSceneManager.IsInUniverse)
{
OrbManager.Instance.QueueBuildOrbs();
}
if (WorldRegistry.OldDialogueTrees.Count == 0 && QSBSceneManager.IsInUniverse)
{
WorldRegistry.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
}
DebugLog.DebugWrite("Network Manager ready.", MessageType.Success);
}
NetworkServer.UnregisterHandler(40);
NetworkServer.UnregisterHandler(41);
NetworkServer.UnregisterHandler(42);
NetworkServer.RegisterHandler(40, new NetworkMessageDelegate(QSBNetworkAnimator.OnAnimationServerMessage));
NetworkServer.RegisterHandler(41, new NetworkMessageDelegate(QSBNetworkAnimator.OnAnimationParametersServerMessage));
NetworkServer.RegisterHandler(42, new NetworkMessageDelegate(QSBNetworkAnimator.OnAnimationTriggerServerMessage));
}
public override void OnStartServer()
{
DebugLog.DebugWrite("OnStartServer", MessageType.Info);
if (WorldRegistry.OrbSyncList.Count == 0 && QSBSceneManager.IsInUniverse)
{
OrbManager.Instance.QueueBuildOrbs();
}
if (WorldRegistry.OldDialogueTrees.Count == 0 && QSBSceneManager.IsInUniverse)
{
WorldRegistry.OldDialogueTrees = Resources.FindObjectsOfTypeAll<CharacterDialogueTree>().ToList();
}
}
public override void OnServerAddPlayer(NetworkConnection connection, short playerControllerId) // Called on the server when a client joins
{
DebugLog.DebugWrite("[S] Add player");
base.OnServerAddPlayer(connection, playerControllerId);
public override void OnServerAddPlayer(QSBNetworkConnection connection, short playerControllerId) // Called on the server when a client joins
{
DebugLog.DebugWrite("OnServerAddPlayer", MessageType.Info);
base.OnServerAddPlayer(connection, playerControllerId);
// These have to be in a constant order (for now, until we get a better netId getting system...)
NetworkServer.SpawnWithClientAuthority(Instantiate(_shipPrefab), connection);
NetworkServer.SpawnWithClientAuthority(Instantiate(_cameraPrefab), connection);
NetworkServer.SpawnWithClientAuthority(Instantiate(_probePrefab), connection);
}
QSBNetworkServer.SpawnWithClientAuthority(Instantiate(_shipPrefab), connection);
QSBNetworkServer.SpawnWithClientAuthority(Instantiate(_cameraPrefab), connection);
QSBNetworkServer.SpawnWithClientAuthority(Instantiate(_probePrefab), connection);
}
public override void OnClientConnect(NetworkConnection connection) // Called on the client when connecting to a server
{
base.OnClientConnect(connection);
public override void OnClientConnect(QSBNetworkConnection connection) // Called on the client when connecting to a server
{
DebugLog.DebugWrite("OnClientConnect", MessageType.Info);
base.OnClientConnect(connection);
gameObject.AddComponent<SectorSync.SectorSync>();
gameObject.AddComponent<RespawnOnDeath>();
gameObject.AddComponent<PreventShipDestruction>();
gameObject.AddComponent<SectorSync.SectorSync>();
gameObject.AddComponent<RespawnOnDeath>();
gameObject.AddComponent<PreventShipDestruction>();
if (QSBSceneManager.IsInUniverse)
{
QSBSectorManager.Instance.RebuildSectors();
}
OrbManager.Instance.QueueBuildSlots();
if (QSBSceneManager.IsInUniverse)
{
QSBSectorManager.Instance.RebuildSectors();
OrbManager.Instance.QueueBuildSlots();
}
if (!NetworkServer.localClientActive)
{
QSBPatchManager.DoPatchType(QSBPatchTypes.OnNonServerClientConnect);
singleton.client.UnregisterHandler(40);
singleton.client.UnregisterHandler(41);
singleton.client.RegisterHandlerSafe(40, new NetworkMessageDelegate(QSBNetworkAnimator.OnAnimationClientMessage));
singleton.client.RegisterHandlerSafe(41, new NetworkMessageDelegate(QSBNetworkAnimator.OnAnimationParametersClientMessage));
}
singleton.client.UnregisterHandler(42);
singleton.client.RegisterHandlerSafe(42, new NetworkMessageDelegate(QSBNetworkAnimator.OnAnimationTriggerClientMessage));
if (!QSBNetworkServer.localClientActive)
{
QSBPatchManager.DoPatchType(QSBPatchTypes.OnNonServerClientConnect);
}
QSBPatchManager.DoPatchType(QSBPatchTypes.OnClientConnect);
QSBPatchManager.DoPatchType(QSBPatchTypes.OnClientConnect);
_lobby.CanEditName = false;
_lobby.CanEditName = false;
OnNetworkManagerReady?.Invoke();
IsReady = true;
OnNetworkManagerReady?.Invoke();
IsReady = true;
QSB.Helper.Events.Unity.RunWhen(() => PlayerTransformSync.LocalInstance != null, QSBEventManager.Init);
QSB.Helper.Events.Unity.RunWhen(() => PlayerTransformSync.LocalInstance != null, QSBEventManager.Init);
QSB.Helper.Events.Unity.RunWhen(() => QSBEventManager.Ready,
() => GlobalMessenger<string>.FireEvent(EventNames.QSBPlayerJoin, _lobby.PlayerName));
QSB.Helper.Events.Unity.RunWhen(() => QSBEventManager.Ready,
() => GlobalMessenger<string>.FireEvent(EventNames.QSBPlayerJoin, _lobby.PlayerName));
QSB.Helper.Events.Unity.RunWhen(() => QSBEventManager.Ready,
() => GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest));
}
QSB.Helper.Events.Unity.RunWhen(() => QSBEventManager.Ready,
() => GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest));
}
public override void OnStopClient() // Called on the client when closing connection
{
DebugLog.ToConsole("Disconnecting from server...", MessageType.Info);
Destroy(GetComponent<SectorSync.SectorSync>());
Destroy(GetComponent<RespawnOnDeath>());
Destroy(GetComponent<PreventShipDestruction>());
QSBEventManager.Reset();
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
public override void OnStopClient() // Called on the client when closing connection
{
DebugLog.DebugWrite("OnStopClient", MessageType.Info);
DebugLog.ToConsole("Disconnecting from server...", MessageType.Info);
Destroy(GetComponent<SectorSync.SectorSync>());
Destroy(GetComponent<RespawnOnDeath>());
Destroy(GetComponent<PreventShipDestruction>());
QSBEventManager.Reset();
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
foreach (var player in QSBPlayerManager.PlayerList)
{
QSBPlayerManager.GetPlayerNetIds(player).ForEach(CleanupNetworkBehaviour);
}
QSBPlayerManager.RemoveAllPlayers();
foreach (var player in QSBPlayerManager.PlayerList)
{
QSBPlayerManager.GetPlayerNetIds(player).ForEach(CleanupNetworkBehaviour);
}
QSBPlayerManager.RemoveAllPlayers();
WorldRegistry.RemoveObjects<QSBOrbSlot>();
WorldRegistry.RemoveObjects<QSBElevator>();
WorldRegistry.RemoveObjects<QSBGeyser>();
WorldRegistry.RemoveObjects<QSBSector>();
WorldRegistry.OrbSyncList.Clear();
WorldRegistry.OldDialogueTrees.Clear();
WorldRegistry.RemoveObjects<QSBOrbSlot>();
WorldRegistry.RemoveObjects<QSBElevator>();
WorldRegistry.RemoveObjects<QSBGeyser>();
WorldRegistry.RemoveObjects<QSBSector>();
WorldRegistry.OrbSyncList.Clear();
WorldRegistry.OldDialogueTrees.Clear();
_lobby.CanEditName = true;
}
_lobby.CanEditName = true;
}
public override void OnServerDisconnect(NetworkConnection connection) // Called on the server when any client disconnects
{
var playerId = connection.playerControllers[0].gameObject.GetComponent<PlayerTransformSync>().netId.Value;
var netIds = connection.clientOwnedObjects.Select(x => x.Value).ToArray();
GlobalMessenger<uint, uint[]>.FireEvent(EventNames.QSBPlayerLeave, playerId, netIds);
public override void OnServerDisconnect(QSBNetworkConnection connection) // Called on the server when any client disconnects
{
DebugLog.DebugWrite("OnServerDisconnect", MessageType.Info);
var player = connection.GetPlayer();
var netIds = connection.ClientOwnedObjects.Select(x => x.Value).ToArray();
GlobalMessenger<uint, uint[]>.FireEvent(EventNames.QSBPlayerLeave, player.PlayerId, netIds);
foreach (var item in WorldRegistry.OrbSyncList)
{
var identity = item.GetComponent<NetworkIdentity>();
if (identity.clientAuthorityOwner == connection)
{
identity.RemoveClientAuthority(connection);
}
}
foreach (var item in WorldRegistry.OrbSyncList)
{
var identity = item.GetComponent<QSBNetworkIdentity>();
if (identity.ClientAuthorityOwner == connection)
{
identity.RemoveClientAuthority(connection);
}
}
QSBPlayerManager.GetPlayer(playerId).HudMarker?.Remove();
CleanupConnection(connection);
}
player.HudMarker?.Remove();
CleanupConnection(connection);
}
public override void OnStopServer()
{
Destroy(GetComponent<SectorSync.SectorSync>());
Destroy(GetComponent<RespawnOnDeath>());
Destroy(GetComponent<PreventShipDestruction>());
QSBEventManager.Reset();
DebugLog.ToConsole("[S] Server stopped!", MessageType.Info);
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
NetworkServer.connections.ToList().ForEach(CleanupConnection);
public override void OnStopServer()
{
DebugLog.DebugWrite("OnStopServer", MessageType.Info);
Destroy(GetComponent<SectorSync.SectorSync>());
Destroy(GetComponent<RespawnOnDeath>());
Destroy(GetComponent<PreventShipDestruction>());
QSBEventManager.Reset();
DebugLog.ToConsole("[S] Server stopped!", MessageType.Info);
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
QSBNetworkServer.connections.ToList().ForEach(CleanupConnection);
WorldRegistry.RemoveObjects<QSBOrbSlot>();
WorldRegistry.RemoveObjects<QSBElevator>();
WorldRegistry.RemoveObjects<QSBGeyser>();
WorldRegistry.RemoveObjects<QSBSector>();
WorldRegistry.RemoveObjects<QSBOrbSlot>();
WorldRegistry.RemoveObjects<QSBElevator>();
WorldRegistry.RemoveObjects<QSBGeyser>();
WorldRegistry.RemoveObjects<QSBSector>();
base.OnStopServer();
}
base.OnStopServer();
}
private void CleanupConnection(NetworkConnection connection)
{
uint playerId;
try
{
playerId = connection.playerControllers[0].gameObject.GetComponent<PlayerTransformSync>().netId.Value;
}
catch (Exception ex)
{
DebugLog.ToConsole("Error when getting playerId in CleanupConnection: " + ex.Message, MessageType.Error);
return;
}
if (!QSBPlayerManager.PlayerExists(playerId))
{
return;
}
var playerName = QSBPlayerManager.GetPlayer(playerId).Name;
DebugLog.ToConsole($"{playerName} disconnected.", MessageType.Info);
QSBPlayerManager.RemovePlayer(playerId);
private void CleanupConnection(QSBNetworkConnection connection)
{
var player = connection.GetPlayer();
DebugLog.ToConsole($"{player.Name} disconnected.", MessageType.Info);
QSBPlayerManager.RemovePlayer(player.PlayerId);
var netIds = connection.clientOwnedObjects?.Select(x => x.Value).ToList();
netIds.ForEach(CleanupNetworkBehaviour);
}
var netIds = connection.ClientOwnedObjects?.Select(x => x.Value).ToList();
netIds.ForEach(CleanupNetworkBehaviour);
}
public void CleanupNetworkBehaviour(uint netId)
{
DebugLog.DebugWrite($"Cleaning up netId {netId}");
// Multiple networkbehaviours can use the same networkidentity (same netId), so get all of them
var networkBehaviours = FindObjectsOfType<NetworkBehaviour>()
.Where(x => x != null && x.netId.Value == netId);
foreach (var networkBehaviour in networkBehaviours)
{
var transformSync = networkBehaviour.GetComponent<TransformSync.TransformSync>();
public void CleanupNetworkBehaviour(uint netId)
{
DebugLog.DebugWrite($"Cleaning up netId {netId}");
// Multiple networkbehaviours can use the same networkidentity (same netId), so get all of them
var networkBehaviours = FindObjectsOfType<QSBNetworkBehaviour>()
.Where(x => x != null && x.NetId.Value == netId);
foreach (var networkBehaviour in networkBehaviours)
{
var transformSync = networkBehaviour.GetComponent<TransformSync.TransformSync>();
if (transformSync != null)
{
DebugLog.DebugWrite($" * Removing TransformSync from syncobjects");
QSBPlayerManager.PlayerSyncObjects.Remove(transformSync);
if (transformSync.SyncedTransform != null && netId != QSBPlayerManager.LocalPlayerId && !networkBehaviour.hasAuthority)
{
DebugLog.DebugWrite($" * Destroying {transformSync.SyncedTransform.gameObject.name}");
Destroy(transformSync.SyncedTransform.gameObject);
}
}
if (transformSync != null)
{
DebugLog.DebugWrite($" * Removing TransformSync from syncobjects");
QSBPlayerManager.PlayerSyncObjects.Remove(transformSync);
if (transformSync.SyncedTransform != null && netId != QSBPlayerManager.LocalPlayerId && !networkBehaviour.HasAuthority)
{
DebugLog.DebugWrite($" * Destroying {transformSync.SyncedTransform.gameObject.name}");
Destroy(transformSync.SyncedTransform.gameObject);
}
}
var animationSync = networkBehaviour.GetComponent<AnimationSync>();
var animationSync = networkBehaviour.GetComponent<AnimationSync>();
if (animationSync != null)
{
DebugLog.DebugWrite($" * Removing AnimationSync from syncobjects");
QSBPlayerManager.PlayerSyncObjects.Remove(animationSync);
}
if (animationSync != null)
{
DebugLog.DebugWrite($" * Removing AnimationSync from syncobjects");
QSBPlayerManager.PlayerSyncObjects.Remove(animationSync);
}
if (!networkBehaviour.hasAuthority)
{
DebugLog.DebugWrite($" * Destroying {networkBehaviour.gameObject.name}");
Destroy(networkBehaviour.gameObject);
}
}
}
}
if (!networkBehaviour.HasAuthority)
{
DebugLog.DebugWrite($" * Destroying {networkBehaviour.gameObject.name}");
Destroy(networkBehaviour.gameObject);
}
}
}
}
}

View File

@ -4,34 +4,34 @@ using System;
namespace QSB
{
public static class QSBSceneManager
{
public static OWScene CurrentScene => LoadManager.GetCurrentScene();
public static class QSBSceneManager
{
public static OWScene CurrentScene => LoadManager.GetCurrentScene();
public static bool IsInUniverse => InUniverse(CurrentScene);
public static bool IsInUniverse => InUniverse(CurrentScene);
public static event Action<OWScene, bool> OnSceneLoaded;
public static event Action<OWScene> OnUniverseSceneLoaded;
public static event Action<OWScene, bool> OnSceneLoaded;
static QSBSceneManager()
{
LoadManager.OnCompleteSceneLoad += OnCompleteSceneLoad;
DebugLog.DebugWrite("Scene Manager ready.", MessageType.Success);
}
public static event Action<OWScene> OnUniverseSceneLoaded;
private static void OnCompleteSceneLoad(OWScene oldScene, OWScene newScene)
{
var universe = InUniverse(newScene);
OnSceneLoaded?.Invoke(newScene, universe);
if (universe)
{
OnUniverseSceneLoaded?.Invoke(newScene);
}
}
static QSBSceneManager()
{
LoadManager.OnCompleteSceneLoad += OnCompleteSceneLoad;
DebugLog.DebugWrite("Scene Manager ready.", MessageType.Success);
}
private static bool InUniverse(OWScene scene)
{
return scene == OWScene.SolarSystem || scene == OWScene.EyeOfTheUniverse;
}
}
}
private static void OnCompleteSceneLoad(OWScene oldScene, OWScene newScene)
{
DebugLog.DebugWrite($"COMPLETE SCENE LOAD ({oldScene} -> {newScene})", MessageType.Info);
var universe = InUniverse(newScene);
OnSceneLoaded?.Invoke(newScene, universe);
if (universe)
{
OnUniverseSceneLoaded?.Invoke(newScene);
}
}
private static bool InUniverse(OWScene scene)
=> scene == OWScene.SolarSystem || scene == OWScene.EyeOfTheUniverse;
}
}

View File

@ -3,18 +3,18 @@ using UnityEngine;
namespace QSB.SectorSync
{
public class QSBSector : WorldObject
{
public Sector Sector { get; private set; }
public Sector.Name Type => Sector.GetName();
public string Name => Sector.name;
public Transform Transform => Sector.transform;
public Vector3 Position => Transform.position;
public class QSBSector : WorldObject
{
public Sector Sector { get; private set; }
public Sector.Name Type => Sector.GetName();
public string Name => Sector.name;
public Transform Transform => Sector.transform;
public Vector3 Position => Transform.position;
public void Init(Sector sector, int id)
{
Sector = sector;
ObjectId = id;
}
}
}
public void Init(Sector sector, int id)
{
Sector = sector;
ObjectId = id;
}
}
}

View File

@ -6,57 +6,49 @@ using UnityEngine;
namespace QSB.SectorSync
{
public class QSBSectorManager : MonoBehaviour
{
public static QSBSectorManager Instance { get; private set; }
public class QSBSectorManager : MonoBehaviour
{
public static QSBSectorManager Instance { get; private set; }
public bool IsReady { get; private set; }
public bool IsReady { get; private set; }
private readonly Sector.Name[] _sectorBlacklist =
{
Sector.Name.Ship
};
private readonly Sector.Name[] _sectorBlacklist =
{
Sector.Name.Ship
};
private void Awake()
{
Instance = this;
QSBSceneManager.OnUniverseSceneLoaded += (OWScene scene) => RebuildSectors();
DebugLog.DebugWrite("Sector Manager ready.", MessageType.Success);
}
private void OnDestroy()
{
QSBSceneManager.OnUniverseSceneLoaded -= (OWScene scene) => RebuildSectors();
}
private void Awake()
{
Instance = this;
QSBSceneManager.OnUniverseSceneLoaded += (OWScene scene) => RebuildSectors();
DebugLog.DebugWrite("Sector Manager ready.", MessageType.Success);
}
public void RebuildSectors()
{
DebugLog.DebugWrite("Rebuilding sectors...", MessageType.Warning);
WorldRegistry.RemoveObjects<QSBSector>();
var sectors = Resources.FindObjectsOfTypeAll<Sector>().ToList();
for (var id = 0; id < sectors.Count; id++)
{
var qsbSector = WorldRegistry.GetObject<QSBSector>(id) ?? new QSBSector();
qsbSector.Init(sectors[id], id);
WorldRegistry.AddObject(qsbSector);
}
IsReady = WorldRegistry.GetObjects<QSBSector>().Any();
}
private void OnDestroy()
{
QSBSceneManager.OnUniverseSceneLoaded -= (OWScene scene) => RebuildSectors();
}
public QSBSector GetClosestSector(Transform trans)
{
return WorldRegistry.GetObjects<QSBSector>()
.Where(sector => sector.Sector != null && !_sectorBlacklist.Contains(sector.Type))
.OrderBy(sector => Vector3.Distance(sector.Position, trans.position))
.First();
}
public void RebuildSectors()
{
DebugLog.DebugWrite("Rebuilding sectors...", MessageType.Warning);
WorldRegistry.RemoveObjects<QSBSector>();
var sectors = Resources.FindObjectsOfTypeAll<Sector>().ToList();
for (var id = 0; id < sectors.Count; id++)
{
var qsbSector = WorldRegistry.GetObject<QSBSector>(id) ?? new QSBSector();
qsbSector.Init(sectors[id], id);
WorldRegistry.AddObject(qsbSector);
}
IsReady = WorldRegistry.GetObjects<QSBSector>().Any();
}
public QSBSector GetStartPlanetSector()
{
var sector = QSBSceneManager.CurrentScene == OWScene.SolarSystem
? Locator.GetAstroObject(AstroObject.Name.TimberHearth).GetRootSector()
: Locator.GetAstroObject(AstroObject.Name.Eye).GetRootSector();
return WorldRegistry.GetObjects<QSBSector>()
.FirstOrDefault(x => x.Sector == sector);
}
}
}
public QSBSector GetClosestSector(Transform trans)
{
return WorldRegistry.GetObjects<QSBSector>()
.Where(sector => sector.Sector != null && !_sectorBlacklist.Contains(sector.Type))
.OrderBy(sector => Vector3.Distance(sector.Position, trans.position))
.First();
}
}
}

View File

@ -5,45 +5,45 @@ using UnityEngine;
namespace QSB.SectorSync
{
public class SectorSync : MonoBehaviour
{
private const float CheckInterval = 0.5f;
private float _checkTimer = CheckInterval;
public class SectorSync : MonoBehaviour
{
private const float CheckInterval = 0.5f;
private float _checkTimer = CheckInterval;
private void Update()
{
if (!QSBSectorManager.Instance.IsReady)
{
return;
}
_checkTimer += Time.unscaledDeltaTime;
if (_checkTimer < CheckInterval)
{
return;
}
QSBPlayerManager.GetSyncObjects<TransformSync.TransformSync>().Where(x => x.hasAuthority).ToList().ForEach(CheckTransformSyncSector);
_checkTimer = 0;
}
private void Update()
{
if (!QSBSectorManager.Instance.IsReady)
{
return;
}
_checkTimer += Time.unscaledDeltaTime;
if (_checkTimer < CheckInterval)
{
return;
}
QSBPlayerManager.GetSyncObjects<TransformSync.TransformSync>().Where(x => x.HasAuthority).ToList().ForEach(CheckTransformSyncSector);
_checkTimer = 0;
}
private void CheckTransformSyncSector(TransformSync.TransformSync transformSync)
{
var syncedTransform = transformSync.SyncedTransform;
if (syncedTransform == null || syncedTransform.position == Vector3.zero)
{
return;
}
var closestSector = QSBSectorManager.Instance.GetClosestSector(syncedTransform);
if (closestSector == transformSync.ReferenceSector)
{
return;
}
transformSync.ReferenceSector = closestSector;
SendSector(transformSync.netId.Value, closestSector);
}
private void CheckTransformSyncSector(TransformSync.TransformSync transformSync)
{
var syncedTransform = transformSync.SyncedTransform;
if (syncedTransform == null || syncedTransform.position == Vector3.zero)
{
return;
}
var closestSector = QSBSectorManager.Instance.GetClosestSector(syncedTransform);
if (closestSector == transformSync.ReferenceSector)
{
return;
}
transformSync.SetReferenceSector(closestSector);
SendSector(transformSync.NetId.Value, closestSector);
}
private void SendSector(uint id, QSBSector sector)
{
GlobalMessenger<uint, QSBSector>.FireEvent(EventNames.QSBSectorChange, id, sector);
}
}
}
private void SendSector(uint id, QSBSector sector)
{
GlobalMessenger<uint, QSBSector>.FireEvent(EventNames.QSBSectorChange, id, sector);
}
}
}

View File

@ -2,26 +2,26 @@
namespace QSB.TimeSync.Events
{
public class ServerTimeEvent : QSBEvent<ServerTimeMessage>
{
public override EventType Type => EventType.ServerTime;
public class ServerTimeEvent : QSBEvent<ServerTimeMessage>
{
public override EventType Type => EventType.ServerTime;
public override void SetupListener() => GlobalMessenger<float, int>.AddListener(EventNames.QSBServerTime, Handler);
public override void SetupListener() => GlobalMessenger<float, int>.AddListener(EventNames.QSBServerTime, Handler);
public override void CloseListener() => GlobalMessenger<float, int>.RemoveListener(EventNames.QSBServerTime, Handler);
public override void CloseListener() => GlobalMessenger<float, int>.RemoveListener(EventNames.QSBServerTime, Handler);
private void Handler(float time, int count) => SendEvent(CreateMessage(time, count));
private void Handler(float time, int count) => SendEvent(CreateMessage(time, count));
private ServerTimeMessage CreateMessage(float time, int count) => new ServerTimeMessage
{
AboutId = LocalPlayerId,
ServerTime = time,
LoopCount = count
};
private ServerTimeMessage CreateMessage(float time, int count) => new ServerTimeMessage
{
AboutId = LocalPlayerId,
ServerTime = time,
LoopCount = count
};
public override void OnReceiveRemote(ServerTimeMessage message)
{
WakeUpSync.LocalInstance.OnClientReceiveMessage(message);
}
}
}
public override void OnReceiveRemote(ServerTimeMessage message)
{
WakeUpSync.LocalInstance.OnClientReceiveMessage(message);
}
}
}

View File

@ -1,25 +1,25 @@
using QSB.Messaging;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.TimeSync.Events
{
public class ServerTimeMessage : PlayerMessage
{
public float ServerTime { get; set; }
public int LoopCount { get; set; }
public class ServerTimeMessage : PlayerMessage
{
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 Deserialize(QSBNetworkReader 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);
}
}
public override void Serialize(QSBNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(ServerTime);
writer.Write(LoopCount);
}
}
}

View File

@ -1,25 +1,25 @@
using OWML.ModHelper.Events;
using UnityEngine.Networking;
using QuantumUNET;
namespace QSB.TimeSync
{
public class PreserveTimeScale : NetworkBehaviour
{
private void Start()
{
QSB.Helper.Menus.PauseMenu.GetTitleButton("Button-EndCurrentLoop").Hide(); // Remove the meditation button
public class PreserveTimeScale : QSBNetworkBehaviour
{
private void Start()
{
QSB.Helper.Menus.PauseMenu.GetTitleButton("Button-EndCurrentLoop").Hide(); // Remove the meditation button
// Allow server to sleep at campfires
if (isServer)
{
return;
}
// Allow server to sleep at campfires
if (IsServer)
{
return;
}
var campfires = FindObjectsOfType<Campfire>();
foreach (var campfire in campfires)
{
campfire.SetValue("_canSleepHere", false); // Stop players from sleeping at campfires
}
}
}
}
var campfires = FindObjectsOfType<Campfire>();
foreach (var campfire in campfires)
{
campfire.SetValue("_canSleepHere", false); // Stop players from sleeping at campfires
}
}
}
}

View File

@ -1,9 +1,9 @@
namespace QSB.TimeSync
{
public enum TimeSyncType
{
None,
Pausing,
Fastforwarding
}
}
public enum TimeSyncType
{
None,
Pausing,
Fastforwarding
}
}

View File

@ -5,7 +5,7 @@ using UnityEngine.UI;
namespace QSB.TimeSync
{
class TimeSyncUI : MonoBehaviour
internal class TimeSyncUI : MonoBehaviour
{
public static TimeSyncUI Instance;
@ -42,6 +42,7 @@ namespace QSB.TimeSync
}
public static void Start(TimeSyncType type) => QSB.Helper.Events.Unity.RunWhen(() => Instance._isSetUp, () => Instance.StartTimeSync(type));
public static void Stop() => QSB.Helper.Events.Unity.RunWhen(() => Instance._isSetUp, () => Instance.EndTimeSync());
private void StartTimeSync(TimeSyncType type)
@ -78,6 +79,7 @@ namespace QSB.TimeSync
+ Environment.NewLine
+ "Fast-forwarding to match server time...";
break;
case TimeSyncType.Pausing:
text = "Pausing to match server time...";
break;

View File

@ -2,22 +2,22 @@
namespace QSB.TimeSync
{
public class WakeUpPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnNonServerClientConnect;
public class WakeUpPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnNonServerClientConnect;
public static bool OnStartOfTimeLoopPrefix(ref PlayerCameraEffectController __instance)
{
if (__instance.gameObject.CompareTag("MainCamera") && QSBSceneManager.CurrentScene != OWScene.EyeOfTheUniverse)
{
__instance.Invoke("WakeUp");
}
return false;
}
public static bool OnStartOfTimeLoopPrefix(ref PlayerCameraEffectController __instance)
{
if (__instance.gameObject.CompareTag("MainCamera") && QSBSceneManager.CurrentScene != OWScene.EyeOfTheUniverse)
{
__instance.Invoke("WakeUp");
}
return false;
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPrefix<PlayerCameraEffectController>("OnStartOfTimeLoop", typeof(WakeUpPatches), nameof(OnStartOfTimeLoopPrefix));
}
}
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPrefix<PlayerCameraEffectController>("OnStartOfTimeLoop", typeof(WakeUpPatches), nameof(OnStartOfTimeLoopPrefix));
}
}
}

View File

@ -1,256 +1,255 @@
using QSB.DeathSync;
using QSB.EventsCore;
using QSB.TimeSync.Events;
using QSB.Utility;
using QuantumUNET;
using UnityEngine;
using UnityEngine.Networking;
namespace QSB.TimeSync
{
public class WakeUpSync : NetworkBehaviour
{
public static WakeUpSync LocalInstance { get; private set; }
public class WakeUpSync : QSBNetworkBehaviour
{
public static WakeUpSync LocalInstance { get; private set; }
private const float TimeThreshold = 0.5f;
private const float MaxFastForwardSpeed = 60f;
private const float MaxFastForwardDiff = 20f;
private const float MinFastForwardSpeed = 2f;
private const float TimeThreshold = 0.5f;
private const float MaxFastForwardSpeed = 60f;
private const float MaxFastForwardDiff = 20f;
private const float MinFastForwardSpeed = 2f;
private enum State { NotLoaded, Loaded, FastForwarding, Pausing }
private State _state = State.NotLoaded;
private enum State { NotLoaded, Loaded, FastForwarding, Pausing }
private float _sendTimer;
private float _serverTime;
private float _timeScale;
private bool _isInputEnabled = true;
private bool _isFirstFastForward = true;
private int _localLoopCount;
private int _serverLoopCount;
private State _state = State.NotLoaded;
public override void OnStartLocalPlayer()
{
LocalInstance = this;
}
private float _sendTimer;
private float _serverTime;
private float _timeScale;
private bool _isInputEnabled = true;
private bool _isFirstFastForward = true;
private int _localLoopCount;
private int _serverLoopCount;
private void Start()
{
if (!isLocalPlayer)
{
return;
}
public override void OnStartLocalPlayer()
{
LocalInstance = this;
}
if (QSBSceneManager.IsInUniverse)
{
Init();
}
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
private void Start()
{
if (!IsLocalPlayer)
{
return;
}
GlobalMessenger.AddListener(EventNames.RestartTimeLoop, OnLoopStart);
GlobalMessenger.AddListener(EventNames.WakeUp, OnWakeUp);
}
if (QSBSceneManager.IsInUniverse)
{
Init();
}
QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
private void OnWakeUp()
{
DebugLog.DebugWrite("ON WAKE UP!");
if (NetworkServer.active)
{
QSB.HasWokenUp = true;
}
}
GlobalMessenger.AddListener(EventNames.RestartTimeLoop, OnLoopStart);
GlobalMessenger.AddListener(EventNames.WakeUp, OnWakeUp);
}
private void OnDestroy()
{
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
GlobalMessenger.RemoveListener(EventNames.RestartTimeLoop, OnLoopStart);
GlobalMessenger.RemoveListener(EventNames.WakeUp, OnWakeUp);
}
private void OnWakeUp()
{
if (QSBNetworkServer.active)
{
QSB.HasWokenUp = true;
}
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
{
QSB.HasWokenUp = false;
if (isInUniverse)
{
Init();
}
else
{
_state = State.NotLoaded;
}
}
private void OnDestroy()
{
QSBSceneManager.OnSceneLoaded -= OnSceneLoaded;
GlobalMessenger.RemoveListener(EventNames.RestartTimeLoop, OnLoopStart);
GlobalMessenger.RemoveListener(EventNames.WakeUp, OnWakeUp);
}
private void OnLoopStart()
{
_localLoopCount++;
}
private void OnSceneLoaded(OWScene scene, bool isInUniverse)
{
QSB.HasWokenUp = (scene == OWScene.EyeOfTheUniverse);
if (isInUniverse)
{
Init();
}
else
{
_state = State.NotLoaded;
}
}
private void Init()
{
GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest);
_state = State.Loaded;
gameObject.AddComponent<PreserveTimeScale>();
if (isServer)
{
SendServerTime();
}
else
{
WakeUpOrSleep();
}
}
private void OnLoopStart()
{
_localLoopCount++;
}
private void SendServerTime()
{
GlobalMessenger<float, int>.FireEvent(EventNames.QSBServerTime, Time.timeSinceLevelLoad, _localLoopCount);
}
private void Init()
{
GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest);
_state = State.Loaded;
gameObject.AddComponent<PreserveTimeScale>();
if (IsServer)
{
SendServerTime();
}
else
{
WakeUpOrSleep();
}
}
public void OnClientReceiveMessage(ServerTimeMessage message)
{
_serverTime = message.ServerTime;
_serverLoopCount = message.LoopCount;
WakeUpOrSleep();
}
private void SendServerTime()
{
GlobalMessenger<float, int>.FireEvent(EventNames.QSBServerTime, Time.timeSinceLevelLoad, _localLoopCount);
}
private void WakeUpOrSleep()
{
if (_state == State.NotLoaded || _localLoopCount != _serverLoopCount)
{
return;
}
public void OnClientReceiveMessage(ServerTimeMessage message)
{
_serverTime = message.ServerTime;
_serverLoopCount = message.LoopCount;
WakeUpOrSleep();
}
var myTime = Time.timeSinceLevelLoad;
var diff = myTime - _serverTime;
private void WakeUpOrSleep()
{
if (_state == State.NotLoaded || _localLoopCount != _serverLoopCount)
{
return;
}
if (diff > TimeThreshold)
{
StartPausing();
return;
}
var myTime = Time.timeSinceLevelLoad;
var diff = myTime - _serverTime;
if (diff < -TimeThreshold)
{
StartFastForwarding();
}
}
if (diff > TimeThreshold)
{
StartPausing();
return;
}
private void StartFastForwarding()
{
if (_state == State.FastForwarding)
{
return;
}
_timeScale = MaxFastForwardSpeed;
_state = State.FastForwarding;
TimeSyncUI.Start(TimeSyncType.Fastforwarding);
}
if (diff < -TimeThreshold)
{
StartFastForwarding();
}
}
private void StartPausing()
{
if (_state == State.Pausing)
{
return;
}
_timeScale = 0f;
_state = State.Pausing;
SpinnerUI.Show();
TimeSyncUI.Start(TimeSyncType.Pausing);
}
private void StartFastForwarding()
{
if (_state == State.FastForwarding)
{
return;
}
_timeScale = MaxFastForwardSpeed;
_state = State.FastForwarding;
TimeSyncUI.Start(TimeSyncType.Fastforwarding);
}
private void ResetTimeScale()
{
_timeScale = 1f;
_state = State.Loaded;
private void StartPausing()
{
if (_state == State.Pausing)
{
return;
}
_timeScale = 0f;
_state = State.Pausing;
SpinnerUI.Show();
TimeSyncUI.Start(TimeSyncType.Pausing);
}
if (!_isInputEnabled)
{
EnableInput();
}
_isFirstFastForward = false;
QSB.HasWokenUp = true;
Physics.SyncTransforms();
SpinnerUI.Hide();
TimeSyncUI.Stop();
GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest);
RespawnOnDeath.Instance.Init();
}
private void ResetTimeScale()
{
_timeScale = 1f;
_state = State.Loaded;
private void DisableInput()
{
_isInputEnabled = false;
OWInput.ChangeInputMode(InputMode.None);
}
if (!_isInputEnabled)
{
EnableInput();
}
_isFirstFastForward = false;
QSB.HasWokenUp = true;
Physics.SyncTransforms();
SpinnerUI.Hide();
TimeSyncUI.Stop();
GlobalMessenger.FireEvent(EventNames.QSBPlayerStatesRequest);
RespawnOnDeath.Instance.Init();
}
private void EnableInput()
{
_isInputEnabled = true;
OWInput.ChangeInputMode(InputMode.Character);
}
private void DisableInput()
{
_isInputEnabled = false;
OWInput.ChangeInputMode(InputMode.None);
}
private void Update()
{
if (isServer)
{
UpdateServer();
}
else if (isLocalPlayer)
{
UpdateLocal();
}
}
private void EnableInput()
{
_isInputEnabled = true;
OWInput.ChangeInputMode(InputMode.Character);
}
private void UpdateServer()
{
if (_state != State.Loaded)
{
return;
}
private void Update()
{
if (IsServer)
{
UpdateServer();
}
else if (IsLocalPlayer)
{
UpdateLocal();
}
}
_sendTimer += Time.unscaledDeltaTime;
if (_sendTimer > 1)
{
SendServerTime();
_sendTimer = 0;
}
}
private void UpdateServer()
{
if (_state != State.Loaded)
{
return;
}
private void UpdateLocal()
{
_serverTime += Time.unscaledDeltaTime;
_sendTimer += Time.unscaledDeltaTime;
if (_sendTimer > 1)
{
SendServerTime();
_sendTimer = 0;
}
}
if (_state == State.NotLoaded)
{
return;
}
private void UpdateLocal()
{
_serverTime += Time.unscaledDeltaTime;
if (_state == State.FastForwarding)
{
var diff = _serverTime - Time.timeSinceLevelLoad;
Time.timeScale = Mathf.Lerp(MinFastForwardSpeed, MaxFastForwardSpeed, Mathf.Abs(diff) / MaxFastForwardDiff);
if (_state == State.NotLoaded)
{
return;
}
if (QSBSceneManager.CurrentScene == OWScene.SolarSystem && _isFirstFastForward)
{
var spawnPoint = Locator.GetPlayerBody().GetComponent<PlayerSpawner>().GetInitialSpawnPoint().transform;
Locator.GetPlayerTransform().position = spawnPoint.position;
Locator.GetPlayerTransform().rotation = spawnPoint.rotation;
Physics.SyncTransforms();
}
}
else
{
Time.timeScale = _timeScale;
}
if (_state == State.FastForwarding)
{
var diff = _serverTime - Time.timeSinceLevelLoad;
Time.timeScale = Mathf.Lerp(MinFastForwardSpeed, MaxFastForwardSpeed, Mathf.Abs(diff) / MaxFastForwardDiff);
var isDoneFastForwarding = _state == State.FastForwarding && Time.timeSinceLevelLoad >= _serverTime;
var isDonePausing = _state == State.Pausing && Time.timeSinceLevelLoad < _serverTime;
if (QSBSceneManager.CurrentScene == OWScene.SolarSystem && _isFirstFastForward)
{
var spawnPoint = Locator.GetPlayerBody().GetComponent<PlayerSpawner>().GetInitialSpawnPoint().transform;
Locator.GetPlayerTransform().position = spawnPoint.position;
Locator.GetPlayerTransform().rotation = spawnPoint.rotation;
Physics.SyncTransforms();
}
}
else
{
Time.timeScale = _timeScale;
}
if (isDoneFastForwarding || isDonePausing)
{
ResetTimeScale();
}
var isDoneFastForwarding = _state == State.FastForwarding && Time.timeSinceLevelLoad >= _serverTime;
var isDonePausing = _state == State.Pausing && Time.timeSinceLevelLoad < _serverTime;
if (!_isInputEnabled && OWInput.GetInputMode() != InputMode.None)
{
DisableInput();
}
}
}
if (isDoneFastForwarding || isDonePausing)
{
ResetTimeScale();
}
if (!_isInputEnabled && OWInput.GetInputMode() != InputMode.None)
{
DisableInput();
}
}
}
}

View File

@ -4,41 +4,42 @@ using QSB.Player;
namespace QSB.Tools.Events
{
public class PlayerFlashlightEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.FlashlightActiveChange;
public class PlayerFlashlightEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.FlashlightActiveChange;
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.TurnOnFlashlight, HandleTurnOn);
GlobalMessenger.AddListener(EventNames.TurnOffFlashlight, HandleTurnOff);
}
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.TurnOnFlashlight, HandleTurnOn);
GlobalMessenger.AddListener(EventNames.TurnOffFlashlight, HandleTurnOff);
}
public override void CloseListener()
{
GlobalMessenger.RemoveListener(EventNames.TurnOnFlashlight, HandleTurnOn);
GlobalMessenger.RemoveListener(EventNames.TurnOffFlashlight, HandleTurnOff);
}
public override void CloseListener()
{
GlobalMessenger.RemoveListener(EventNames.TurnOnFlashlight, HandleTurnOn);
GlobalMessenger.RemoveListener(EventNames.TurnOffFlashlight, HandleTurnOff);
}
private void HandleTurnOn() => SendEvent(CreateMessage(true));
private void HandleTurnOff() => SendEvent(CreateMessage(false));
private void HandleTurnOn() => SendEvent(CreateMessage(true));
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
private void HandleTurnOff() => SendEvent(CreateMessage(false));
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.Flashlight, message.ToggleValue);
player.FlashLight?.UpdateState(message.ToggleValue);
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Flashlight, message.ToggleValue);
}
}
}
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.Flashlight, message.ToggleValue);
player.FlashLight?.UpdateState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Flashlight, message.ToggleValue);
}
}
}

View File

@ -4,41 +4,42 @@ using QSB.Player;
namespace QSB.Tools.Events
{
public class PlayerProbeEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.ProbeActiveChange;
public class PlayerProbeEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.ProbeActiveChange;
public override void SetupListener()
{
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.LaunchProbe, HandleLaunch);
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.RetrieveProbe, HandleRetrieve);
}
public override void SetupListener()
{
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.LaunchProbe, HandleLaunch);
GlobalMessenger<SurveyorProbe>.AddListener(EventNames.RetrieveProbe, HandleRetrieve);
}
public override void CloseListener()
{
GlobalMessenger<SurveyorProbe>.RemoveListener(EventNames.LaunchProbe, HandleLaunch);
GlobalMessenger<SurveyorProbe>.RemoveListener(EventNames.RetrieveProbe, HandleRetrieve);
}
public override void CloseListener()
{
GlobalMessenger<SurveyorProbe>.RemoveListener(EventNames.LaunchProbe, HandleLaunch);
GlobalMessenger<SurveyorProbe>.RemoveListener(EventNames.RetrieveProbe, HandleRetrieve);
}
private void HandleLaunch(SurveyorProbe probe) => SendEvent(CreateMessage(true));
private void HandleRetrieve(SurveyorProbe probe) => SendEvent(CreateMessage(false));
private void HandleLaunch(SurveyorProbe probe) => SendEvent(CreateMessage(true));
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
private void HandleRetrieve(SurveyorProbe probe) => SendEvent(CreateMessage(false));
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.ProbeActive, message.ToggleValue);
player.Probe?.SetState(message.ToggleValue);
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.ProbeActive, message.ToggleValue);
}
}
}
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.ProbeActive, message.ToggleValue);
player.Probe?.SetState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.ProbeActive, message.ToggleValue);
}
}
}

View File

@ -4,41 +4,42 @@ using QSB.Player;
namespace QSB.Tools.Events
{
public class PlayerProbeLauncherEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.ProbeLauncherActiveChange;
public class PlayerProbeLauncherEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.ProbeLauncherActiveChange;
public override void SetupListener()
{
GlobalMessenger<ProbeLauncher>.AddListener(EventNames.ProbeLauncherEquipped, HandleEquip);
GlobalMessenger<ProbeLauncher>.AddListener(EventNames.ProbeLauncherUnequipped, HandleUnequip);
}
public override void SetupListener()
{
GlobalMessenger<ProbeLauncher>.AddListener(EventNames.ProbeLauncherEquipped, HandleEquip);
GlobalMessenger<ProbeLauncher>.AddListener(EventNames.ProbeLauncherUnequipped, HandleUnequip);
}
public override void CloseListener()
{
GlobalMessenger<ProbeLauncher>.RemoveListener(EventNames.ProbeLauncherEquipped, HandleEquip);
GlobalMessenger<ProbeLauncher>.RemoveListener(EventNames.ProbeLauncherUnequipped, HandleUnequip);
}
public override void CloseListener()
{
GlobalMessenger<ProbeLauncher>.RemoveListener(EventNames.ProbeLauncherEquipped, HandleEquip);
GlobalMessenger<ProbeLauncher>.RemoveListener(EventNames.ProbeLauncherUnequipped, HandleUnequip);
}
private void HandleEquip(ProbeLauncher var) => SendEvent(CreateMessage(true));
private void HandleUnequip(ProbeLauncher var) => SendEvent(CreateMessage(false));
private void HandleEquip(ProbeLauncher var) => SendEvent(CreateMessage(true));
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
private void HandleUnequip(ProbeLauncher var) => SendEvent(CreateMessage(false));
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.ProbeLauncher, message.ToggleValue);
player.ProbeLauncher?.ChangeEquipState(message.ToggleValue);
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.ProbeLauncher, message.ToggleValue);
}
}
}
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.ProbeLauncher, message.ToggleValue);
player.ProbeLauncher?.ChangeEquipState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.ProbeLauncher, message.ToggleValue);
}
}
}

View File

@ -4,41 +4,42 @@ using QSB.Player;
namespace QSB.Tools.Events
{
public class PlayerSignalscopeEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.SignalscopeActiveChange;
public class PlayerSignalscopeEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.SignalscopeActiveChange;
public override void SetupListener()
{
GlobalMessenger<Signalscope>.AddListener(EventNames.EquipSignalscope, HandleEquip);
GlobalMessenger.AddListener(EventNames.UnequipSignalscope, HandleUnequip);
}
public override void SetupListener()
{
GlobalMessenger<Signalscope>.AddListener(EventNames.EquipSignalscope, HandleEquip);
GlobalMessenger.AddListener(EventNames.UnequipSignalscope, HandleUnequip);
}
public override void CloseListener()
{
GlobalMessenger<Signalscope>.RemoveListener(EventNames.EquipSignalscope, HandleEquip);
GlobalMessenger.RemoveListener(EventNames.UnequipSignalscope, HandleUnequip);
}
public override void CloseListener()
{
GlobalMessenger<Signalscope>.RemoveListener(EventNames.EquipSignalscope, HandleEquip);
GlobalMessenger.RemoveListener(EventNames.UnequipSignalscope, HandleUnequip);
}
private void HandleEquip(Signalscope var) => SendEvent(CreateMessage(true));
private void HandleUnequip() => SendEvent(CreateMessage(false));
private void HandleEquip(Signalscope var) => SendEvent(CreateMessage(true));
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
private void HandleUnequip() => SendEvent(CreateMessage(false));
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.Signalscope, message.ToggleValue);
player.Signalscope?.ChangeEquipState(message.ToggleValue);
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Signalscope, message.ToggleValue);
}
}
}
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.Signalscope, message.ToggleValue);
player.Signalscope?.ChangeEquipState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Signalscope, message.ToggleValue);
}
}
}

View File

@ -4,41 +4,42 @@ using QSB.Player;
namespace QSB.Tools.Events
{
public class PlayerTranslatorEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.TranslatorActiveChange;
public class PlayerTranslatorEvent : QSBEvent<ToggleMessage>
{
public override EventType Type => EventType.TranslatorActiveChange;
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.EquipTranslator, HandleEquip);
GlobalMessenger.AddListener(EventNames.UnequipTranslator, HandleUnequip);
}
public override void SetupListener()
{
GlobalMessenger.AddListener(EventNames.EquipTranslator, HandleEquip);
GlobalMessenger.AddListener(EventNames.UnequipTranslator, HandleUnequip);
}
public override void CloseListener()
{
GlobalMessenger.RemoveListener(EventNames.EquipTranslator, HandleEquip);
GlobalMessenger.RemoveListener(EventNames.UnequipTranslator, HandleUnequip);
}
public override void CloseListener()
{
GlobalMessenger.RemoveListener(EventNames.EquipTranslator, HandleEquip);
GlobalMessenger.RemoveListener(EventNames.UnequipTranslator, HandleUnequip);
}
private void HandleEquip() => SendEvent(CreateMessage(true));
private void HandleUnequip() => SendEvent(CreateMessage(false));
private void HandleEquip() => SendEvent(CreateMessage(true));
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
private void HandleUnequip() => SendEvent(CreateMessage(false));
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.Translator, message.ToggleValue);
player.Translator?.ChangeEquipState(message.ToggleValue);
}
private ToggleMessage CreateMessage(bool value) => new ToggleMessage
{
AboutId = LocalPlayerId,
ToggleValue = value
};
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Translator, message.ToggleValue);
}
}
}
public override void OnReceiveRemote(ToggleMessage message)
{
var player = QSBPlayerManager.GetPlayer(message.AboutId);
player.UpdateState(State.Translator, message.ToggleValue);
player.Translator?.ChangeEquipState(message.ToggleValue);
}
public override void OnReceiveLocal(ToggleMessage message)
{
QSBPlayerManager.LocalPlayer.UpdateState(State.Translator, message.ToggleValue);
}
}
}

View File

@ -6,182 +6,189 @@ using UnityEngine;
namespace QSB.Tools
{
public class PlayerToolsManager
{
private static Transform _toolStowTransform;
private static Transform _toolHoldTransform;
private static Material _playerToolsMaterial;
private static Material _lightbulbMaterial;
public class PlayerToolsManager
{
private static Transform _toolStowTransform;
private static Transform _toolHoldTransform;
private static Material _playerToolsMaterial;
private static Material _lightbulbMaterial;
private static readonly Vector3 FlashlightOffset = new Vector3(0.7196316f, -0.2697681f, 0.3769455f);
private static readonly Vector3 ProbeLauncherOffset = new Vector3(0.5745087f, -0.26f, 0.4453125f);
private static readonly Vector3 SignalscopeScale = new Vector3(1.5f, 1.5f, 1.5f);
private static readonly Vector3 TranslatorScale = new Vector3(0.75f, 0.75f, 0.75f);
private static readonly Vector3 FlashlightOffset = new Vector3(0.7196316f, -0.2697681f, 0.3769455f);
private static readonly Vector3 ProbeLauncherOffset = new Vector3(0.5745087f, -0.26f, 0.4453125f);
private static readonly Vector3 SignalscopeScale = new Vector3(1.5f, 1.5f, 1.5f);
private static readonly Vector3 TranslatorScale = new Vector3(0.75f, 0.75f, 0.75f);
public static void Init(Transform camera)
{
CreateStowTransforms(camera);
public static void Init(Transform camera)
{
CreateStowTransforms(camera);
_playerToolsMaterial = GameObject.Find("PlayerSuit_Jetpack").GetComponent<MeshRenderer>().materials[0];
_lightbulbMaterial = GameObject.Find("Props_HEA_Lantern (10)/Lantern_Lamp").GetComponent<MeshRenderer>().materials[0];
_playerToolsMaterial = GameObject.Find("Props_HEA_ProbeLauncher_ProbeCamera/ProbeLauncherChassis").GetComponent<MeshRenderer>().materials[0];
if (QSBSceneManager.CurrentScene == OWScene.SolarSystem)
{
_lightbulbMaterial = GameObject.Find("Props_HEA_Lantern (10)/Lantern_Lamp").GetComponent<MeshRenderer>().materials[0];
}
else if (QSBSceneManager.CurrentScene == OWScene.EyeOfTheUniverse)
{
_lightbulbMaterial = GameObject.Find("lantern_lamp").GetComponent<MeshRenderer>().materials[0];
}
CreateFlashlight(camera);
CreateSignalscope(camera);
CreateProbeLauncher(camera);
CreateTranslator(camera);
}
CreateFlashlight(camera);
CreateSignalscope(camera);
CreateProbeLauncher(camera);
CreateTranslator(camera);
}
public static void CreateProbe(Transform body, PlayerInfo player)
{
var newProbe = body.gameObject.AddComponent<QSBProbe>();
player.Probe = newProbe;
}
public static void CreateProbe(Transform body, PlayerInfo player)
{
var newProbe = body.gameObject.AddComponent<QSBProbe>();
player.Probe = newProbe;
}
private static void CreateStowTransforms(Transform cameraBody)
{
var stow = new GameObject("ToolStowTransform");
_toolStowTransform = stow.transform;
stow.transform.parent = cameraBody;
stow.transform.localPosition = Vector3.zero;
stow.transform.localRotation = Quaternion.Euler(45f, 0f, 0f);
private static void CreateStowTransforms(Transform cameraBody)
{
var stow = new GameObject("ToolStowTransform");
_toolStowTransform = stow.transform;
stow.transform.parent = cameraBody;
stow.transform.localPosition = Vector3.zero;
stow.transform.localRotation = Quaternion.Euler(45f, 0f, 0f);
var hold = new GameObject("ToolHoldTransform");
_toolHoldTransform = hold.transform;
hold.transform.parent = cameraBody;
hold.transform.localPosition = Vector3.zero;
hold.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
}
var hold = new GameObject("ToolHoldTransform");
_toolHoldTransform = hold.transform;
hold.transform.parent = cameraBody;
hold.transform.localPosition = Vector3.zero;
hold.transform.localRotation = Quaternion.Euler(0f, 0f, 0f);
}
private static GameObject CreateFlashlight(Transform cameraBody)
{
var flashlightRoot = Object.Instantiate(GameObject.Find("FlashlightRoot"));
flashlightRoot.SetActive(false);
var oldComponent = flashlightRoot.GetComponent<Flashlight>();
var component = flashlightRoot.AddComponent<QSBFlashlight>();
private static GameObject CreateFlashlight(Transform cameraBody)
{
var flashlightRoot = Object.Instantiate(GameObject.Find("FlashlightRoot"));
flashlightRoot.SetActive(false);
var oldComponent = flashlightRoot.GetComponent<Flashlight>();
var component = flashlightRoot.AddComponent<QSBFlashlight>();
component.Init(oldComponent);
oldComponent.enabled = false;
component.Init(oldComponent);
oldComponent.enabled = false;
flashlightRoot.transform.parent = cameraBody;
flashlightRoot.transform.localPosition = FlashlightOffset;
flashlightRoot.SetActive(true);
flashlightRoot.transform.parent = cameraBody;
flashlightRoot.transform.localPosition = FlashlightOffset;
flashlightRoot.SetActive(true);
return flashlightRoot;
}
return flashlightRoot;
}
private static GameObject CreateSignalscope(Transform cameraBody)
{
var signalscopeRoot = Object.Instantiate(GameObject.Find("Signalscope"));
signalscopeRoot.SetActive(false);
private static GameObject CreateSignalscope(Transform cameraBody)
{
var signalscopeRoot = Object.Instantiate(GameObject.Find("Signalscope"));
signalscopeRoot.SetActive(false);
Object.Destroy(signalscopeRoot.GetComponent<SignalscopePromptController>());
Object.Destroy(signalscopeRoot.transform.Find("Props_HEA_Signalscope")
.Find("Props_HEA_Signalscope_Prepass").gameObject);
Object.Destroy(signalscopeRoot.GetComponent<SignalscopePromptController>());
Object.Destroy(signalscopeRoot.transform.Find("Props_HEA_Signalscope")
.Find("Props_HEA_Signalscope_Prepass").gameObject);
var oldSignalscope = signalscopeRoot.GetComponent<Signalscope>();
var tool = signalscopeRoot.AddComponent<QSBTool>();
tool.MoveSpring = oldSignalscope.GetValue<DampedSpringQuat>("_moveSpring");
tool.StowTransform = _toolStowTransform;
tool.HoldTransform = _toolHoldTransform;
tool.ArrivalDegrees = 5f;
tool.Type = ToolType.Signalscope;
tool.ToolGameObject = signalscopeRoot.transform.Find("Props_HEA_Signalscope").gameObject;
oldSignalscope.enabled = false;
var oldSignalscope = signalscopeRoot.GetComponent<Signalscope>();
var tool = signalscopeRoot.AddComponent<QSBTool>();
tool.MoveSpring = oldSignalscope.GetValue<DampedSpringQuat>("_moveSpring");
tool.StowTransform = _toolStowTransform;
tool.HoldTransform = _toolHoldTransform;
tool.ArrivalDegrees = 5f;
tool.Type = ToolType.Signalscope;
tool.ToolGameObject = signalscopeRoot.transform.Find("Props_HEA_Signalscope").gameObject;
oldSignalscope.enabled = false;
GetRenderer(signalscopeRoot, "Props_HEA_Signalscope").material = _playerToolsMaterial;
GetRenderer(signalscopeRoot, "Props_HEA_Signalscope").material = _playerToolsMaterial;
signalscopeRoot.transform.parent = cameraBody;
signalscopeRoot.transform.localPosition = Vector3.zero;
signalscopeRoot.transform.localScale = SignalscopeScale;
signalscopeRoot.SetActive(true);
signalscopeRoot.transform.parent = cameraBody;
signalscopeRoot.transform.localPosition = Vector3.zero;
signalscopeRoot.transform.localScale = SignalscopeScale;
signalscopeRoot.SetActive(true);
return signalscopeRoot;
}
return signalscopeRoot;
}
private static GameObject CreateTranslator(Transform cameraBody)
{
var original = GameObject.Find("NomaiTranslatorProp");
private static GameObject CreateTranslator(Transform cameraBody)
{
var original = GameObject.Find("NomaiTranslatorProp");
var translatorRoot = original.InstantiateInactive();
var translatorRoot = original.InstantiateInactive();
var group = translatorRoot.transform.Find("TranslatorGroup");
var model = group.Find("Props_HEA_Translator");
var group = translatorRoot.transform.Find("TranslatorGroup");
var model = group.Find("Props_HEA_Translator");
Object.Destroy(translatorRoot.GetComponent<NomaiTranslatorProp>());
Object.Destroy(group.Find("Canvas").gameObject);
Object.Destroy(group.Find("Lighting").gameObject);
Object.Destroy(group.Find("TranslatorBeams").gameObject);
Object.Destroy(model.Find("Props_HEA_Translator_Pivot_RotatingPart")
.Find("Props_HEA_Translator_RotatingPart")
.Find("Props_HEA_Translator_RotatingPart_Prepass").gameObject);
Object.Destroy(model.Find("Props_HEA_Translator_Prepass").gameObject);
Object.Destroy(translatorRoot.GetComponent<NomaiTranslatorProp>());
Object.Destroy(group.Find("Canvas").gameObject);
Object.Destroy(group.Find("Lighting").gameObject);
Object.Destroy(group.Find("TranslatorBeams").gameObject);
Object.Destroy(model.Find("Props_HEA_Translator_Pivot_RotatingPart")
.Find("Props_HEA_Translator_RotatingPart")
.Find("Props_HEA_Translator_RotatingPart_Prepass").gameObject);
Object.Destroy(model.Find("Props_HEA_Translator_Prepass").gameObject);
var oldTranslator = translatorRoot.GetComponent<NomaiTranslator>();
var tool = translatorRoot.AddComponent<QSBTool>();
tool.MoveSpring = oldTranslator.GetValue<DampedSpringQuat>("_moveSpring");
tool.StowTransform = _toolStowTransform;
tool.HoldTransform = _toolHoldTransform;
tool.ArrivalDegrees = 5f;
tool.Type = ToolType.Translator;
tool.ToolGameObject = group.gameObject;
Object.Destroy(oldTranslator);
var oldTranslator = translatorRoot.GetComponent<NomaiTranslator>();
var tool = translatorRoot.AddComponent<QSBTool>();
tool.MoveSpring = oldTranslator.GetValue<DampedSpringQuat>("_moveSpring");
tool.StowTransform = _toolStowTransform;
tool.HoldTransform = _toolHoldTransform;
tool.ArrivalDegrees = 5f;
tool.Type = ToolType.Translator;
tool.ToolGameObject = group.gameObject;
Object.Destroy(oldTranslator);
GetRenderer(translatorRoot, "Props_HEA_Translator_Geo").material = _playerToolsMaterial;
GetRenderer(translatorRoot, "Props_HEA_Translator_RotatingPart").material = _playerToolsMaterial;
GetRenderer(translatorRoot, "Props_HEA_Translator_Button_L").material = _lightbulbMaterial;
GetRenderer(translatorRoot, "Props_HEA_Translator_Button_R").material = _lightbulbMaterial;
GetRenderer(translatorRoot, "Props_HEA_Translator_Geo").material = _playerToolsMaterial;
GetRenderer(translatorRoot, "Props_HEA_Translator_RotatingPart").material = _playerToolsMaterial;
GetRenderer(translatorRoot, "Props_HEA_Translator_Button_L").material = _lightbulbMaterial;
GetRenderer(translatorRoot, "Props_HEA_Translator_Button_R").material = _lightbulbMaterial;
translatorRoot.transform.parent = cameraBody;
translatorRoot.transform.localPosition = Vector3.zero;
translatorRoot.transform.localScale = TranslatorScale;
QSB.Helper.Events.Unity.FireOnNextUpdate(() => translatorRoot.SetActive(true));
translatorRoot.transform.parent = cameraBody;
translatorRoot.transform.localPosition = Vector3.zero;
translatorRoot.transform.localScale = TranslatorScale;
QSB.Helper.Events.Unity.FireOnNextUpdate(() => translatorRoot.SetActive(true));
return translatorRoot;
}
return translatorRoot;
}
private static GameObject CreateProbeLauncher(Transform cameraBody)
{
var launcherRoot = new GameObject("ProbeLauncher");
var modelOrig = GameObject.Find("PlayerCamera/ProbeLauncher/Props_HEA_ProbeLauncher");
var model = Object.Instantiate(modelOrig);
model.transform.parent = launcherRoot.transform;
private static GameObject CreateProbeLauncher(Transform cameraBody)
{
var launcherRoot = new GameObject("ProbeLauncher");
var modelOrig = GameObject.Find("PlayerCamera/ProbeLauncher/Props_HEA_ProbeLauncher");
var model = Object.Instantiate(modelOrig);
model.transform.parent = launcherRoot.transform;
Object.Destroy(model.transform.Find("Props_HEA_ProbeLauncher_Prepass").gameObject);
Object.Destroy(model.transform.Find("Props_HEA_Probe_Prelaunch").Find("Props_HEA_Probe_Prelaunch_Prepass").gameObject);
Object.Destroy(model.transform.Find("Props_HEA_ProbeLauncher_Prepass").gameObject);
Object.Destroy(model.transform.Find("Props_HEA_Probe_Prelaunch").Find("Props_HEA_Probe_Prelaunch_Prepass").gameObject);
var tool = launcherRoot.AddComponent<QSBTool>();
var spring = new DampedSpringQuat
{
velocity = Vector4.zero,
settings = new DampedSpringSettings
{
springConstant = 50f,
dampingCoefficient = 8.485282f,
mass = 1
}
};
tool.MoveSpring = spring;
tool.StowTransform = _toolStowTransform;
tool.HoldTransform = _toolHoldTransform;
tool.ArrivalDegrees = 5f;
tool.Type = ToolType.ProbeLauncher;
tool.ToolGameObject = model;
var tool = launcherRoot.AddComponent<QSBTool>();
var spring = new DampedSpringQuat
{
velocity = Vector4.zero,
settings = new DampedSpringSettings
{
springConstant = 50f,
dampingCoefficient = 8.485282f,
mass = 1
}
};
tool.MoveSpring = spring;
tool.StowTransform = _toolStowTransform;
tool.HoldTransform = _toolHoldTransform;
tool.ArrivalDegrees = 5f;
tool.Type = ToolType.ProbeLauncher;
tool.ToolGameObject = model;
GetRenderer(launcherRoot, "Props_HEA_Probe_Prelaunch").materials[0] = _playerToolsMaterial;
GetRenderer(launcherRoot, "Props_HEA_Probe_Prelaunch").materials[1] = _lightbulbMaterial;
GetRenderer(launcherRoot, "PressureGauge_Arrow").material = _playerToolsMaterial;
GetRenderer(launcherRoot, "ProbeLauncherChassis").material = _playerToolsMaterial;
GetRenderer(launcherRoot, "Props_HEA_Probe_Prelaunch").materials[0] = _playerToolsMaterial;
GetRenderer(launcherRoot, "Props_HEA_Probe_Prelaunch").materials[1] = _lightbulbMaterial;
GetRenderer(launcherRoot, "PressureGauge_Arrow").material = _playerToolsMaterial;
GetRenderer(launcherRoot, "ProbeLauncherChassis").material = _playerToolsMaterial;
launcherRoot.transform.parent = cameraBody;
launcherRoot.transform.localPosition = ProbeLauncherOffset;
launcherRoot.SetActive(true);
launcherRoot.transform.parent = cameraBody;
launcherRoot.transform.localPosition = ProbeLauncherOffset;
launcherRoot.SetActive(true);
return launcherRoot;
}
return launcherRoot;
}
private static MeshRenderer GetRenderer(GameObject root, string gameObjectName)
{
return root.GetComponentsInChildren<MeshRenderer>(true).First(x => x.name == gameObjectName);
}
}
private static MeshRenderer GetRenderer(GameObject root, string gameObjectName)
{
return root.GetComponentsInChildren<MeshRenderer>(true).First(x => x.name == gameObjectName);
}
}
}

View File

@ -2,28 +2,28 @@
namespace QSB.Tools
{
public class ProbePatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
public class ProbePatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnModStart;
private static void ProbeAnchor()
{
GlobalMessenger.FireEvent(EventNames.QSBOnProbeAnchor);
}
private static void ProbeAnchor()
{
GlobalMessenger.FireEvent(EventNames.QSBOnProbeAnchor);
}
private static bool ProbeWarp(ref bool ____isRetrieving)
{
if (!____isRetrieving)
{
GlobalMessenger.FireEvent(EventNames.QSBOnProbeWarp);
}
return true;
}
private static bool ProbeWarp(ref bool ____isRetrieving)
{
if (!____isRetrieving)
{
GlobalMessenger.FireEvent(EventNames.QSBOnProbeWarp);
}
return true;
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<SurveyorProbe>("OnAnchor", typeof(ProbePatches), nameof(ProbeAnchor));
QSB.Helper.HarmonyHelper.AddPrefix<SurveyorProbe>("Retrieve", typeof(ProbePatches), nameof(ProbeWarp));
}
}
}
public override void DoPatches()
{
QSB.Helper.HarmonyHelper.AddPostfix<SurveyorProbe>("OnAnchor", typeof(ProbePatches), nameof(ProbeAnchor));
QSB.Helper.HarmonyHelper.AddPrefix<SurveyorProbe>("Retrieve", typeof(ProbePatches), nameof(ProbeWarp));
}
}
}

View File

@ -3,82 +3,90 @@ using UnityEngine;
namespace QSB.Tools
{
public class QSBFlashlight : MonoBehaviour
{
private OWLight2[] _lights;
private Transform _root;
private Transform _basePivot;
private Transform _wobblePivot;
public class QSBFlashlight : MonoBehaviour
{
private OWLight2[] _lights;
private Transform _root;
private Transform _basePivot;
private Transform _wobblePivot;
private bool _flashlightOn;
private Vector3 _baseForward;
private Quaternion _baseRotation;
private bool _flashlightOn;
private Vector3 _baseForward;
private Quaternion _baseRotation;
private void Start()
{
_baseForward = _basePivot.forward;
_baseRotation = _basePivot.rotation;
}
private void Start()
{
_baseForward = _basePivot.forward;
_baseRotation = _basePivot.rotation;
}
public void Init(Flashlight oldComponent)
{
_lights = oldComponent.GetValue<OWLight2[]>("_lights");
_root = oldComponent.GetValue<Transform>("_root");
_basePivot = oldComponent.GetValue<Transform>("_basePivot");
_wobblePivot = oldComponent.GetValue<Transform>("_wobblePivot");
}
public void Init(Flashlight oldComponent)
{
_lights = oldComponent.GetValue<OWLight2[]>("_lights");
_root = oldComponent.GetValue<Transform>("_root");
_basePivot = oldComponent.GetValue<Transform>("_basePivot");
_wobblePivot = oldComponent.GetValue<Transform>("_wobblePivot");
Destroy(oldComponent.GetComponent<LightLOD>());
public void UpdateState(bool value)
{
if (value)
{
TurnOn();
}
else
{
TurnOff();
}
}
foreach (var light in _lights)
{
light.GetLight().enabled = false;
light.GetLight().shadows = LightShadows.Soft;
}
_flashlightOn = false;
}
private void TurnOn()
{
if (_flashlightOn)
{
return;
}
foreach (var light in _lights)
{
light.GetLight().enabled = true;
}
_flashlightOn = true;
var rotation = _root.rotation;
_basePivot.rotation = rotation;
_baseRotation = rotation;
_baseForward = _basePivot.forward;
}
public void UpdateState(bool value)
{
if (value)
{
TurnOn();
}
else
{
TurnOff();
}
}
private void TurnOff()
{
if (!_flashlightOn)
{
return;
}
foreach (var light in _lights)
{
light.GetLight().enabled = false;
}
_flashlightOn = false;
}
private void TurnOn()
{
if (_flashlightOn)
{
return;
}
foreach (var light in _lights)
{
light.GetLight().enabled = true;
}
_flashlightOn = true;
var rotation = _root.rotation;
_basePivot.rotation = rotation;
_baseRotation = rotation;
_baseForward = _basePivot.forward;
}
private void FixedUpdate()
{
// This really isn't needed... but it makes it look that extra bit nicer.
var lhs = Quaternion.FromToRotation(_basePivot.up, _root.up) * Quaternion.FromToRotation(_baseForward, _root.forward);
var b = lhs * _baseRotation;
_baseRotation = Quaternion.Slerp(_baseRotation, b, 6f * Time.deltaTime);
_basePivot.rotation = _baseRotation;
_baseForward = _basePivot.forward;
_wobblePivot.localRotation = OWUtilities.GetWobbleRotation(0.3f, 0.15f) * Quaternion.identity;
}
}
}
private void TurnOff()
{
if (!_flashlightOn)
{
return;
}
foreach (var light in _lights)
{
light.GetLight().enabled = false;
}
_flashlightOn = false;
}
private void FixedUpdate()
{
// This really isn't needed... but it makes it look that extra bit nicer.
var lhs = Quaternion.FromToRotation(_basePivot.up, _root.up) * Quaternion.FromToRotation(_baseForward, _root.forward);
var b = lhs * _baseRotation;
_baseRotation = Quaternion.Slerp(_baseRotation, b, 6f * Time.deltaTime);
_basePivot.rotation = _baseRotation;
_baseForward = _basePivot.forward;
_wobblePivot.localRotation = OWUtilities.GetWobbleRotation(0.3f, 0.15f) * Quaternion.identity;
}
}
}

View File

@ -3,29 +3,29 @@ using UnityEngine;
namespace QSB.Tools
{
public class QSBProbe : MonoBehaviour
{
public void SetState(bool state)
{
if (state)
{
Activate();
}
else
{
Deactivate();
}
}
public class QSBProbe : MonoBehaviour
{
public void SetState(bool state)
{
if (state)
{
Activate();
}
else
{
Deactivate();
}
}
private void Activate()
{
gameObject.SetActive(true);
gameObject.Show();
}
private void Activate()
{
gameObject.SetActive(true);
gameObject.Show();
}
private void Deactivate()
{
gameObject.Hide();
}
}
}
private void Deactivate()
{
gameObject.Hide();
}
}
}

View File

@ -2,55 +2,55 @@
namespace QSB.Tools
{
public class QSBTool : PlayerTool
{
public ToolType Type { get; set; }
public GameObject ToolGameObject { get; set; }
public class QSBTool : PlayerTool
{
public ToolType Type { get; set; }
public GameObject ToolGameObject { get; set; }
public DampedSpringQuat MoveSpring
{
get => _moveSpring;
set => _moveSpring = value;
}
public DampedSpringQuat MoveSpring
{
get => _moveSpring;
set => _moveSpring = value;
}
public Transform StowTransform
{
get => _stowTransform;
set => _stowTransform = value;
}
public Transform StowTransform
{
get => _stowTransform;
set => _stowTransform = value;
}
public Transform HoldTransform
{
get => _holdTransform;
set => _holdTransform = value;
}
public Transform HoldTransform
{
get => _holdTransform;
set => _holdTransform = value;
}
public float ArrivalDegrees
{
get => _arrivalDegrees;
set => _arrivalDegrees = value;
}
public float ArrivalDegrees
{
get => _arrivalDegrees;
set => _arrivalDegrees = value;
}
private void OnEnable()
{
ToolGameObject?.SetActive(true);
}
private void OnEnable()
{
ToolGameObject?.SetActive(true);
}
private void OnDisable()
{
ToolGameObject?.SetActive(false);
}
private void OnDisable()
{
ToolGameObject?.SetActive(false);
}
public void ChangeEquipState(bool equipState)
{
if (equipState)
{
EquipTool();
}
else
{
UnequipTool();
}
}
}
public void ChangeEquipState(bool equipState)
{
if (equipState)
{
EquipTool();
}
else
{
UnequipTool();
}
}
}
}

View File

@ -1,9 +1,9 @@
namespace QSB.Tools
{
public enum ToolType
{
Signalscope,
ProbeLauncher,
Translator
}
public enum ToolType
{
Signalscope,
ProbeLauncher,
Translator
}
}

Some files were not shown because too many files have changed in this diff Show More