Merge pull request #452 from misternebula/better-trigger

Better trigger
This commit is contained in:
_nebula 2022-01-13 11:51:50 +00:00 committed by GitHub
commit f2a35583ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 467 additions and 517 deletions

View File

@ -6,7 +6,7 @@ using QSB.ConversationSync;
using QSB.Messaging; using QSB.Messaging;
using QSB.Patches; using QSB.Patches;
using QSB.Player; using QSB.Player;
using QSB.Player.Messages; using QSB.TriggerSync.WorldObjects;
using QSB.Utility; using QSB.Utility;
using QSB.WorldSync; using QSB.WorldSync;
using System.Linq; using System.Linq;
@ -31,7 +31,7 @@ namespace QSB.Animation.NPC.Patches
var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(__instance._dialogueTree); var playerId = ConversationManager.Instance.GetPlayerTalkingToTree(__instance._dialogueTree);
var player = QSBPlayerManager.GetPlayer(playerId); var player = QSBPlayerManager.GetPlayer(playerId);
var qsbObj = __instance.GetWorldObject<QSBCharacterAnimController>(); // OPTIMIZE : maybe cache this somewhere... or assess how slow this is var qsbObj = __instance.playerTrackingZone.GetWorldObject<QSBCharacterTrigger>(); // OPTIMIZE : maybe cache this somewhere... or assess how slow this is
PlayerInfo playerToUse = null; PlayerInfo playerToUse = null;
if (__instance._inConversation) if (__instance._inConversation)
@ -48,9 +48,9 @@ namespace QSB.Animation.NPC.Patches
: player; : player;
} }
} }
else if (!__instance.lookOnlyWhenTalking && qsbObj.GetPlayersInHeadZone().Count != 0) // IDEA : maybe this would be more fun if characters looked between players at random times? :P else if (!__instance.lookOnlyWhenTalking && qsbObj.Occupants.Count != 0) // IDEA : maybe this would be more fun if characters looked between players at random times? :P
{ {
playerToUse = QSBPlayerManager.GetClosestPlayerToWorldPoint(qsbObj.GetPlayersInHeadZone(), __instance.transform.position); playerToUse = QSBPlayerManager.GetClosestPlayerToWorldPoint(qsbObj.Occupants, __instance.transform.position);
} }
else if (QSBPlayerManager.PlayerList.Count != 0) else if (QSBPlayerManager.PlayerList.Count != 0)
{ {
@ -65,16 +65,16 @@ namespace QSB.Animation.NPC.Patches
if (__instance.lookOnlyWhenTalking) if (__instance.lookOnlyWhenTalking)
{ {
if (!__instance._inConversation if (!__instance._inConversation
|| qsbObj.GetPlayersInHeadZone().Count == 0 || qsbObj.Occupants.Count == 0
|| !qsbObj.GetPlayersInHeadZone().Contains(playerToUse)) || !qsbObj.Occupants.Contains(playerToUse))
{ {
targetWeight *= 0; targetWeight *= 0;
} }
} }
else else
{ {
if (qsbObj.GetPlayersInHeadZone().Count == 0 if (qsbObj.Occupants.Count == 0
|| !qsbObj.GetPlayersInHeadZone().Contains(playerToUse)) || !qsbObj.Occupants.Contains(playerToUse))
{ {
targetWeight *= 0; targetWeight *= 0;
} }
@ -88,32 +88,6 @@ namespace QSB.Animation.NPC.Patches
} }
[HarmonyPrefix]
[HarmonyPatch(typeof(CharacterAnimController), nameof(CharacterAnimController.OnZoneExit))]
public static bool HeadZoneExit(CharacterAnimController __instance, GameObject input)
{
if (input.CompareTag("PlayerDetector"))
{
var qsbObj = __instance.GetWorldObject<QSBCharacterAnimController>();
new EnterLeaveMessage(EnterLeaveType.ExitNonNomaiHeadZone, qsbObj.ObjectId).Send();
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(CharacterAnimController), nameof(CharacterAnimController.OnZoneEntry))]
public static bool HeadZoneEntry(CharacterAnimController __instance, GameObject input)
{
if (input.CompareTag("PlayerDetector"))
{
var qsbObj = __instance.GetWorldObject<QSBCharacterAnimController>();
new EnterLeaveMessage(EnterLeaveType.EnterNonNomaiHeadZone, qsbObj.ObjectId).Send();
}
return false;
}
[HarmonyPrefix] [HarmonyPrefix]
[HarmonyPatch(typeof(FacePlayerWhenTalking), nameof(FacePlayerWhenTalking.OnStartConversation))] [HarmonyPatch(typeof(FacePlayerWhenTalking), nameof(FacePlayerWhenTalking.OnStartConversation))]
public static bool OnStartConversation(FacePlayerWhenTalking __instance) public static bool OnStartConversation(FacePlayerWhenTalking __instance)

View File

@ -1,9 +1,7 @@
using HarmonyLib; using HarmonyLib;
using QSB.Animation.NPC.WorldObjects; using QSB.Animation.NPC.WorldObjects;
using QSB.Messaging;
using QSB.Patches; using QSB.Patches;
using QSB.Player; using QSB.Player;
using QSB.Player.Messages;
using QSB.WorldSync; using QSB.WorldSync;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
@ -26,7 +24,7 @@ namespace QSB.Animation.NPC.Patches
} }
var qsbObj = __instance.GetWorldObject<QSBSolanumAnimController>(); var qsbObj = __instance.GetWorldObject<QSBSolanumAnimController>();
var playersInHeadZone = qsbObj.GetPlayersInHeadZone(); var playersInHeadZone = qsbObj.Trigger.Occupants;
var targetCamera = playersInHeadZone == null || playersInHeadZone.Count == 0 var targetCamera = playersInHeadZone == null || playersInHeadZone.Count == 0
? __instance._playerCameraTransform ? __instance._playerCameraTransform
@ -41,38 +39,12 @@ namespace QSB.Animation.NPC.Patches
return false; return false;
} }
[HarmonyPrefix]
[HarmonyPatch(typeof(NomaiConversationManager), nameof(NomaiConversationManager.OnEnterWatchVolume))]
public static bool EnterWatchZone(NomaiConversationManager __instance, GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
var qsbObj = __instance._solanumAnimController.GetWorldObject<QSBSolanumAnimController>();
new EnterLeaveMessage(EnterLeaveType.EnterNomaiHeadZone, qsbObj.ObjectId).Send();
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(NomaiConversationManager), nameof(NomaiConversationManager.OnExitWatchVolume))]
public static bool ExitWatchZone(NomaiConversationManager __instance, GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
var qsbObj = __instance._solanumAnimController.GetWorldObject<QSBSolanumAnimController>();
new EnterLeaveMessage(EnterLeaveType.ExitNomaiHeadZone, qsbObj.ObjectId).Send();
}
return false;
}
[HarmonyPrefix] [HarmonyPrefix]
[HarmonyPatch(typeof(NomaiConversationManager), nameof(NomaiConversationManager.Update))] [HarmonyPatch(typeof(NomaiConversationManager), nameof(NomaiConversationManager.Update))]
public static bool ReplacementUpdate(NomaiConversationManager __instance) public static bool ReplacementUpdate(NomaiConversationManager __instance)
{ {
var qsbObj = __instance._solanumAnimController.GetWorldObject<QSBSolanumAnimController>(); var qsbObj = __instance._solanumAnimController.GetWorldObject<QSBSolanumAnimController>();
__instance._playerInWatchVolume = qsbObj.GetPlayersInHeadZone().Any(); __instance._playerInWatchVolume = qsbObj.Trigger.Occupants.Any();
if (!__instance._initialized) if (!__instance._initialized)
{ {

View File

@ -1,35 +1,7 @@
using QSB.Player; namespace QSB.Animation.NPC.WorldObjects
using System.Collections.Generic;
namespace QSB.Animation.NPC.WorldObjects
{ {
internal class QSBCharacterAnimController : NpcAnimController<CharacterAnimController> internal class QSBCharacterAnimController : NpcAnimController<CharacterAnimController>
{ {
private readonly List<PlayerInfo> _playersInHeadZone = new();
public List<PlayerInfo> GetPlayersInHeadZone()
=> _playersInHeadZone;
public void AddPlayerToHeadZone(PlayerInfo player)
{
if (_playersInHeadZone.Contains(player))
{
return;
}
_playersInHeadZone.Add(player);
}
public void RemovePlayerFromHeadZone(PlayerInfo player)
{
if (!_playersInHeadZone.Contains(player))
{
return;
}
_playersInHeadZone.Remove(player);
}
public override CharacterDialogueTree GetDialogueTree() public override CharacterDialogueTree GetDialogueTree()
=> AttachedObject._dialogueTree; => AttachedObject._dialogueTree;

View File

@ -1,34 +1,12 @@
using QSB.Player; using QSB.TriggerSync.WorldObjects;
using QSB.WorldSync; using QSB.WorldSync;
using System.Collections.Generic; using System.Linq;
namespace QSB.Animation.NPC.WorldObjects namespace QSB.Animation.NPC.WorldObjects
{ {
internal class QSBSolanumAnimController : WorldObject<SolanumAnimController> internal class QSBSolanumAnimController : WorldObject<SolanumAnimController>
{ {
private readonly List<PlayerInfo> _playersInHeadZone = new(); private QSBSolanumTrigger _trigger;
public QSBSolanumTrigger Trigger => _trigger ??= QSBWorldSync.GetWorldObjects<QSBSolanumTrigger>().Single();
public List<PlayerInfo> GetPlayersInHeadZone()
=> _playersInHeadZone;
public void AddPlayerToHeadZone(PlayerInfo player)
{
if (_playersInHeadZone.Contains(player))
{
return;
}
_playersInHeadZone.Add(player);
}
public void RemovePlayerFromHeadZone(PlayerInfo player)
{
if (!_playersInHeadZone.Contains(player))
{
return;
}
_playersInHeadZone.Remove(player);
}
} }
} }

View File

@ -1,127 +0,0 @@
using QSB.Messaging;
using QSB.Player;
using QSB.Player.Messages;
using QSB.Utility;
using QSB.WorldSync;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.EyeOfTheUniverse.CosmicInflation
{
internal class InflationManager : WorldObjectManager
{
public static InflationManager Instance { get; private set; }
private readonly List<PlayerInfo> _playersInFog = new();
private CosmicInflationController _controller;
public override WorldObjectType WorldObjectType => WorldObjectType.Eye;
public override void Awake()
{
base.Awake();
Instance = this;
QSBPlayerManager.OnRemovePlayer += OnPlayerLeave;
}
private void OnPlayerLeave(PlayerInfo player)
{
_playersInFog.Remove(player);
// wait 1 frame for player to be removed
QSBCore.UnityEvents.FireOnNextUpdate(() =>
{
if (QSBCore.IsInMultiplayer && _playersInFog.Count == QSBPlayerManager.PlayerList.Count)
{
StartCollapse();
}
});
}
protected override void RebuildWorldObjects(OWScene scene)
{
_playersInFog.Clear();
if (_controller != null)
{
_controller._smokeSphereTrigger.OnEntry -= OnEntry;
}
_controller = QSBWorldSync.GetUnityObjects<CosmicInflationController>().First();
_controller._smokeSphereTrigger.OnEntry -= _controller.OnEnterFogSphere;
_controller._smokeSphereTrigger.OnEntry += OnEntry;
}
private void OnEntry(GameObject hitObj)
{
if (hitObj.CompareTag("PlayerCameraDetector") && _controller._state == CosmicInflationController.State.ReadyToCollapse)
{
_controller._smokeSphereTrigger.SetTriggerActivation(false);
_controller._probeDestroyTrigger.SetTriggerActivation(false);
new EnterLeaveMessage(EnterLeaveType.EnterCosmicFog).Send();
DebugLog.DebugWrite("disable input, wait for other players to enter");
var repelVolume = (WhiteHoleFluidVolume)_controller._repelVolume;
repelVolume._flowSpeed = -repelVolume._flowSpeed;
repelVolume._massiveFlowSpeed = -repelVolume._massiveFlowSpeed;
repelVolume.SetVolumeActivation(true);
QSBPlayerManager.HideAllPlayers();
ReticleController.Hide();
Locator.GetFlashlight().TurnOff(false);
Locator.GetPromptManager().SetPromptsVisible(false);
OWInput.ChangeInputMode(InputMode.None);
}
}
public void Enter(PlayerInfo player)
{
_playersInFog.Add(player);
if (player != QSBPlayerManager.LocalPlayer)
{
DebugLog.DebugWrite($"fade out player {player.PlayerId}");
player.DitheringAnimator.SetVisible(false, 3);
}
if (_playersInFog.Count == QSBPlayerManager.PlayerList.Count)
{
StartCollapse();
}
}
private void StartCollapse()
{
DebugLog.DebugWrite("fade in everyone, fog sphere collapse");
var repelVolume = (WhiteHoleFluidVolume)_controller._repelVolume;
repelVolume.SetVolumeActivation(false);
QSBPlayerManager.ShowAllPlayers();
_controller._state = CosmicInflationController.State.Collapsing;
_controller._stateChangeTime = Time.time;
_controller._collapseStartPos = _controller._possibilitySphereRoot.localPosition;
_controller._smokeSphereTrigger.SetTriggerActivation(false);
_controller._inflationLight.FadeTo(1f, 1f);
_controller._possibilitySphereController.OnCollapse();
if (_controller._campsiteController.GetUseAltPostCollapseSocket())
{
_controller._playerPostCollapseSocket = _controller._altPlayerPostCollapseSocket;
_controller._altTravelerToHidePostCollapse.SetActive(false);
}
Locator.GetPlayerBody().SetPosition(_controller._playerPostCollapseSocket.position);
Locator.GetPlayerBody().SetRotation(_controller._playerPostCollapseSocket.rotation);
Locator.GetPlayerBody().SetVelocity(-_controller._playerPostCollapseSocket.forward);
Locator.GetPlayerTransform().GetRequiredComponent<PlayerLockOnTargeting>().LockOn(_controller._possibilitySphereRoot, 2f);
foreach (var particles in _controller._smokeSphereParticles)
{
particles.Stop();
}
}
}
}

View File

@ -1,9 +0,0 @@
using QSB.Patches;
namespace QSB.EyeOfTheUniverse.CosmicInflation.Patches
{
internal class InflationPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
}
}

View File

@ -1,107 +1,28 @@
using QSB.EyeOfTheUniverse.EyeStateSync.Messages; using QSB.EyeOfTheUniverse.EyeStateSync.Messages;
using QSB.Messaging; using QSB.Messaging;
using QSB.Player;
using QSB.Player.Messages;
using QSB.WorldSync; using QSB.WorldSync;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine; using UnityEngine;
namespace QSB.EyeOfTheUniverse.MaskSync namespace QSB.EyeOfTheUniverse.MaskSync
{ {
internal class MaskManager : WorldObjectManager internal class MaskManager : MonoBehaviour
{ {
public static MaskManager Instance { get; private set; } private static bool _flickering;
private static float _flickerOutTime;
private readonly List<PlayerInfo> _playersInZone = new(); public void Awake() => QSBSceneManager.OnSceneLoaded += OnSceneLoaded;
private MaskZoneController _controller;
private bool _flickering;
private float _flickerOutTime;
public override WorldObjectType WorldObjectType => WorldObjectType.Eye; private static void OnSceneLoaded(OWScene oldScene, OWScene newScene, bool inUniverse)
public override void Awake()
{ {
base.Awake(); _flickering = false;
Instance = this; _flickerOutTime = 0f;
QSBPlayerManager.OnRemovePlayer += OnPlayerLeave;
} }
private void OnPlayerLeave(PlayerInfo player) public static void FlickerOutShuttle()
{
if (_playersInZone.Contains(player))
{
Exit(player);
}
}
protected override void RebuildWorldObjects(OWScene scene)
{
_playersInZone.Clear();
if (_controller != null)
{
_controller._maskZoneTrigger.OnEntry -= OnEntry;
_controller._maskZoneTrigger.OnExit -= OnExit;
}
_controller = QSBWorldSync.GetUnityObjects<MaskZoneController>().First();
_controller._maskZoneTrigger.OnEntry -= _controller.OnEnterMaskZone;
_controller._maskZoneTrigger.OnExit -= _controller.OnExitMaskZone;
_controller._maskZoneTrigger.OnEntry += OnEntry;
_controller._maskZoneTrigger.OnExit += OnExit;
}
private static void OnEntry(GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
new EnterLeaveMessage(EnterLeaveType.EnterMaskZone).Send();
}
}
private static void OnExit(GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
new EnterLeaveMessage(EnterLeaveType.ExitMaskZone).Send();
}
}
public void Enter(PlayerInfo player)
{
if (_playersInZone.Count == 0)
{
_controller._whiteSphere.SetActive(true);
_controller._groundSignal.SetSignalActivation(false);
_controller._skySignal.SetSignalActivation(true);
_controller._skeletonTower.SetIsQuantum(_controller._hasPlayerLookedAtSky);
_controller.enabled = true;
}
_playersInZone.Add(player);
}
public void Exit(PlayerInfo player)
{
_playersInZone.Remove(player);
if (_playersInZone.Count == 0 && !_controller._shuttle.HasLaunched())
{
_controller._whiteSphere.SetActive(false);
_controller._skeletonTower.SetIsQuantum(false);
_controller._groundSignal.SetSignalActivation(true);
_controller._skySignal.SetSignalActivation(false);
_controller.enabled = false;
}
}
public void FlickerOutShuttle()
{ {
FlickerMessage.IgnoreNextMessage = true; FlickerMessage.IgnoreNextMessage = true;
GlobalMessenger<float, float>.FireEvent("FlickerOffAndOn", 0.5f, 0.5f); GlobalMessenger<float, float>.FireEvent(OWEvents.FlickerOffAndOn, 0.5f, 0.5f);
_flickerOutTime = Time.time + 0.5f; _flickerOutTime = Time.time + 0.5f;
_flickering = true; _flickering = true;
} }

View File

@ -1,6 +1,5 @@
using HarmonyLib; using HarmonyLib;
using QSB.Patches; using QSB.Patches;
using QSB.Utility;
namespace QSB.EyeOfTheUniverse.MaskSync.Patches namespace QSB.EyeOfTheUniverse.MaskSync.Patches
{ {
@ -17,7 +16,7 @@ namespace QSB.EyeOfTheUniverse.MaskSync.Patches
return true; return true;
} }
MaskManager.Instance.FlickerOutShuttle(); MaskManager.FlickerOutShuttle();
__instance.enabled = false; __instance.enabled = false;
return false; return false;

View File

@ -1,81 +0,0 @@
using QSB.Messaging;
using QSB.Player;
using QSB.Player.Messages;
using QSB.WorldSync;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.EyeOfTheUniverse.VesselSync
{
internal class VesselManager : WorldObjectManager
{
public static VesselManager Instance { get; private set; }
private readonly List<PlayerInfo> _playersInCage = new();
private VesselWarpController _warpController;
// cage trigger is null in the eye
public override WorldObjectType WorldObjectType => WorldObjectType.SolarSystem;
public override void Awake()
{
base.Awake();
Instance = this;
}
protected override void RebuildWorldObjects(OWScene scene)
{
_playersInCage.Clear();
if (_warpController != null)
{
_warpController._cageTrigger.OnEntry -= OnEntry;
_warpController._cageTrigger.OnExit -= OnExit;
}
_warpController = QSBWorldSync.GetUnityObjects<VesselWarpController>().First();
_warpController._cageTrigger.OnExit -= _warpController.OnExitCageTrigger;
_warpController._cageTrigger.OnEntry += OnEntry;
_warpController._cageTrigger.OnExit += OnExit;
}
private static void OnEntry(GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
new EnterLeaveMessage(EnterLeaveType.EnterVesselCage).Send();
}
}
private static void OnExit(GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
new EnterLeaveMessage(EnterLeaveType.ExitVesselCage).Send();
}
}
public void Enter(PlayerInfo player)
{
_playersInCage.Add(player);
}
public void Exit(PlayerInfo player)
{
_playersInCage.Remove(player);
if (_playersInCage.Count == 0 && _warpController._hasPower)
{
var obj = _warpController;
obj._cageClosed = true;
obj._cageAnimator.TranslateToLocalPosition(new Vector3(0f, -8.1f, 0f), 5f);
obj._cageAnimator.RotateToLocalEulerAngles(new Vector3(0f, 180f, 0f), 5f);
obj._cageAnimator.OnTranslationComplete -= obj.OnCageAnimationComplete;
obj._cageAnimator.OnTranslationComplete += obj.OnCageAnimationComplete;
obj._cageLoopingAudio.FadeIn(1f);
}
}
}
}

View File

@ -4,20 +4,9 @@
{ {
EnterMoon, EnterMoon,
ExitMoon, ExitMoon,
EnterShrine,
ExitShrine,
EnterPlatform, EnterPlatform,
ExitPlatform, ExitPlatform,
EnterNonNomaiHeadZone,
ExitNonNomaiHeadZone,
EnterShip, EnterShip,
ExitShip, ExitShip,
EnterNomaiHeadZone,
ExitNomaiHeadZone,
EnterVesselCage,
ExitVesselCage,
EnterCosmicFog,
EnterMaskZone,
ExitMaskZone
} }
} }

View File

@ -1,8 +1,4 @@
using OWML.Common; using OWML.Common;
using QSB.Animation.NPC.WorldObjects;
using QSB.EyeOfTheUniverse.CosmicInflation;
using QSB.EyeOfTheUniverse.MaskSync;
using QSB.EyeOfTheUniverse.VesselSync;
using QSB.Messaging; using QSB.Messaging;
using QSB.Player.TransformSync; using QSB.Player.TransformSync;
using QSB.PoolSync; using QSB.PoolSync;
@ -66,12 +62,6 @@ namespace QSB.Player.Messages
case EnterLeaveType.ExitMoon: case EnterLeaveType.ExitMoon:
player.IsInMoon = false; player.IsInMoon = false;
break; break;
case EnterLeaveType.EnterShrine:
player.IsInShrine = true;
break;
case EnterLeaveType.ExitShrine:
player.IsInShrine = false;
break;
case EnterLeaveType.EnterPlatform: case EnterLeaveType.EnterPlatform:
CustomNomaiRemoteCameraPlatform.CustomPlatformList[ObjectId] CustomNomaiRemoteCameraPlatform.CustomPlatformList[ObjectId]
.OnRemotePlayerEnter(From); .OnRemotePlayerEnter(From);
@ -80,39 +70,12 @@ namespace QSB.Player.Messages
CustomNomaiRemoteCameraPlatform.CustomPlatformList[ObjectId] CustomNomaiRemoteCameraPlatform.CustomPlatformList[ObjectId]
.OnRemotePlayerExit(From); .OnRemotePlayerExit(From);
break; break;
case EnterLeaveType.EnterNonNomaiHeadZone:
ObjectId.GetWorldObject<QSBCharacterAnimController>().AddPlayerToHeadZone(player);
break;
case EnterLeaveType.ExitNonNomaiHeadZone:
ObjectId.GetWorldObject<QSBCharacterAnimController>().RemovePlayerFromHeadZone(player);
break;
case EnterLeaveType.EnterNomaiHeadZone:
ObjectId.GetWorldObject<QSBSolanumAnimController>().AddPlayerToHeadZone(player);
break;
case EnterLeaveType.ExitNomaiHeadZone:
ObjectId.GetWorldObject<QSBSolanumAnimController>().RemovePlayerFromHeadZone(player);
break;
case EnterLeaveType.EnterShip: case EnterLeaveType.EnterShip:
ShipManager.Instance.AddPlayerToShip(player); ShipManager.Instance.AddPlayerToShip(player);
break; break;
case EnterLeaveType.ExitShip: case EnterLeaveType.ExitShip:
ShipManager.Instance.RemovePlayerFromShip(player); ShipManager.Instance.RemovePlayerFromShip(player);
break; break;
case EnterLeaveType.EnterVesselCage:
VesselManager.Instance.Enter(player);
break;
case EnterLeaveType.ExitVesselCage:
VesselManager.Instance.Exit(player);
break;
case EnterLeaveType.EnterCosmicFog:
InflationManager.Instance.Enter(player);
break;
case EnterLeaveType.EnterMaskZone:
MaskManager.Instance.Enter(player);
break;
case EnterLeaveType.ExitMaskZone:
MaskManager.Instance.Exit(player);
break;
default: default:
DebugLog.ToConsole($"Warning - Unknown EnterLeaveType : {Value}", MessageType.Warning); DebugLog.ToConsole($"Warning - Unknown EnterLeaveType : {Value}", MessageType.Warning);
break; break;

View File

@ -16,6 +16,8 @@ using QSB.Tools.TranslatorTool.TranslationSync.Messages;
using QSB.Tools.TranslatorTool.TranslationSync.WorldObjects; using QSB.Tools.TranslatorTool.TranslationSync.WorldObjects;
using QSB.TornadoSync.Messages; using QSB.TornadoSync.Messages;
using QSB.TornadoSync.WorldObjects; using QSB.TornadoSync.WorldObjects;
using QSB.TriggerSync.Messages;
using QSB.TriggerSync.WorldObjects;
using QSB.Utility; using QSB.Utility;
using QSB.WorldSync; using QSB.WorldSync;
using System.Linq; using System.Linq;
@ -126,6 +128,9 @@ namespace QSB.Player.Messages
QSBWorldSync.GetWorldObjects<QSBTornado>().ForEach(tornado QSBWorldSync.GetWorldObjects<QSBTornado>().ForEach(tornado
=> tornado.SendMessage(new TornadoFormStateMessage(tornado.FormState) { To = From })); => tornado.SendMessage(new TornadoFormStateMessage(tornado.FormState) { To = From }));
QSBWorldSync.GetWorldObjects<IQSBTrigger>().ForEach(trigger
=> trigger.SendMessage(new TriggerResyncMessage(trigger.Occupants) { To = From }));
} }
/// <summary> /// <summary>

View File

@ -2,6 +2,7 @@
using OWML.ModHelper; using OWML.ModHelper;
using OWML.ModHelper.Input; using OWML.ModHelper.Input;
using QSB.EyeOfTheUniverse.GalaxyMap; using QSB.EyeOfTheUniverse.GalaxyMap;
using QSB.EyeOfTheUniverse.MaskSync;
using QSB.Inputs; using QSB.Inputs;
using QSB.Menus; using QSB.Menus;
using QSB.Patches; using QSB.Patches;
@ -109,6 +110,7 @@ namespace QSB
gameObject.AddComponent<StatueManager>(); gameObject.AddComponent<StatueManager>();
gameObject.AddComponent<GalaxyMapManager>(); gameObject.AddComponent<GalaxyMapManager>();
gameObject.AddComponent<DebugCameraSettings>(); gameObject.AddComponent<DebugCameraSettings>();
gameObject.AddComponent<MaskManager>();
// WorldObject managers // WorldObject managers
foreach (var type in typeof(WorldObjectManager).GetDerivedTypes()) foreach (var type in typeof(WorldObjectManager).GetDerivedTypes())

View File

@ -3,7 +3,6 @@ using OWML.Common;
using QSB.Messaging; using QSB.Messaging;
using QSB.Patches; using QSB.Patches;
using QSB.Player; using QSB.Player;
using QSB.Player.Messages;
using QSB.QuantumSync.Messages; using QSB.QuantumSync.Messages;
using QSB.QuantumSync.WorldObjects; using QSB.QuantumSync.WorldObjects;
using QSB.Utility; using QSB.Utility;
@ -364,48 +363,6 @@ namespace QSB.QuantumSync.Patches
return isInControl; return isInControl;
} }
[HarmonyPrefix]
[HarmonyPatch(typeof(QuantumShrine), nameof(QuantumShrine.OnEntry))]
public static bool QuantumShrine_OnEntry(
QuantumShrine __instance,
GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
__instance._isPlayerInside = true;
__instance._fading = true;
__instance._exteriorLightController.FadeTo(0f, 1f);
new EnterLeaveMessage(EnterLeaveType.EnterShrine).Send();
}
else if (hitObj.CompareTag("ProbeDetector"))
{
__instance._isProbeInside = true;
}
return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(QuantumShrine), nameof(QuantumShrine.OnExit))]
public static bool QuantumShrine_OnExit(
QuantumShrine __instance,
GameObject hitObj)
{
if (hitObj.CompareTag("PlayerDetector"))
{
__instance._isPlayerInside = false;
__instance._fading = true;
__instance._exteriorLightController.FadeTo(1f, 1f);
new EnterLeaveMessage(EnterLeaveType.ExitShrine).Send();
}
else if (hitObj.CompareTag("ProbeDetector"))
{
__instance._isProbeInside = false;
}
return false;
}
[HarmonyPrefix] [HarmonyPrefix]
[HarmonyPatch(typeof(QuantumMoon), nameof(QuantumMoon.CheckPlayerFogProximity))] [HarmonyPatch(typeof(QuantumMoon), nameof(QuantumMoon.CheckPlayerFogProximity))]
public static bool QuantumMoon_CheckPlayerFogProximity(QuantumMoon __instance) public static bool QuantumMoon_CheckPlayerFogProximity(QuantumMoon __instance)

View File

@ -0,0 +1,26 @@
using QSB.Messaging;
using QSB.Player;
using QSB.TriggerSync.WorldObjects;
namespace QSB.TriggerSync.Messages
{
public class TriggerMessage : QSBBoolWorldObjectMessage<IQSBTrigger>
{
public TriggerMessage(bool entered) => Value = entered;
public override void OnReceiveLocal() => OnReceiveRemote();
public override void OnReceiveRemote()
{
var player = QSBPlayerManager.GetPlayer(From);
if (Value)
{
WorldObject.Enter(player);
}
else
{
WorldObject.Exit(player);
}
}
}
}

View File

@ -0,0 +1,52 @@
using QSB.Messaging;
using QSB.Player;
using QSB.TriggerSync.WorldObjects;
using QSB.Utility;
using QuantumUNET.Transport;
using System.Collections.Generic;
using System.Linq;
namespace QSB.TriggerSync.Messages
{
/// <summary>
/// always sent by host
/// </summary>
public class TriggerResyncMessage : QSBWorldObjectMessage<IQSBTrigger>
{
private uint[] _playerIds;
public TriggerResyncMessage(IEnumerable<PlayerInfo> occupants) =>
_playerIds = occupants.Select(x => x.PlayerId).ToArray();
public override void Serialize(QNetworkWriter writer)
{
base.Serialize(writer);
writer.Write(_playerIds.Length);
_playerIds.ForEach(writer.Write);
}
public override void Deserialize(QNetworkReader reader)
{
base.Deserialize(reader);
_playerIds = new uint[reader.ReadInt32()];
for (var i = 0; i < _playerIds.Length; i++)
{
_playerIds[i] = reader.ReadUInt32();
}
}
public override void OnReceiveRemote()
{
var serverOccupants = _playerIds.Select(QSBPlayerManager.GetPlayer).ToList();
foreach (var added in serverOccupants.Except(WorldObject.Occupants))
{
WorldObject.Enter(added);
}
foreach (var removed in WorldObject.Occupants.Except(serverOccupants))
{
WorldObject.Exit(removed);
}
}
}
}

View File

@ -0,0 +1,20 @@
using QSB.TriggerSync.WorldObjects;
using QSB.WorldSync;
namespace QSB.TriggerSync
{
public class TriggerManager : WorldObjectManager
{
public override WorldObjectType WorldObjectType => WorldObjectType.Both;
protected override void RebuildWorldObjects(OWScene scene)
{
QSBWorldSync.Init<QSBCharacterTrigger, CharacterAnimController>(x => x.playerTrackingZone);
QSBWorldSync.Init<QSBSolanumTrigger, NomaiConversationManager>(x => x._watchPlayerVolume);
QSBWorldSync.Init<QSBShrineTrigger, QuantumShrine>(x => x._triggerVolume);
QSBWorldSync.Init<QSBVesselCageTrigger, VesselWarpController>(x => x._cageTrigger);
QSBWorldSync.Init<QSBInflationTrigger, CosmicInflationController>(x => x._smokeSphereTrigger);
QSBWorldSync.Init<QSBMaskZoneTrigger, MaskZoneController>(x => x._maskZoneTrigger);
}
}
}

View File

@ -0,0 +1,12 @@
namespace QSB.TriggerSync.WorldObjects
{
public class QSBCharacterTrigger : QSBTrigger<CharacterAnimController>
{
public override void Init()
{
base.Init();
AttachedObject.OnEntry -= TriggerOwner.OnZoneEntry;
AttachedObject.OnExit -= TriggerOwner.OnZoneExit;
}
}
}

View File

@ -0,0 +1,98 @@
using QSB.Player;
using QSB.Utility;
using UnityEngine;
namespace QSB.TriggerSync.WorldObjects
{
public class QSBInflationTrigger : QSBTrigger<CosmicInflationController>
{
protected override string CompareTag => "PlayerCameraDetector";
public override void Init()
{
base.Init();
AttachedObject.OnEntry -= TriggerOwner.OnEnterFogSphere;
}
protected override void OnEnter(PlayerInfo player)
{
if (TriggerOwner._state != CosmicInflationController.State.ReadyToCollapse)
{
return;
}
if (player == QSBPlayerManager.LocalPlayer)
{
AttachedObject.OnEntry -= OnEnterEvent;
AttachedObject.SetTriggerActivation(false);
TriggerOwner._probeDestroyTrigger.SetTriggerActivation(false);
DebugLog.DebugWrite("disable input, wait for other players to enter");
var repelVolume = (WhiteHoleFluidVolume)TriggerOwner._repelVolume;
repelVolume._flowSpeed = -repelVolume._flowSpeed;
repelVolume._massiveFlowSpeed = -repelVolume._massiveFlowSpeed;
repelVolume.SetVolumeActivation(true);
QSBPlayerManager.HideAllPlayers();
ReticleController.Hide();
Locator.GetFlashlight().TurnOff(false);
Locator.GetPromptManager().SetPromptsVisible(false);
OWInput.ChangeInputMode(InputMode.None);
}
else
{
DebugLog.DebugWrite($"fade out player {player.PlayerId}");
player.DitheringAnimator.SetVisible(false, 3);
}
if (Occupants.Count == QSBPlayerManager.PlayerList.Count)
{
StartCollapse();
}
}
protected override void OnExit(PlayerInfo player)
{
// wait 1 frame for player to be removed
QSBCore.UnityEvents.FireOnNextUpdate(() =>
{
if (QSBCore.IsInMultiplayer && Occupants.Count == QSBPlayerManager.PlayerList.Count)
{
StartCollapse();
}
});
}
private void StartCollapse()
{
DebugLog.DebugWrite("fade in everyone, fog sphere collapse");
var repelVolume = (WhiteHoleFluidVolume)TriggerOwner._repelVolume;
repelVolume.SetVolumeActivation(false);
QSBPlayerManager.ShowAllPlayers();
TriggerOwner._state = CosmicInflationController.State.Collapsing;
TriggerOwner._stateChangeTime = Time.time;
TriggerOwner._collapseStartPos = TriggerOwner._possibilitySphereRoot.localPosition;
AttachedObject.SetTriggerActivation(false);
TriggerOwner._inflationLight.FadeTo(1f, 1f);
TriggerOwner._possibilitySphereController.OnCollapse();
if (TriggerOwner._campsiteController.GetUseAltPostCollapseSocket())
{
TriggerOwner._playerPostCollapseSocket = TriggerOwner._altPlayerPostCollapseSocket;
TriggerOwner._altTravelerToHidePostCollapse.SetActive(false);
}
Locator.GetPlayerBody().SetPosition(TriggerOwner._playerPostCollapseSocket.position);
Locator.GetPlayerBody().SetRotation(TriggerOwner._playerPostCollapseSocket.rotation);
Locator.GetPlayerBody().SetVelocity(-TriggerOwner._playerPostCollapseSocket.forward);
Locator.GetPlayerTransform().GetRequiredComponent<PlayerLockOnTargeting>().LockOn(TriggerOwner._possibilitySphereRoot, 2f);
foreach (var particles in TriggerOwner._smokeSphereParticles)
{
particles.Stop();
}
}
}
}

View File

@ -0,0 +1,38 @@
using QSB.Player;
namespace QSB.TriggerSync.WorldObjects
{
public class QSBMaskZoneTrigger : QSBTrigger<MaskZoneController>
{
public override void Init()
{
base.Init();
AttachedObject.OnEntry -= TriggerOwner.OnEnterMaskZone;
AttachedObject.OnExit -= TriggerOwner.OnExitMaskZone;
}
protected override void OnEnter(PlayerInfo player)
{
if (Occupants.Count == 1)
{
TriggerOwner._whiteSphere.SetActive(true);
TriggerOwner._groundSignal.SetSignalActivation(false);
TriggerOwner._skySignal.SetSignalActivation(true);
TriggerOwner._skeletonTower.SetIsQuantum(TriggerOwner._hasPlayerLookedAtSky);
TriggerOwner.enabled = true;
}
}
protected override void OnExit(PlayerInfo player)
{
if (Occupants.Count == 0 && !TriggerOwner._shuttle.HasLaunched())
{
TriggerOwner._whiteSphere.SetActive(false);
TriggerOwner._skeletonTower.SetIsQuantum(false);
TriggerOwner._groundSignal.SetSignalActivation(true);
TriggerOwner._skySignal.SetSignalActivation(false);
TriggerOwner.enabled = false;
}
}
}
}

View File

@ -0,0 +1,11 @@
using QSB.Player;
namespace QSB.TriggerSync.WorldObjects
{
public class QSBShrineTrigger : QSBTrigger<QuantumShrine>
{
protected override void OnEnter(PlayerInfo player) => player.IsInShrine = true;
protected override void OnExit(PlayerInfo player) => player.IsInShrine = false;
}
}

View File

@ -0,0 +1,12 @@
namespace QSB.TriggerSync.WorldObjects
{
public class QSBSolanumTrigger : QSBTrigger<NomaiConversationManager>
{
public override void Init()
{
base.Init();
AttachedObject.OnEntry -= TriggerOwner.OnEnterWatchVolume;
AttachedObject.OnExit -= TriggerOwner.OnExitWatchVolume;
}
}
}

View File

@ -0,0 +1,116 @@
using OWML.Common;
using QSB.Messaging;
using QSB.Player;
using QSB.TriggerSync.Messages;
using QSB.Utility;
using QSB.WorldSync;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace QSB.TriggerSync.WorldObjects
{
public interface IQSBTrigger : IWorldObject
{
List<PlayerInfo> Occupants { get; }
void Enter(PlayerInfo player);
void Exit(PlayerInfo player);
}
public abstract class QSBTrigger<TO> : WorldObject<OWTriggerVolume>, IQSBTrigger
{
public TO TriggerOwner { get; init; }
public List<PlayerInfo> Occupants { get; } = new();
protected virtual string CompareTag => "PlayerDetector";
public override void Init()
{
AttachedObject.OnEntry += OnEnterEvent;
AttachedObject.OnExit += OnExitEvent;
QSBPlayerManager.OnRemovePlayer += OnPlayerLeave;
QSBCore.UnityEvents.RunWhen(() => WorldObjectManager.AllObjectsReady, () =>
{
if (AttachedObject._trackedObjects == null)
{
DebugLog.DebugWrite($"{LogName} _trackedObjects == null", MessageType.Warning);
}
else if (AttachedObject._trackedObjects.Any(x => x.CompareTag(CompareTag)))
{
((IQSBTrigger)this).SendMessage(new TriggerMessage(true));
}
});
}
public override void OnRemoval()
{
AttachedObject.OnEntry -= OnEnterEvent;
AttachedObject.OnExit -= OnExitEvent;
QSBPlayerManager.OnRemovePlayer -= OnPlayerLeave;
}
protected void OnEnterEvent(GameObject hitObj)
{
if (hitObj.CompareTag(CompareTag))
{
((IQSBTrigger)this).SendMessage(new TriggerMessage(true));
}
}
protected void OnExitEvent(GameObject hitObj)
{
if (hitObj.CompareTag(CompareTag))
{
((IQSBTrigger)this).SendMessage(new TriggerMessage(false));
}
}
private void OnPlayerLeave(PlayerInfo player)
{
if (Occupants.Contains(player))
{
Exit(player);
}
}
public void Enter(PlayerInfo player)
{
if (!Occupants.SafeAdd(player))
{
DebugLog.DebugWrite($"{LogName} + {player.PlayerId}", MessageType.Warning);
return;
}
DebugLog.DebugWrite($"{LogName} + {player.PlayerId}");
OnEnter(player);
}
public void Exit(PlayerInfo player)
{
if (!Occupants.QuickRemove(player))
{
DebugLog.DebugWrite($"{LogName} - {player.PlayerId}", MessageType.Warning);
return;
}
DebugLog.DebugWrite($"{LogName} - {player.PlayerId}");
OnExit(player);
}
/// <summary>
/// called when a player enters this trigger
/// </summary>
protected virtual void OnEnter(PlayerInfo player) { }
/// <summary>
/// called when a player exits this trigger or leaves the game
/// </summary>
protected virtual void OnExit(PlayerInfo player) { }
}
}

View File

@ -0,0 +1,27 @@
using QSB.Player;
using UnityEngine;
namespace QSB.TriggerSync.WorldObjects
{
public class QSBVesselCageTrigger : QSBTrigger<VesselWarpController>
{
public override void Init()
{
base.Init();
AttachedObject.OnExit -= TriggerOwner.OnExitCageTrigger;
}
protected override void OnExit(PlayerInfo player)
{
if (Occupants.Count == 0 && TriggerOwner._hasPower)
{
TriggerOwner._cageClosed = true;
TriggerOwner._cageAnimator.TranslateToLocalPosition(new Vector3(0f, -8.1f, 0f), 5f);
TriggerOwner._cageAnimator.RotateToLocalEulerAngles(new Vector3(0f, 180f, 0f), 5f);
TriggerOwner._cageAnimator.OnTranslationComplete -= TriggerOwner.OnCageAnimationComplete;
TriggerOwner._cageAnimator.OnTranslationComplete += TriggerOwner.OnCageAnimationComplete;
TriggerOwner._cageLoopingAudio.FadeIn(1f);
}
}
}
}

View File

@ -1,6 +1,7 @@
using OWML.Common; using OWML.Common;
using QSB.ConversationSync.Patches; using QSB.ConversationSync.Patches;
using QSB.LogSync; using QSB.LogSync;
using QSB.TriggerSync.WorldObjects;
using QSB.Utility; using QSB.Utility;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -163,11 +164,33 @@ namespace QSB.WorldSync
{ {
//DebugLog.DebugWrite($"{typeof(TWorldObject).Name} init : {listToInitFrom.Count()} instances.", MessageType.Info); //DebugLog.DebugWrite($"{typeof(TWorldObject).Name} init : {listToInitFrom.Count()} instances.", MessageType.Info);
foreach (var item in listToInitFrom) foreach (var item in listToInitFrom)
{
var obj = new TWorldObject
{
AttachedObject = item,
ObjectId = WorldObjects.Count
};
obj.Init();
WorldObjects.Add(obj);
WorldObjectsToUnityObjects.Add(item, obj);
}
}
public static void Init<TWorldObject, TUnityObject>(Func<TUnityObject, OWTriggerVolume> triggerSelector)
where TWorldObject : QSBTrigger<TUnityObject>, new()
where TUnityObject : MonoBehaviour
{
var list = GetUnityObjects<TUnityObject>()
.Select(x => (triggerSelector(x), x))
.Where(x => x.Item1);
foreach (var (item, owner) in list)
{ {
var obj = new TWorldObject var obj = new TWorldObject
{ {
AttachedObject = item, AttachedObject = item,
ObjectId = WorldObjects.Count, ObjectId = WorldObjects.Count,
TriggerOwner = owner
}; };
obj.Init(); obj.Init();