diff --git a/Directory.Build.props b/Directory.Build.props
index 4cf7c933..468bd66a 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -16,7 +16,6 @@
- C:\Program Files\Epic Games\OuterWilds
$(AppData)\OuterWildsModManager\OWML
$(SolutionDir)\qsb-unityproject\Assets
diff --git a/QSB/Animation/Player/AnimationSync.cs b/QSB/Animation/Player/AnimationSync.cs
index ec837038..d79b8773 100644
--- a/QSB/Animation/Player/AnimationSync.cs
+++ b/QSB/Animation/Player/AnimationSync.cs
@@ -39,6 +39,7 @@ public class AnimationSync : PlayerSyncObject
///
/// This wipes the NetworkAnimator's fields, so it assumes the parameters have changed.
/// Basically just forces it to set all its dirty flags.
+ /// BUG: this doesnt work for other players because its only called by the host.
///
private void SendInitialState(uint to) => NetworkAnimator.Invoke("Awake");
diff --git a/QSB/ConversationSync/CameraFacingBillboard.cs b/QSB/ConversationSync/CameraFacingBillboard.cs
index 109392ec..21499bb4 100644
--- a/QSB/ConversationSync/CameraFacingBillboard.cs
+++ b/QSB/ConversationSync/CameraFacingBillboard.cs
@@ -1,7 +1,9 @@
-using UnityEngine;
+using QSB.Utility;
+using UnityEngine;
namespace QSB.ConversationSync;
+[UsedInUnityProject]
public class CameraFacingBillboard : MonoBehaviour
{
private OWCamera _activeCam;
diff --git a/QSB/DeathSync/Patches/DeathPatches.cs b/QSB/DeathSync/Patches/DeathPatches.cs
index 478e25d8..59fa30a3 100644
--- a/QSB/DeathSync/Patches/DeathPatches.cs
+++ b/QSB/DeathSync/Patches/DeathPatches.cs
@@ -3,7 +3,6 @@ using QSB.DeathSync.Messages;
using QSB.Messaging;
using QSB.Patches;
using QSB.Player;
-using QSB.Utility;
using System.Linq;
using UnityEngine;
@@ -14,96 +13,47 @@ public class DeathPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
+ ///
+ /// don't take damage from impact in ship
+ ///
[HarmonyPrefix]
[HarmonyPatch(typeof(PlayerResources), nameof(PlayerResources.OnImpact))]
- public static bool PlayerResources_OnImpact(PlayerResources __instance, ImpactData impact) =>
- // don't take damage from impact in ship
- !PlayerState.IsInsideShip();
+ public static bool PlayerResources_OnImpact(PlayerResources __instance, ImpactData impact)
+ {
+ if (QSBCore.ShipDamage)
+ {
+ return true;
+ }
+
+ return !PlayerState.IsInsideShip();
+ }
///
/// don't insta-die from impact in ship
///
[HarmonyPrefix]
- [HarmonyPatch(typeof(HighSpeedImpactSensor), nameof(HighSpeedImpactSensor.FixedUpdate))]
- public static bool HighSpeedImpactSensor_FixedUpdate(HighSpeedImpactSensor __instance)
+ [HarmonyPatch(typeof(HighSpeedImpactSensor), nameof(HighSpeedImpactSensor.HandlePlayerInsideShip))]
+ public static bool HighSpeedImpactSensor_HandlePlayerInsideShip(HighSpeedImpactSensor __instance)
{
- if (__instance._isPlayer && (PlayerState.IsAttached() || PlayerState.IsInsideShuttle() || PlayerState.UsingNomaiRemoteCamera()))
+ if (QSBCore.ShipDamage)
{
- return false;
+ return true;
}
- if (__instance._dieNextUpdate && !__instance._dead)
+ var shipCenter = Locator.GetShipTransform().position + Locator.GetShipTransform().up * 2f;
+ var distanceFromShip = Vector3.Distance(__instance._body.GetPosition(), shipCenter);
+ if (distanceFromShip > 8f)
{
- __instance._dead = true;
- __instance._dieNextUpdate = false;
- if (__instance.gameObject.CompareTag("Player"))
- {
- Locator.GetDeathManager().SetImpactDeathSpeed(__instance._impactSpeed);
- Locator.GetDeathManager().KillPlayer(DeathType.Impact);
- }
- else if (__instance.gameObject.CompareTag("Ship"))
- {
- __instance.GetComponent().Explode();
- }
+ __instance._body.SetPosition(shipCenter);
}
- if (__instance._isPlayer && PlayerState.IsInsideShip())
+ if (!__instance._dead)
{
- var shipCenter = Locator.GetShipTransform().position + Locator.GetShipTransform().up * 2f;
- var distanceFromShip = Vector3.Distance(__instance._body.GetPosition(), shipCenter);
- if (distanceFromShip > 8f)
+ var a = __instance._body.GetVelocity() - Locator.GetShipBody().GetPointVelocity(__instance._body.GetPosition());
+ if (a.sqrMagnitude > __instance._sqrCheckSpeedThreshold)
{
- __instance._body.SetPosition(shipCenter);
- }
-
- if (!__instance._dead)
- {
- var a = __instance._body.GetVelocity() - Locator.GetShipBody().GetPointVelocity(__instance._body.GetPosition());
- if (a.sqrMagnitude > __instance._sqrCheckSpeedThreshold)
- {
- __instance._impactSpeed = a.magnitude;
- __instance._body.AddVelocityChange(-a);
- }
- }
-
- return false;
- }
-
- var passiveReferenceFrame = __instance._sectorDetector.GetPassiveReferenceFrame();
- if (!__instance._dead && passiveReferenceFrame != null)
- {
- var relativeVelocity = __instance._body.GetVelocity() - passiveReferenceFrame.GetOWRigidBody().GetPointVelocity(__instance._body.GetPosition());
- if (relativeVelocity.sqrMagnitude > __instance._sqrCheckSpeedThreshold)
- {
- var hitCount = Physics.RaycastNonAlloc(__instance.transform.TransformPoint(__instance._localOffset), relativeVelocity, __instance._raycastHits, relativeVelocity.magnitude * Time.deltaTime + __instance._radius, OWLayerMask.physicalMask, QueryTriggerInteraction.Ignore);
- for (var i = 0; i < hitCount; i++)
- {
- if (__instance._raycastHits[i].rigidbody.mass > 10f && !__instance._raycastHits[i].rigidbody.Equals(__instance._body.GetRigidbody()))
- {
- var owRigidbody = __instance._raycastHits[i].rigidbody.GetComponent();
- if (owRigidbody == null)
- {
- DebugLog.ToConsole("Rigidbody does not have attached OWRigidbody!!!", OWML.Common.MessageType.Error);
- Debug.Break();
- }
- else
- {
- relativeVelocity = __instance._body.GetVelocity() - owRigidbody.GetPointVelocity(__instance._body.GetPosition());
- var a2 = Vector3.Project(relativeVelocity, __instance._raycastHits[i].normal);
- if (a2.sqrMagnitude > __instance._sqrCheckSpeedThreshold)
- {
- __instance._body.AddVelocityChange(-a2);
- __instance._impactSpeed = a2.magnitude;
- if (!PlayerState.IsInsideTheEye())
- {
- __instance._dieNextUpdate = true;
- }
-
- break;
- }
- }
- }
- }
+ __instance._impactSpeed = a.magnitude;
+ __instance._body.AddVelocityChange(-a);
}
}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/AlarmTotemManager.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/AlarmTotemManager.cs
index b50b1e90..992f79ee 100644
--- a/QSB/EchoesOfTheEye/AlarmTotemSync/AlarmTotemManager.cs
+++ b/QSB/EchoesOfTheEye/AlarmTotemSync/AlarmTotemManager.cs
@@ -1,8 +1,9 @@
using Cysharp.Threading.Tasks;
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
+using QSB.Utility;
using QSB.WorldSync;
+using System.Linq;
using System.Threading;
-using UnityEngine;
namespace QSB.EchoesOfTheEye.AlarmTotemSync;
@@ -11,18 +12,12 @@ public class AlarmTotemManager : WorldObjectManager
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
public override bool DlcOnly => true;
- private QSBAlarmSequenceController _qsbAlarmSequenceController;
+ public static AlarmBell[] AlarmBells;
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
{
- // QSBWorldSync.Init();
+ QSBWorldSync.Init();
QSBWorldSync.Init();
-
- _qsbAlarmSequenceController = new GameObject(nameof(QSBAlarmSequenceController))
- .AddComponent();
- DontDestroyOnLoad(_qsbAlarmSequenceController.gameObject);
+ AlarmBells = QSBWorldSync.GetUnityObjects().Where(x => x._lightController).SortDeterministic().ToArray();
}
-
- public override void UnbuildWorldObjects() =>
- Destroy(_qsbAlarmSequenceController.gameObject);
}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetVisibleMessage.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetVisibleMessage.cs
new file mode 100644
index 00000000..fd8ad1a4
--- /dev/null
+++ b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/SetVisibleMessage.cs
@@ -0,0 +1,37 @@
+using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
+using QSB.Messaging;
+
+namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
+
+public class SetVisibleMessage : QSBWorldObjectMessage
+{
+ public SetVisibleMessage(bool visible) : base(visible) { }
+
+ public override void OnReceiveRemote()
+ {
+ if (WorldObject.AttachedObject._isPlayerVisible == Data)
+ {
+ return;
+ }
+
+ WorldObject.AttachedObject._isPlayerVisible = Data;
+ if (Data)
+ {
+ Locator.GetAlarmSequenceController().IncreaseAlarmCounter();
+ WorldObject.AttachedObject._secondsConcealed = 0f;
+ WorldObject.AttachedObject._simTotemMaterials[0] = WorldObject.AttachedObject._simAlarmMaterial;
+ WorldObject.AttachedObject._simTotemRenderer.sharedMaterials = WorldObject.AttachedObject._simTotemMaterials;
+ WorldObject.AttachedObject._simVisionConeRenderer.SetColor(WorldObject.AttachedObject._simAlarmColor);
+ GlobalMessenger.FireEvent("AlarmTotemTriggered");
+ }
+ else
+ {
+ Locator.GetAlarmSequenceController().DecreaseAlarmCounter();
+ WorldObject.AttachedObject._secondsConcealed = 0f;
+ WorldObject.AttachedObject._simTotemMaterials[0] = WorldObject.AttachedObject._origSimEyeMaterial;
+ WorldObject.AttachedObject._simTotemRenderer.sharedMaterials = WorldObject.AttachedObject._simTotemMaterials;
+ WorldObject.AttachedObject._simVisionConeRenderer.SetColor(WorldObject.AttachedObject._simVisionConeRenderer.GetOriginalColor());
+ WorldObject.AttachedObject._pulseLightController.FadeTo(0f, 0.5f);
+ }
+ }
+}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemEnabledMessage.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemEnabledMessage.cs
deleted file mode 100644
index 446c3f0e..00000000
--- a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemEnabledMessage.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
-using QSB.Messaging;
-
-namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
-
-public class TotemEnabledMessage : QSBWorldObjectMessage
-{
- public TotemEnabledMessage(bool enabled) : base(enabled) { }
-
- public override void OnReceiveRemote() =>
- WorldObject.SetEnabled(Data);
-}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemVisibleForMessage.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemVisibleForMessage.cs
deleted file mode 100644
index e8624afb..00000000
--- a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemVisibleForMessage.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
-using QSB.Messaging;
-using System.Collections.Generic;
-
-namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
-
-public class TotemVisibleForMessage : QSBWorldObjectMessage>
-{
- public TotemVisibleForMessage(List visibleFor) : base(visibleFor) { }
-
- public override void OnReceiveRemote()
- {
- WorldObject.VisibleFor.Clear();
- WorldObject.VisibleFor.AddRange(Data);
- }
-}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemVisibleMessage.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemVisibleMessage.cs
deleted file mode 100644
index 947302e9..00000000
--- a/QSB/EchoesOfTheEye/AlarmTotemSync/Messages/TotemVisibleMessage.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
-using QSB.Messaging;
-
-namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
-
-public class TotemVisibleMessage : QSBWorldObjectMessage
-{
- public TotemVisibleMessage(bool visible) : base(visible) { }
- public override void OnReceiveLocal() => OnReceiveRemote();
- public override void OnReceiveRemote() => WorldObject.SetVisible(From, Data);
-}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmSequenceControllerPatches.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmSequenceControllerPatches.cs
new file mode 100644
index 00000000..d51aa386
--- /dev/null
+++ b/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmSequenceControllerPatches.cs
@@ -0,0 +1,93 @@
+using HarmonyLib;
+using QSB.Patches;
+using UnityEngine;
+
+namespace QSB.EchoesOfTheEye.AlarmTotemSync.Patches;
+
+[HarmonyPatch(typeof(AlarmSequenceController))]
+public class AlarmSequenceControllerPatches : QSBPatch
+{
+ public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(AlarmSequenceController.IncreaseAlarmCounter))]
+ private static bool IncreaseAlarmCounter(AlarmSequenceController __instance)
+ {
+ __instance._alarmCounter++;
+ if (__instance._alarmCounter == 1)
+ {
+ __instance.PlayChimes();
+ }
+ __instance.enabled = true;
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(AlarmSequenceController.DecreaseAlarmCounter))]
+ private static bool DecreaseAlarmCounter(AlarmSequenceController __instance)
+ {
+ __instance._alarmCounter--;
+ if (__instance._alarmCounter < 0)
+ {
+ __instance._alarmCounter = 0;
+ Debug.LogError("Something went wrong, alarm counter should never drop below zero!");
+ }
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(AlarmSequenceController.StopChimes))]
+ private static bool StopChimes(AlarmSequenceController __instance)
+ {
+ __instance._playing = false;
+ __instance._stopRequested = false;
+ __instance._animationStarted = false;
+ foreach (var alarmBell in AlarmTotemManager.AlarmBells)
+ {
+ alarmBell.StopAnimation();
+ }
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(AlarmSequenceController.Update))]
+ private static bool Update(AlarmSequenceController __instance)
+ {
+ __instance.UpdateWakeFraction();
+ if (__instance._playing)
+ {
+ __instance.UpdateChimes();
+ }
+ __instance.UpdatePulse();
+ if (!__instance._playing && __instance._alarmCounter == 0 && __instance._pulse <= 0.01f)
+ {
+ __instance._pulse = 0f;
+ __instance._targetPulse = 0f;
+ __instance.enabled = false;
+ }
+ return false;
+ }
+
+ [HarmonyPrefix]
+ [HarmonyPatch(nameof(AlarmSequenceController.PlaySingleChime))]
+ private static bool PlaySingleChime(AlarmSequenceController __instance)
+ {
+ foreach (var alarmBell in AlarmTotemManager.AlarmBells)
+ {
+ alarmBell.PlaySingleChime(__instance._chimeIndex);
+ }
+ if (!__instance._animationStarted && !__instance._dreamWorldController.IsInDream())
+ {
+ foreach (var alarmBell in AlarmTotemManager.AlarmBells)
+ {
+ alarmBell.PlayAnimation();
+ }
+ __instance._animationStarted = true;
+ }
+ if (__instance._dreamWorldController.IsInDream() && !__instance._dreamWorldController.IsExitingDream())
+ {
+ Locator.GetDreamWorldAudioController().PlaySingleAlarmChime(__instance._chimeIndex, __instance._volumeCurve.Evaluate(__instance._wakeFraction));
+ }
+ return false;
+ }
+}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmTotemPatches.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmTotemPatches.cs
index 93169d62..8b84d710 100644
--- a/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmTotemPatches.cs
+++ b/QSB/EchoesOfTheEye/AlarmTotemSync/Patches/AlarmTotemPatches.cs
@@ -1,8 +1,11 @@
using HarmonyLib;
+using QSB.AuthoritySync;
using QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
using QSB.Messaging;
using QSB.Patches;
+using QSB.Player;
+using QSB.Utility;
using QSB.WorldSync;
using UnityEngine;
@@ -12,27 +15,58 @@ public class AlarmTotemPatches : QSBPatch
{
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
- /*
[HarmonyPrefix]
[HarmonyPatch(typeof(AlarmTotem), nameof(AlarmTotem.OnSectorOccupantAdded))]
- private static void OnSectorOccupantAdded(AlarmTotem __instance, SectorDetector sectorDetector)
+ private static bool OnSectorOccupantAdded(AlarmTotem __instance, SectorDetector sectorDetector)
{
- if (sectorDetector.GetOccupantType() == DynamicOccupant.Player && QSBWorldSync.AllObjectsReady)
+ if (!QSBWorldSync.AllObjectsReady)
{
- __instance.GetWorldObject()
- .SendMessage(new TotemEnabledMessage(true));
+ return true;
}
+
+ if (sectorDetector.GetOccupantType() == DynamicOccupant.Player)
+ {
+ __instance.enabled = true;
+ var qsbAlarmTotem = __instance.GetWorldObject();
+ qsbAlarmTotem.RequestOwnership();
+ }
+ return false;
}
[HarmonyPrefix]
[HarmonyPatch(typeof(AlarmTotem), nameof(AlarmTotem.OnSectorOccupantRemoved))]
- private static void OnSectorOccupantRemoved(AlarmTotem __instance, SectorDetector sectorDetector)
+ private static bool OnSectorOccupantRemoved(AlarmTotem __instance, SectorDetector sectorDetector)
{
- if (sectorDetector.GetOccupantType() == DynamicOccupant.Player && QSBWorldSync.AllObjectsReady)
+ if (!QSBWorldSync.AllObjectsReady)
{
- __instance.GetWorldObject()
- .SendMessage(new TotemEnabledMessage(false));
+ return true;
}
+
+ if (sectorDetector.GetOccupantType() == DynamicOccupant.Player)
+ {
+ __instance.enabled = false;
+ var qsbAlarmTotem = __instance.GetWorldObject();
+ qsbAlarmTotem.ReleaseOwnership();
+ Delay.RunFramesLater(10, () =>
+ {
+ // no one else took ownership, so we can safely turn stuff off
+ // ie turn off when no one else is there
+ if (qsbAlarmTotem.Owner == 0)
+ {
+ __instance._pulseLightController.SetIntensity(0f);
+ __instance._simTotemMaterials[0] = __instance._origSimEyeMaterial;
+ __instance._simTotemRenderer.sharedMaterials = __instance._simTotemMaterials;
+ __instance._simVisionConeRenderer.SetColor(__instance._simVisionConeRenderer.GetOriginalColor());
+ if (__instance._isPlayerVisible)
+ {
+ __instance._isPlayerVisible = false;
+ __instance._secondsConcealed = 0f;
+ Locator.GetAlarmSequenceController().DecreaseAlarmCounter();
+ }
+ }
+ });
+ }
+ return false;
}
[HarmonyPrefix]
@@ -43,45 +77,87 @@ public class AlarmTotemPatches : QSBPatch
{
return true;
}
-
var qsbAlarmTotem = __instance.GetWorldObject();
- var isLocallyVisible = qsbAlarmTotem.IsLocallyVisible;
- qsbAlarmTotem.IsLocallyVisible = __instance.CheckPlayerVisible();
- if (qsbAlarmTotem.IsLocallyVisible && !isLocallyVisible)
+ if (qsbAlarmTotem.Owner != QSBPlayerManager.LocalPlayerId)
{
- qsbAlarmTotem.SendMessage(new TotemVisibleMessage(true));
- }
- else if (isLocallyVisible && !qsbAlarmTotem.IsLocallyVisible)
- {
- qsbAlarmTotem.SendMessage(new TotemVisibleMessage(false));
+ return false;
}
var isPlayerVisible = __instance._isPlayerVisible;
- __instance._isPlayerVisible = qsbAlarmTotem.VisibleFor.Count > 0;
- if (__instance._isPlayerVisible && !isPlayerVisible)
+ __instance._isPlayerVisible = __instance.CheckPlayerVisible();
+ if (!isPlayerVisible && __instance._isPlayerVisible)
{
Locator.GetAlarmSequenceController().IncreaseAlarmCounter();
+ __instance._secondsConcealed = 0f;
__instance._simTotemMaterials[0] = __instance._simAlarmMaterial;
__instance._simTotemRenderer.sharedMaterials = __instance._simTotemMaterials;
__instance._simVisionConeRenderer.SetColor(__instance._simAlarmColor);
- if (__instance._isTutorialTotem)
- {
- GlobalMessenger.FireEvent("TutorialAlarmTotemTriggered");
- }
+ GlobalMessenger.FireEvent("AlarmTotemTriggered");
+ qsbAlarmTotem.SendMessage(new SetVisibleMessage(true));
}
else if (isPlayerVisible && !__instance._isPlayerVisible)
{
Locator.GetAlarmSequenceController().DecreaseAlarmCounter();
+ __instance._secondsConcealed = 0f;
__instance._simTotemMaterials[0] = __instance._origSimEyeMaterial;
__instance._simTotemRenderer.sharedMaterials = __instance._simTotemMaterials;
__instance._simVisionConeRenderer.SetColor(__instance._simVisionConeRenderer.GetOriginalColor());
__instance._pulseLightController.FadeTo(0f, 0.5f);
+ qsbAlarmTotem.SendMessage(new SetVisibleMessage(false));
}
-
return false;
}
- */
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(AlarmTotem), nameof(AlarmTotem.CheckPlayerVisible))]
+ private static bool CheckPlayerVisible(AlarmTotem __instance, out bool __result)
+ {
+ if (!__instance._isFaceOpen)
+ {
+ __result = false;
+ return false;
+ }
+ foreach (var player in QSBPlayerManager.PlayerList)
+ {
+ var position = player.Camera.transform.position;
+ if (__instance.CheckPointInVisionCone(position) && !__instance.CheckLineOccluded(__instance._sightOrigin.position, position))
+ {
+ if (player.LightSensor.IsIlluminated())
+ {
+ __result = true;
+ return false;
+ }
+ if (player.AssignedSimulationLantern == null)
+ {
+ continue;
+ }
+ var lanternController = player.AssignedSimulationLantern.AttachedObject.GetLanternController();
+ if (lanternController.IsHeldByPlayer())
+ {
+ if (lanternController.IsConcealed())
+ {
+ if (!__instance._hasConcealedFromAlarm)
+ {
+ __instance._secondsConcealed += Time.deltaTime;
+ if (__instance._secondsConcealed > 1f)
+ {
+ __instance._hasConcealedFromAlarm = true;
+ GlobalMessenger.FireEvent("ConcealFromAlarmTotem");
+ }
+ }
+ __result = false;
+ return false;
+ }
+ __result = true;
+ return false;
+ }
+ }
+ }
+ __result = false;
+ return false;
+ }
+
[HarmonyPrefix]
[HarmonyPatch(typeof(AlarmBell), nameof(AlarmBell.OnEntry))]
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/QSBAlarmSequenceController.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/QSBAlarmSequenceController.cs
deleted file mode 100644
index d81c178d..00000000
--- a/QSB/EchoesOfTheEye/AlarmTotemSync/QSBAlarmSequenceController.cs
+++ /dev/null
@@ -1,245 +0,0 @@
-using UnityEngine;
-
-namespace QSB.EchoesOfTheEye.AlarmTotemSync;
-
-///
-/// copied and modified from base game
-///
-public class QSBAlarmSequenceController : MonoBehaviour
-{
- private const int CHIME_COUNT = 3;
-
- [SerializeField]
- private float _wakeDuration = 5f;
-
- [SerializeField]
- private float _recoveryDuration = 2f;
-
- [Header("Audio")]
- [SerializeField]
- private float _audioLingerTime = 3f;
-
- [SerializeField]
- private AnimationCurve _volumeCurve;
-
- [Header("Pulse")]
- [SerializeField]
- private float _pulseAttackLength = 0.2f;
-
- [SerializeField]
- private float _pulseHoldLength = 0.1f;
-
- [SerializeField]
- private float _pulseCooldownLength = 1f;
-
- private DreamWorldController _dreamWorldController;
-
- private AlarmBell _activeBell;
-
- private int _alarmCounter;
-
- private float _wakeFraction;
-
- private float _targetPulse;
-
- private float _pulse;
-
- private bool _playing;
-
- private bool _animationStarted;
-
- private bool _stopRequested;
-
- private float _stopTime;
-
- private int _chimeIndex;
-
- private float _lastChimeTime;
-
- private float _chimeInterval;
-
- private void Awake()
- {
- // Locator.RegisterAlarmSequenceController(this);
- GlobalMessenger.AddListener("ExitDreamWorld", OnExitDreamWorld);
- }
-
- private void Start()
- {
- _dreamWorldController = Locator.GetDreamWorldController();
- enabled = false;
- }
-
- private void OnDestroy()
- {
- GlobalMessenger.RemoveListener("ExitDreamWorld", OnExitDreamWorld);
- }
-
- public void RegisterDreamEyeMaskController(DreamEyeMaskController dreamEyeMaskController) { }
-
- public float GetPulseIntensity() => _pulse;
-
- public bool IsAlarmWakingPlayer() => _alarmCounter > 0 && !PlayerState.IsResurrected();
-
- public void IncreaseAlarmCounter()
- {
- if (!_dreamWorldController.IsInDream() || _dreamWorldController.IsExitingDream())
- {
- return;
- }
-
- _alarmCounter++;
- if (_alarmCounter == 1)
- {
- PlayChimes();
- }
-
- enabled = true;
- }
-
- public void DecreaseAlarmCounter()
- {
- if (!_dreamWorldController.IsInDream() || _dreamWorldController.IsExitingDream())
- {
- return;
- }
-
- _alarmCounter--;
- if (_alarmCounter < 0)
- {
- _alarmCounter = 0;
- Debug.LogError("Something went wrong, alarm counter should never drop below zero!");
- }
- }
-
- private void PlayChimes()
- {
- if (Locator.GetDreamWorldController().GetDreamCampfire() != null)
- {
- _activeBell = Locator.GetDreamWorldController().GetDreamCampfire().GetAlarmBell();
- }
-
- _playing = true;
- _chimeInterval = 1f;
- _lastChimeTime = 0f;
- _stopRequested = false;
- }
-
- private void StopChimes()
- {
- _playing = false;
- _stopRequested = false;
- _animationStarted = false;
- if (_activeBell != null)
- {
- _activeBell.StopAnimation();
- _activeBell = null;
- }
- }
-
- private void Update()
- {
- if (_dreamWorldController.IsInDream() && !_dreamWorldController.IsExitingDream())
- {
- UpdateWakeFraction();
- }
-
- if (_playing)
- {
- UpdateChimes();
- }
-
- UpdatePulse();
- if (!_playing && _alarmCounter == 0 && _pulse <= 0.01f)
- {
- _pulse = 0f;
- _targetPulse = 0f;
- enabled = false;
- }
- }
-
- private void UpdateWakeFraction()
- {
- if (_alarmCounter > 0)
- {
- _wakeFraction = Mathf.MoveTowards(_wakeFraction, 1f, Time.deltaTime / _wakeDuration);
- if (_wakeFraction >= 1f && !PlayerState.IsResurrected())
- {
- _dreamWorldController.ExitDreamWorld(DreamWakeType.Alarm);
- }
- }
- else if (_wakeFraction > 0f)
- {
- _wakeFraction = Mathf.MoveTowards(_wakeFraction, 0f, Time.deltaTime / _recoveryDuration);
- if (_wakeFraction <= 0f)
- {
- StopChimes();
- }
- }
- }
-
- private void UpdateChimes()
- {
- if (Time.time > _lastChimeTime + _chimeInterval)
- {
- if (!PlayerState.IsResurrected())
- {
- PlaySingleChime();
- }
-
- _targetPulse = 1f;
- _lastChimeTime = Time.time;
- _chimeInterval = Mathf.Max(_chimeInterval - 0.08f, 0.4f);
- _chimeIndex++;
- _chimeIndex = _chimeIndex >= CHIME_COUNT ? 0 : _chimeIndex;
- }
-
- if (_stopRequested && Time.time > _stopTime)
- {
- StopChimes();
- }
- }
-
- private void UpdatePulse()
- {
- if (Time.time > _lastChimeTime + _pulseAttackLength + _pulseHoldLength)
- {
- var num = _pulseCooldownLength * _chimeInterval;
- _targetPulse = Mathf.MoveTowards(_targetPulse, 0f, 1f / num * Time.deltaTime);
- _pulse = _targetPulse;
- return;
- }
-
- _pulse = Mathf.MoveTowards(_pulse, _targetPulse, 1f / _pulseAttackLength * Time.deltaTime);
- }
-
- private void PlaySingleChime()
- {
- if (_activeBell != null)
- {
- _activeBell.PlaySingleChime(_chimeIndex);
- if (!_animationStarted && !_dreamWorldController.IsInDream())
- {
- _activeBell.PlayAnimation();
- _animationStarted = true;
- }
- }
-
- if (_dreamWorldController.IsInDream() && !_dreamWorldController.IsExitingDream())
- {
- Locator.GetDreamWorldAudioController().PlaySingleAlarmChime(_chimeIndex, _volumeCurve.Evaluate(_wakeFraction));
- }
- }
-
- private void OnExitDreamWorld()
- {
- if (_playing)
- {
- _stopRequested = true;
- _stopTime = Time.time + _audioLingerTime;
- }
-
- _alarmCounter = 0;
- _wakeFraction = 0f;
- }
-}
diff --git a/QSB/EchoesOfTheEye/AlarmTotemSync/WorldObjects/QSBAlarmTotem.cs b/QSB/EchoesOfTheEye/AlarmTotemSync/WorldObjects/QSBAlarmTotem.cs
index 69ff7f9b..b8a3affd 100644
--- a/QSB/EchoesOfTheEye/AlarmTotemSync/WorldObjects/QSBAlarmTotem.cs
+++ b/QSB/EchoesOfTheEye/AlarmTotemSync/WorldObjects/QSBAlarmTotem.cs
@@ -1,83 +1,17 @@
-using Cysharp.Threading.Tasks;
+using QSB.AuthoritySync;
using QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
using QSB.Messaging;
-using QSB.Player;
-using QSB.WorldSync;
-using System.Collections.Generic;
-using System.Threading;
namespace QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
-///
-/// TODO: make this not NRE (by not doing enable sync) and then readd it back in
-///
-public class QSBAlarmTotem : WorldObject
+public class QSBAlarmTotem : AuthWorldObject
{
- public readonly List VisibleFor = new();
- public bool IsLocallyVisible;
+ public override bool CanOwn => AttachedObject.enabled;
public override void SendInitialState(uint to)
{
- this.SendMessage(new TotemEnabledMessage(AttachedObject.enabled) { To = to });
- this.SendMessage(new TotemVisibleForMessage(VisibleFor) { To = to });
- }
+ base.SendInitialState(to);
- public override async UniTask Init(CancellationToken ct) =>
- QSBPlayerManager.OnRemovePlayer += OnPlayerLeave;
-
- public override void OnRemoval() =>
- QSBPlayerManager.OnRemovePlayer -= OnPlayerLeave;
-
- private void OnPlayerLeave(PlayerInfo player) =>
- VisibleFor.QuickRemove(player.PlayerId);
-
- public void SetVisible(uint playerId, bool visible)
- {
- if (visible)
- {
- VisibleFor.SafeAdd(playerId);
- }
- else
- {
- VisibleFor.QuickRemove(playerId);
- }
- }
-
- public void SetEnabled(bool enabled)
- {
- if (AttachedObject.enabled == enabled)
- {
- return;
- }
-
- if (!enabled &&
- AttachedObject._sector &&
- AttachedObject._sector.ContainsOccupant(DynamicOccupant.Player))
- {
- // local player is in sector, do not disable
- return;
- }
-
- AttachedObject.enabled = enabled;
-
- if (!enabled)
- {
- AttachedObject._simTotemMaterials[0] = AttachedObject._origSimEyeMaterial;
- AttachedObject._simTotemRenderer.sharedMaterials = AttachedObject._simTotemMaterials;
- AttachedObject._simVisionConeRenderer.SetColor(AttachedObject._simVisionConeRenderer.GetOriginalColor());
- AttachedObject._pulseLightController.SetIntensity(0f);
- /*
- if (AttachedObject._isPlayerVisible)
- {
- AttachedObject._isPlayerVisible = false;
- Locator.GetAlarmSequenceController().DecreaseAlarmCounter();
- }
- */
- if (IsLocallyVisible)
- {
- IsLocallyVisible = false;
- this.SendMessage(new TotemVisibleMessage(false));
- }
- }
+ this.SendMessage(new SetVisibleMessage(AttachedObject._isPlayerVisible) { To = to });
}
}
diff --git a/QSB/EchoesOfTheEye/DreamLantern/DreamLanternManager.cs b/QSB/EchoesOfTheEye/DreamLantern/DreamLanternManager.cs
index bdb6d5b4..21675177 100644
--- a/QSB/EchoesOfTheEye/DreamLantern/DreamLanternManager.cs
+++ b/QSB/EchoesOfTheEye/DreamLantern/DreamLanternManager.cs
@@ -10,6 +10,9 @@ public class DreamLanternManager : WorldObjectManager
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
public override bool DlcOnly => true;
- public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) =>
+ public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
+ {
QSBWorldSync.Init();
+ QSBWorldSync.Init();
+ }
}
diff --git a/QSB/ItemSync/WorldObjects/Items/QSBDreamLanternItem.cs b/QSB/EchoesOfTheEye/DreamLantern/WorldObjects/QSBDreamLanternItem.cs
similarity index 95%
rename from QSB/ItemSync/WorldObjects/Items/QSBDreamLanternItem.cs
rename to QSB/EchoesOfTheEye/DreamLantern/WorldObjects/QSBDreamLanternItem.cs
index f3a33e81..877fc157 100644
--- a/QSB/ItemSync/WorldObjects/Items/QSBDreamLanternItem.cs
+++ b/QSB/EchoesOfTheEye/DreamLantern/WorldObjects/QSBDreamLanternItem.cs
@@ -1,9 +1,10 @@
using Cysharp.Threading.Tasks;
+using QSB.ItemSync.WorldObjects.Items;
using System.Linq;
using System.Threading;
using UnityEngine;
-namespace QSB.ItemSync.WorldObjects.Items;
+namespace QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
public class QSBDreamLanternItem : QSBItem
{
diff --git a/QSB/EchoesOfTheEye/DreamWorld/Messages/DreamWorldFakePlayer.cs b/QSB/EchoesOfTheEye/DreamWorld/Messages/DreamWorldFakePlayer.cs
new file mode 100644
index 00000000..10661e10
--- /dev/null
+++ b/QSB/EchoesOfTheEye/DreamWorld/Messages/DreamWorldFakePlayer.cs
@@ -0,0 +1,114 @@
+using HarmonyLib;
+using QSB.Animation.Player;
+using QSB.Messaging;
+using QSB.Patches;
+using QSB.Player;
+using QSB.Utility;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace QSB.EchoesOfTheEye.DreamWorld.Messages;
+
+public class DreamWorldFakePlayer : MonoBehaviour
+{
+ private static readonly List _instances = new();
+
+ public static void Create(PlayerInfo player)
+ {
+ var go = new GameObject($"player {player} DreamWorldFakePlayer");
+ go.SetActive(false);
+ go.AddComponent()._player = player;
+ go.SetActive(true);
+ }
+
+ public static void Destroy(PlayerInfo player)
+ {
+ foreach (var dreamWorldFakePlayer in _instances)
+ {
+ if (dreamWorldFakePlayer._player == player)
+ {
+ Destroy(dreamWorldFakePlayer.gameObject);
+ }
+ }
+ }
+
+ private PlayerInfo _player;
+
+ private void Awake()
+ {
+ _instances.SafeAdd(this);
+ QSBPlayerManager.OnRemovePlayer += OnRemovePlayer;
+
+ transform.parent = _player.TransformSync.ReferenceTransform;
+ transform.localPosition = _player.TransformSync.transform.position;
+ transform.localRotation = _player.TransformSync.transform.rotation;
+
+ #region fake player
+
+ var fakePlayer = _player.Body.transform.Find("REMOTE_Traveller_HEA_Player_v2").gameObject.InstantiateInactive();
+ fakePlayer.transform.SetParent(transform, false);
+
+ Destroy(fakePlayer.GetComponent());
+ Destroy(fakePlayer.GetComponent());
+
+ var REMOTE_ItemCarryTool = fakePlayer.transform.Find(
+ // TODO : kill me for my sins
+ "Traveller_Rig_v01:Traveller_Trajectory_Jnt/" +
+ "Traveller_Rig_v01:Traveller_ROOT_Jnt/" +
+ "Traveller_Rig_v01:Traveller_Spine_01_Jnt/" +
+ "Traveller_Rig_v01:Traveller_Spine_02_Jnt/" +
+ "Traveller_Rig_v01:Traveller_Spine_Top_Jnt/" +
+ "Traveller_Rig_v01:Traveller_RT_Arm_Clavicle_Jnt/" +
+ "Traveller_Rig_v01:Traveller_RT_Arm_Shoulder_Jnt/" +
+ "Traveller_Rig_v01:Traveller_RT_Arm_Elbow_Jnt/" +
+ "Traveller_Rig_v01:Traveller_RT_Arm_Wrist_Jnt/" +
+ "REMOTE_ItemCarryTool"
+ ).gameObject;
+ Destroy(REMOTE_ItemCarryTool);
+
+ fakePlayer.SetActive(true);
+
+ #endregion
+ }
+
+ private void OnDestroy()
+ {
+ _instances.QuickRemove(this);
+ QSBPlayerManager.OnRemovePlayer -= OnRemovePlayer;
+ }
+
+ private void OnRemovePlayer(PlayerInfo player)
+ {
+ if (player != _player)
+ {
+ return;
+ }
+ Destroy(gameObject);
+ }
+}
+
+public class DreamWorldFakePlayerPatch : QSBPatch
+{
+ public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
+
+ ///
+ /// do this early to create the fake player BEFORE teleporting
+ ///
+ [HarmonyPatch(typeof(DreamWorldController), nameof(DreamWorldController.EnterDreamWorld))]
+ [HarmonyPrefix]
+ private static void EnterDreamWorld()
+ {
+ if (Locator.GetToolModeSwapper().GetItemCarryTool().GetHeldItemType() == ItemType.DreamLantern)
+ {
+ new DreamWorldFakePlayerMessage().Send();
+ }
+ }
+}
+
+public class DreamWorldFakePlayerMessage : QSBMessage
+{
+ public override void OnReceiveRemote()
+ {
+ DreamWorldFakePlayer.Create(QSBPlayerManager.GetPlayer(From));
+ }
+}
diff --git a/QSB/EchoesOfTheEye/DreamWorld/Messages/EnterDreamWorldMessage.cs b/QSB/EchoesOfTheEye/DreamWorld/Messages/EnterDreamWorldMessage.cs
index 5b9f9e05..7bd9b6ad 100644
--- a/QSB/EchoesOfTheEye/DreamWorld/Messages/EnterDreamWorldMessage.cs
+++ b/QSB/EchoesOfTheEye/DreamWorld/Messages/EnterDreamWorldMessage.cs
@@ -1,5 +1,5 @@
-using QSB.EchoesOfTheEye.Ghosts.WorldObjects;
-using QSB.ItemSync.WorldObjects.Items;
+using QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
+using QSB.EchoesOfTheEye.Ghosts.WorldObjects;
using QSB.Messaging;
using QSB.Player;
using QSB.Player.TransformSync;
diff --git a/QSB/EchoesOfTheEye/DreamWorld/Messages/ExitDreamWorldMessage.cs b/QSB/EchoesOfTheEye/DreamWorld/Messages/ExitDreamWorldMessage.cs
index b1302cf8..373e25d3 100644
--- a/QSB/EchoesOfTheEye/DreamWorld/Messages/ExitDreamWorldMessage.cs
+++ b/QSB/EchoesOfTheEye/DreamWorld/Messages/ExitDreamWorldMessage.cs
@@ -50,5 +50,8 @@ internal class ExitDreamWorldMessage : QSBMessage
ghost.GetEffects().OnSectorOccupantsUpdated();
}
}
+
+ Locator.GetAlarmSequenceController().OnExitDreamWorld();
+ DreamWorldFakePlayer.Destroy(player);
}
}
diff --git a/QSB/EchoesOfTheEye/RaftSync/Messages/RaftDockOnPressInteractMessage.cs b/QSB/EchoesOfTheEye/RaftSync/Messages/RaftDockOnPressInteractMessage.cs
index 1e699b51..848e599f 100644
--- a/QSB/EchoesOfTheEye/RaftSync/Messages/RaftDockOnPressInteractMessage.cs
+++ b/QSB/EchoesOfTheEye/RaftSync/Messages/RaftDockOnPressInteractMessage.cs
@@ -5,5 +5,5 @@ namespace QSB.EchoesOfTheEye.RaftSync.Messages;
public class RaftDockOnPressInteractMessage : QSBWorldObjectMessage
{
- public override void OnReceiveRemote() => WorldObject.OnPressInteract();
+ public override void OnReceiveRemote() => WorldObject.AttachedObject.OnPressInteract();
}
diff --git a/QSB/EchoesOfTheEye/RaftSync/WorldObjects/QSBRaftDock.cs b/QSB/EchoesOfTheEye/RaftSync/WorldObjects/QSBRaftDock.cs
index 7eccf6e3..9b4761f3 100644
--- a/QSB/EchoesOfTheEye/RaftSync/WorldObjects/QSBRaftDock.cs
+++ b/QSB/EchoesOfTheEye/RaftSync/WorldObjects/QSBRaftDock.cs
@@ -6,6 +6,4 @@ namespace QSB.EchoesOfTheEye.RaftSync.WorldObjects;
public class QSBRaftDock : WorldObject, IQSBDropTarget
{
IItemDropTarget IQSBDropTarget.AttachedObject => AttachedObject;
-
- public void OnPressInteract() => AttachedObject.OnPressInteract();
}
diff --git a/QSB/EchoesOfTheEye/Sarcophagus/WorldObjects/QSBSarcophagus.cs b/QSB/EchoesOfTheEye/Sarcophagus/WorldObjects/QSBSarcophagus.cs
index 21adaa72..abee01cf 100644
--- a/QSB/EchoesOfTheEye/Sarcophagus/WorldObjects/QSBSarcophagus.cs
+++ b/QSB/EchoesOfTheEye/Sarcophagus/WorldObjects/QSBSarcophagus.cs
@@ -8,7 +8,7 @@ public class QSBSarcophagus : WorldObject
{
public override void SendInitialState(uint to)
{
- if (AttachedObject._isOpen)
+ if (AttachedObject._isOpen || AttachedObject._isSlightlyOpen)
{
this.SendMessage(new OpenMessage());
}
diff --git a/QSB/EchoesOfTheEye/VisionTorch/Messages/VisionTorchProjectMessage.cs b/QSB/EchoesOfTheEye/VisionTorch/Messages/VisionTorchProjectMessage.cs
new file mode 100644
index 00000000..906810da
--- /dev/null
+++ b/QSB/EchoesOfTheEye/VisionTorch/Messages/VisionTorchProjectMessage.cs
@@ -0,0 +1,17 @@
+using QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
+using QSB.Messaging;
+
+namespace QSB.EchoesOfTheEye.VisionTorch.Messages;
+
+public class VisionTorchProjectMessage : QSBWorldObjectMessage
+{
+ public VisionTorchProjectMessage(bool projecting) : base(projecting) { }
+
+ public override void OnReceiveRemote()
+ {
+ WorldObject.AttachedObject._isProjecting = Data;
+ WorldObject.AttachedObject._mindProjectorTrigger.SetProjectorActive(Data);
+ // prevent the torch from actually doing things remotely
+ WorldObject.AttachedObject.mindProjectorTrigger._triggerVolume.SetTriggerActivation(false);
+ }
+}
diff --git a/QSB/EchoesOfTheEye/VisionTorch/Patches/VisionTorchPatches.cs b/QSB/EchoesOfTheEye/VisionTorch/Patches/VisionTorchPatches.cs
new file mode 100644
index 00000000..d0badb34
--- /dev/null
+++ b/QSB/EchoesOfTheEye/VisionTorch/Patches/VisionTorchPatches.cs
@@ -0,0 +1,45 @@
+using HarmonyLib;
+using QSB.EchoesOfTheEye.VisionTorch.Messages;
+using QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
+using QSB.Messaging;
+using QSB.Patches;
+using QSB.WorldSync;
+
+namespace QSB.EchoesOfTheEye.VisionTorch.Patches;
+
+public class VisionTorchPatches : QSBPatch
+{
+ public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
+
+ [HarmonyPrefix]
+ [HarmonyPatch(typeof(VisionTorchItem), nameof(VisionTorchItem.Update))]
+ private static bool Update(VisionTorchItem __instance)
+ {
+ if (!QSBWorldSync.AllObjectsReady)
+ {
+ return true;
+ }
+
+ if (PlayerState.IsViewingProjector() && __instance._mindSlideProjector.mindSlideCollection.slideCollectionContainer.slideIndex == 1)
+ {
+ OWInput.ChangeInputMode(InputMode.None);
+ __instance._mindSlideProjector.OnProjectionComplete += __instance.OnProjectionComplete;
+ __instance.enabled = false;
+ return false;
+ }
+ __instance._wasProjecting = __instance._isProjecting;
+ __instance._isProjecting = OWInput.IsPressed(InputLibrary.toolActionPrimary, InputMode.Character);
+ if (__instance._isProjecting && !__instance._wasProjecting)
+ {
+ __instance._mindProjectorTrigger.SetProjectorActive(true);
+ __instance.GetWorldObject().SendMessage(new VisionTorchProjectMessage(true));
+ }
+ else if (!__instance._isProjecting && __instance._wasProjecting)
+ {
+ __instance._mindProjectorTrigger.SetProjectorActive(false);
+ __instance.GetWorldObject().SendMessage(new VisionTorchProjectMessage(false));
+ }
+
+ return false;
+ }
+}
diff --git a/QSB/EchoesOfTheEye/VisionTorch/VisionTorchManager.cs b/QSB/EchoesOfTheEye/VisionTorch/VisionTorchManager.cs
new file mode 100644
index 00000000..709126b6
--- /dev/null
+++ b/QSB/EchoesOfTheEye/VisionTorch/VisionTorchManager.cs
@@ -0,0 +1,15 @@
+using Cysharp.Threading.Tasks;
+using QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
+using QSB.WorldSync;
+using System.Threading;
+
+namespace QSB.EchoesOfTheEye.VisionTorch;
+
+public class VisionTorchManager : WorldObjectManager
+{
+ public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
+ public override bool DlcOnly => true;
+
+ public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) =>
+ QSBWorldSync.Init();
+}
diff --git a/QSB/EchoesOfTheEye/VisionTorch/WorldObjects/QSBVisionTorchItem.cs b/QSB/EchoesOfTheEye/VisionTorch/WorldObjects/QSBVisionTorchItem.cs
new file mode 100644
index 00000000..09b6961a
--- /dev/null
+++ b/QSB/EchoesOfTheEye/VisionTorch/WorldObjects/QSBVisionTorchItem.cs
@@ -0,0 +1,13 @@
+using QSB.EchoesOfTheEye.VisionTorch.Messages;
+using QSB.ItemSync.WorldObjects.Items;
+using QSB.Messaging;
+
+namespace QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
+
+public class QSBVisionTorchItem : QSBItem
+{
+ public override void SendInitialState(uint to)
+ {
+ this.SendMessage(new VisionTorchProjectMessage(AttachedObject._isProjecting) { To = to });
+ }
+}
diff --git a/QSB/GetAttachedOWRigidbodyPatch.cs b/QSB/GetAttachedOWRigidbodyPatch.cs
index 7ee82ab1..2d045faa 100644
--- a/QSB/GetAttachedOWRigidbodyPatch.cs
+++ b/QSB/GetAttachedOWRigidbodyPatch.cs
@@ -4,9 +4,6 @@ using UnityEngine;
namespace QSB;
-///
-/// TODO: TEST THIS. see if things horribly break. this could be huge.
-///
[HarmonyPatch(typeof(OWExtensions))]
public class GetAttachedOWRigidbodyPatch : QSBPatch
{
diff --git a/QSB/Inputs/Patches/InputPatches.cs b/QSB/Inputs/Patches/InputPatches.cs
index c482ace7..b4ad08fa 100644
--- a/QSB/Inputs/Patches/InputPatches.cs
+++ b/QSB/Inputs/Patches/InputPatches.cs
@@ -9,7 +9,23 @@ internal class InputPatches : QSBPatch
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
[HarmonyPrefix]
- [HarmonyPatch(typeof(OWInput), nameof(OWInput.Update))]
- public static bool OWInput_Update()
- => QSBInputManager.Instance.InputsEnabled;
+ [HarmonyPatch(typeof(AbstractCommands), nameof(AbstractCommands.Update))]
+ public static bool AbstractCommands_Update(AbstractCommands __instance)
+ {
+ if (QSBInputManager.Instance.InputsEnabled)
+ {
+ return true;
+ }
+
+ __instance.Consumed = false;
+ __instance.WasActiveLastFrame = __instance.IsActiveThisFrame;
+ __instance.IsActiveThisFrame = false;
+
+ if (__instance.WasActiveLastFrame)
+ {
+ __instance.InputStartedTime = float.MaxValue;
+ }
+
+ return false;
+ }
}
\ No newline at end of file
diff --git a/QSB/ItemSync/ItemManager.cs b/QSB/ItemSync/ItemManager.cs
index 7bf6413a..197a416d 100644
--- a/QSB/ItemSync/ItemManager.cs
+++ b/QSB/ItemSync/ItemManager.cs
@@ -5,7 +5,6 @@ using QSB.ItemSync.WorldObjects.Items;
using QSB.ItemSync.WorldObjects.Sockets;
using QSB.Utility;
using QSB.WorldSync;
-using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEngine;
@@ -21,14 +20,13 @@ internal class ItemManager : WorldObjectManager
DebugLog.DebugWrite("Building OWItems...", MessageType.Info);
// Items
- QSBWorldSync.Init();
QSBWorldSync.Init();
QSBWorldSync.Init();
QSBWorldSync.Init();
QSBWorldSync.Init();
QSBWorldSync.Init();
- QSBWorldSync.Init();
QSBWorldSync.Init();
+ // dream lantern and vision torch are set up in their own managers
// Sockets
QSBWorldSync.Init();
diff --git a/QSB/ItemSync/Patches/ItemRemotePatches.cs b/QSB/ItemSync/Patches/ItemRemotePatches.cs
index ebcf4740..ff45b34c 100644
--- a/QSB/ItemSync/Patches/ItemRemotePatches.cs
+++ b/QSB/ItemSync/Patches/ItemRemotePatches.cs
@@ -149,6 +149,12 @@ internal class ItemRemotePatches : QSBPatch
return true;
}
+ if (__instance._isProjecting)
+ {
+ __instance._mindProjectorTrigger.SetProjectorActive(false);
+ __instance._isProjecting = false;
+ }
+
// if (Locator.GetDreamWorldController().IsInDream())
// {
base_DropItem(__instance, position, normal, parent, sector, customDropTarget);
@@ -213,6 +219,12 @@ internal class ItemRemotePatches : QSBPatch
return true;
}
+ if (__instance._isProjecting)
+ {
+ __instance._mindProjectorTrigger.SetProjectorActive(false);
+ __instance._isProjecting = false;
+ }
+
base_SocketItem(__instance, socketTransform, sector);
if (__instance._visionBeam != null)
{
diff --git a/QSB/ItemSync/WorldObjects/Items/QSBVisionTorchItem.cs b/QSB/ItemSync/WorldObjects/Items/QSBVisionTorchItem.cs
deleted file mode 100644
index 10ffd92a..00000000
--- a/QSB/ItemSync/WorldObjects/Items/QSBVisionTorchItem.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace QSB.ItemSync.WorldObjects.Items;
-
-///
-/// TODO: SYNC THIS SHIT LMAOOOOOO
-///
-internal class QSBVisionTorchItem : QSBItem { }
\ No newline at end of file
diff --git a/QSB/Localization/QSBLocalization.cs b/QSB/Localization/QSBLocalization.cs
index ea94b74c..a81af601 100644
--- a/QSB/Localization/QSBLocalization.cs
+++ b/QSB/Localization/QSBLocalization.cs
@@ -2,7 +2,6 @@
using QSB.Utility;
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
@@ -82,28 +81,4 @@ public static class QSBLocalization
Current = newTranslation;
LanguageChanged?.Invoke();
}
-
- public static CultureInfo CultureInfo
- => Current.Language switch
- {
- /*
- * Language tags from BCP-47 standard, implemented by windows
- * https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
- * I have no fucking idea if this will work on linux. ¯\_(ツ)_/¯
- */
-
- TextTranslation.Language.ENGLISH => new CultureInfo("en"),
- TextTranslation.Language.SPANISH_LA => new CultureInfo("es-419"),
- TextTranslation.Language.GERMAN => new CultureInfo("de"),
- TextTranslation.Language.FRENCH => new CultureInfo("fr"),
- TextTranslation.Language.ITALIAN => new CultureInfo("it"),
- TextTranslation.Language.POLISH => new CultureInfo("pl"),
- TextTranslation.Language.PORTUGUESE_BR => new CultureInfo("pt-BR"),
- TextTranslation.Language.JAPANESE => new CultureInfo("ja"),
- TextTranslation.Language.RUSSIAN => new CultureInfo("ru"),
- TextTranslation.Language.CHINESE_SIMPLE => new CultureInfo("zh-Hans"),
- TextTranslation.Language.KOREAN => new CultureInfo("ko"),
- TextTranslation.Language.TURKISH => new CultureInfo("tr"),
- _ => new CultureInfo("en") // what
- };
}
diff --git a/QSB/Menus/MenuManager.cs b/QSB/Menus/MenuManager.cs
index 007e5910..22c78780 100644
--- a/QSB/Menus/MenuManager.cs
+++ b/QSB/Menus/MenuManager.cs
@@ -42,7 +42,7 @@ internal class MenuManager : MonoBehaviour, IAddComponentOnStart
private const int _titleButtonIndex = 2;
private float _connectPopupOpenTime;
- private const string UpdateChangelog = "QSB Version 0.22.0\r\nFixed lots of bugs, and added lots of SFX and VFX stuff.";
+ private const string UpdateChangelog = "QSB Version 0.23.0\r\nA lot of small improvements and bug fixes.";
private Action PopupClose;
diff --git a/QSB/ModelShip/Messages/UseFlightConsoleMessage.cs b/QSB/ModelShip/Messages/UseFlightConsoleMessage.cs
index 464e7f3b..f4abfe95 100644
--- a/QSB/ModelShip/Messages/UseFlightConsoleMessage.cs
+++ b/QSB/ModelShip/Messages/UseFlightConsoleMessage.cs
@@ -74,6 +74,9 @@ internal class UseFlightConsoleMessage : QSBMessage
// Client messes up its position when they start flying it
// We can just recall it immediately so its in the right place.
var console = QSBWorldSync.GetUnityObject();
- console.RespawnModelShip(false);
+ if (console._modelShipBody) // for when model ship is destroyed
+ {
+ console.RespawnModelShip(false);
+ }
}
}
diff --git a/QSB/ModelShip/ModelShipThrusterVariableSyncer.cs b/QSB/ModelShip/ModelShipThrusterVariableSyncer.cs
index 30c82784..3e896587 100644
--- a/QSB/ModelShip/ModelShipThrusterVariableSyncer.cs
+++ b/QSB/ModelShip/ModelShipThrusterVariableSyncer.cs
@@ -1,9 +1,6 @@
-using Mirror;
-using QSB.Player;
-using QSB.Utility;
+using QSB.Player;
+using QSB.Player.TransformSync;
using QSB.Utility.VariableSync;
-using System.Collections.Generic;
-using System.Linq;
using UnityEngine;
namespace QSB.ModelShip;
@@ -26,7 +23,7 @@ public class ModelShipThrusterVariableSyncer : MonoBehaviour
public void Update()
{
- if (QSBPlayerManager.LocalPlayer.FlyingModelShip)
+ if (PlayerTransformSync.LocalInstance && QSBPlayerManager.LocalPlayer.FlyingModelShip)
{
GetFromShip();
return;
diff --git a/QSB/Player/PlayerHUDMarker.cs b/QSB/Player/PlayerHUDMarker.cs
index 82131999..02e33c3c 100644
--- a/QSB/Player/PlayerHUDMarker.cs
+++ b/QSB/Player/PlayerHUDMarker.cs
@@ -1,4 +1,5 @@
-using QSB.Utility;
+using QSB.ServerSettings;
+using QSB.Utility;
using UnityEngine;
namespace QSB.Player;
@@ -34,7 +35,16 @@ public class PlayerHUDMarker : HUDDistanceMarker
return false;
}
- return _player.IsReady && !_player.IsDead && (!_player.InDreamWorld || QSBPlayerManager.LocalPlayer.InDreamWorld) && _player.Visible;
+ if (!ServerSettingsManager.ShowPlayerNames)
+ {
+ return false;
+ }
+
+ return _player.IsReady &&
+ !_player.IsDead &&
+ _player.Visible &&
+ _player.InDreamWorld == QSBPlayerManager.LocalPlayer.InDreamWorld &&
+ _player.IsInMoon == QSBPlayerManager.LocalPlayer.IsInMoon;
}
private void Update()
diff --git a/QSB/Player/PlayerInfo.cs b/QSB/Player/PlayerInfo.cs
index 06715acd..c6a0fe42 100644
--- a/QSB/Player/PlayerInfo.cs
+++ b/QSB/Player/PlayerInfo.cs
@@ -22,6 +22,7 @@ public partial class PlayerInfo
public uint PlayerId { get; }
public string Name { get; set; }
public PlayerHUDMarker HudMarker { get; set; }
+ public PlayerMapMarker MapMarker { get; set; }
public PlayerTransformSync TransformSync { get; }
public ClientState State { get; set; }
public EyeState EyeState { get; set; }
diff --git a/QSB/Player/PlayerInfoParts/DreamWorld.cs b/QSB/Player/PlayerInfoParts/DreamWorld.cs
index 4060de67..600150d4 100644
--- a/QSB/Player/PlayerInfoParts/DreamWorld.cs
+++ b/QSB/Player/PlayerInfoParts/DreamWorld.cs
@@ -1,4 +1,6 @@
-using QSB.ItemSync.WorldObjects.Items;
+using QSB.EchoesOfTheEye.DreamLantern;
+using QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
+using QSB.ItemSync.WorldObjects.Items;
namespace QSB.Player;
diff --git a/QSB/Player/PlayerMapMarker.cs b/QSB/Player/PlayerMapMarker.cs
index 4d35a734..417b7040 100644
--- a/QSB/Player/PlayerMapMarker.cs
+++ b/QSB/Player/PlayerMapMarker.cs
@@ -1,4 +1,5 @@
-using QSB.Utility;
+using QSB.ServerSettings;
+using QSB.Utility;
using UnityEngine;
namespace QSB.Player;
@@ -31,6 +32,7 @@ public class PlayerMapMarker : MonoBehaviour
public void Init(PlayerInfo player)
{
_player = player;
+ _player.MapMarker = this;
_hasBeenSetUpForInit = true;
}
@@ -57,10 +59,20 @@ public class PlayerMapMarker : MonoBehaviour
return false;
}
+ if (!ServerSettingsManager.ShowPlayerNames)
+ {
+ return false;
+ }
+
var playerScreenPos = Locator.GetActiveCamera().WorldToScreenPoint(transform.position);
var isInfrontOfCamera = playerScreenPos.z > 0f;
- return _player.IsReady && !_player.IsDead && (!_player.InDreamWorld || QSBPlayerManager.LocalPlayer.InDreamWorld) && _player.Visible && isInfrontOfCamera;
+ return isInfrontOfCamera &&
+ _player.IsReady &&
+ !_player.IsDead &&
+ _player.Visible &&
+ _player.InDreamWorld == QSBPlayerManager.LocalPlayer.InDreamWorld &&
+ _player.IsInMoon == QSBPlayerManager.LocalPlayer.IsInMoon;
}
public void LateUpdate()
@@ -77,4 +89,9 @@ public class PlayerMapMarker : MonoBehaviour
_canvasMarker.SetVisibility(shouldBeVisible);
}
}
+
+ public void Remove()
+ {
+ // TODO
+ }
}
\ No newline at end of file
diff --git a/QSB/Player/TransformSync/PlayerTransformSync.cs b/QSB/Player/TransformSync/PlayerTransformSync.cs
index ee2bc73d..c030693c 100644
--- a/QSB/Player/TransformSync/PlayerTransformSync.cs
+++ b/QSB/Player/TransformSync/PlayerTransformSync.cs
@@ -54,6 +54,7 @@ public class PlayerTransformSync : SectoredTransformSync
QSBPatch.Remote = false;
base.OnStopClient();
Player.HudMarker?.Remove();
+ Player.MapMarker?.Remove();
QSBPlayerManager.PlayerList.Remove(Player);
DebugLog.DebugWrite($"Remove Player : {Player}", MessageType.Info);
}
diff --git a/QSB/PlayerBodySetup/Remote/ShaderReplacer.cs b/QSB/PlayerBodySetup/Remote/ShaderReplacer.cs
index 29d20295..338b436b 100644
--- a/QSB/PlayerBodySetup/Remote/ShaderReplacer.cs
+++ b/QSB/PlayerBodySetup/Remote/ShaderReplacer.cs
@@ -27,7 +27,20 @@ public static class ShaderReplacer
continue;
}
- material.shader = replacementShader;
+ // preserve override tag and render queue (for Standard shader)
+ // keywords and properties are already preserved
+ if (material.renderQueue != material.shader.renderQueue)
+ {
+ var renderType = material.GetTag("RenderType", false);
+ var renderQueue = material.renderQueue;
+ material.shader = replacementShader;
+ material.SetOverrideTag("RenderType", renderType);
+ material.renderQueue = renderQueue;
+ }
+ else
+ {
+ material.shader = replacementShader;
+ }
}
}
}
diff --git a/QSB/QSB.csproj b/QSB/QSB.csproj
index f3bdfee4..177373de 100644
--- a/QSB/QSB.csproj
+++ b/QSB/QSB.csproj
@@ -7,17 +7,6 @@
CS1998;CS0649
-
-
- <_Files Remove="@(_Files)" />
- <_Files Include="$(OutputPath)\*.dll" />
- <_Files Include="$(OutputPath)\*.exe" />
- <_Files Include="$(OutputPath)\*.pdb" />
-
- <_Files Include="$(OutputPath)\AssetBundles\*" />
-
-
-
<_Files Remove="@(_Files)" />
@@ -31,33 +20,13 @@
- $(GameDir)\OuterWilds_Data\Managed
$(UnityAssetsDir)\Dlls
-
-
- <_Files Remove="@(_Files)" />
- <_Files Include="$(UnityDllsDir)\*.dll" />
- <_Files Include="$(UnityDllsDir)\*.exe" />
- <_Files Include="$(UnityDllsDir)\*.pdb" />
-
-
-
+
<_Files Remove="@(_Files)" />
<_Files Include="$(OutputPath)\*.dll" />
<_Files Include="$(OutputPath)\*.exe" />
- <_Files Include="$(OutputPath)\*.pdb" />
-
- <_Files Include="$(GameDllsDir)\EOS-SDK.dll" />
- <_Files Include="$(GameDllsDir)\Autofac.dll" />
- <_Files Include="$(GameDllsDir)\Newtonsoft.Json.dll" />
- <_Files Include="$(GameDllsDir)\0Harmony.dll" />
- <_Files Include="$(GameDllsDir)\MonoMod*.dll" />
- <_Files Include="$(GameDllsDir)\Mono.Cecil.dll" />
- <_Files Include="$(GameDllsDir)\OWML*.dll" />
- <_Files Include="$(GameDllsDir)\NAudio-Unity.dll" />
- <_Files Include="$(GameDllsDir)\com.rlabrecque.steamworks.net.dll" />
@@ -90,7 +59,7 @@
-
+
diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs
index b7107571..9cf2191f 100644
--- a/QSB/QSBCore.cs
+++ b/QSB/QSBCore.cs
@@ -4,9 +4,11 @@ using OWML.Common;
using OWML.ModHelper;
using QSB.Localization;
using QSB.Menus;
+using QSB.Messaging;
using QSB.Patches;
using QSB.QuantumSync;
using QSB.SaveSync;
+using QSB.ServerSettings;
using QSB.Utility;
using QSB.WorldSync;
using System;
@@ -56,6 +58,8 @@ public class QSBCore : ModBehaviour
Application.version.Split('.').Take(3).Join(delimiter: ".");
public static bool DLCInstalled => EntitlementsManager.IsDlcOwned() == EntitlementsManager.AsyncOwnershipStatus.Owned;
public static bool IncompatibleModsAllowed { get; private set; }
+ public static bool ShowPlayerNames { get; private set; }
+ public static bool ShipDamage { get; private set; }
public static GameVendor GameVendor { get; private set; } = GameVendor.None;
public static bool IsStandalone => GameVendor is GameVendor.Epic or GameVendor.Steam;
public static IProfileManager ProfileManager => IsStandalone
@@ -242,6 +246,14 @@ public class QSBCore : ModBehaviour
{
DefaultServerIP = config.GetSettingsValue("defaultServerIP");
IncompatibleModsAllowed = config.GetSettingsValue("incompatibleModsAllowed");
+ ShowPlayerNames = config.GetSettingsValue("showPlayerNames");
+ ShipDamage = config.GetSettingsValue("shipDamage");
+
+ if (IsHost)
+ {
+ ServerSettingsManager.ServerShowPlayerNames = ShowPlayerNames;
+ new ServerSettingsMessage().Send();
+ }
}
private void Update()
diff --git a/QSB/QSBNetworkManager.cs b/QSB/QSBNetworkManager.cs
index 28a05a52..9d920dbf 100644
--- a/QSB/QSBNetworkManager.cs
+++ b/QSB/QSBNetworkManager.cs
@@ -315,7 +315,11 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
Destroy(GetComponent());
Destroy(GetComponent());
Destroy(GetComponent());
- QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
+ QSBPlayerManager.PlayerList.ForEach(player =>
+ {
+ player.HudMarker?.Remove();
+ player.MapMarker?.Remove();
+ });
QSBWorldSync.RemoveWorldObjects();
@@ -397,7 +401,11 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
DebugLog.DebugWrite("OnStopServer", MessageType.Info);
Destroy(GetComponent());
DebugLog.ToConsole("Server stopped!", MessageType.Info);
- QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
+ QSBPlayerManager.PlayerList.ForEach(player =>
+ {
+ player.HudMarker?.Remove();
+ player.MapMarker?.Remove();
+ });
base.OnStopServer();
}
diff --git a/QSB/RespawnSync/RespawnHUDMarker.cs b/QSB/RespawnSync/RespawnHUDMarker.cs
index f9653a5a..f135d114 100644
--- a/QSB/RespawnSync/RespawnHUDMarker.cs
+++ b/QSB/RespawnSync/RespawnHUDMarker.cs
@@ -12,7 +12,7 @@ public class RespawnHUDMarker : HUDDistanceMarker
{
_markerRadius = 0.2f;
_markerTarget = transform;
- _markerLabel = QSBLocalization.Current.RespawnPlayer.ToUpper(QSBLocalization.CultureInfo);
+ _markerLabel = QSBLocalization.Current.RespawnPlayer.ToUpper();
_isReady = true;
base.InitCanvasMarker();
diff --git a/QSB/SaveSync/Messages/RequestGameStateMessage.cs b/QSB/SaveSync/Messages/RequestGameStateMessage.cs
index 42a24547..da49e43c 100644
--- a/QSB/SaveSync/Messages/RequestGameStateMessage.cs
+++ b/QSB/SaveSync/Messages/RequestGameStateMessage.cs
@@ -1,6 +1,7 @@
using QSB.ConversationSync.Messages;
using QSB.Messaging;
using QSB.Player;
+using QSB.ServerSettings;
using QSB.Utility;
namespace QSB.SaveSync.Messages;
@@ -21,6 +22,7 @@ internal class RequestGameStateMessage : QSBMessage
}
new GameStateMessage(From).Send();
+ new ServerSettingsMessage().Send();
var gameSave = PlayerData._currentGameSave;
diff --git a/QSB/ServerSettings/ServerSettingsManager.cs b/QSB/ServerSettings/ServerSettingsManager.cs
new file mode 100644
index 00000000..505f0ba2
--- /dev/null
+++ b/QSB/ServerSettings/ServerSettingsManager.cs
@@ -0,0 +1,10 @@
+using QSB.Utility;
+using UnityEngine;
+
+namespace QSB.ServerSettings;
+
+internal class ServerSettingsManager : MonoBehaviour, IAddComponentOnStart
+{
+ public static bool ServerShowPlayerNames;
+ public static bool ShowPlayerNames => (ServerShowPlayerNames || QSBCore.IsHost) && QSBCore.ShowPlayerNames;
+}
diff --git a/QSB/ServerSettings/ServerSettingsMessage.cs b/QSB/ServerSettings/ServerSettingsMessage.cs
new file mode 100644
index 00000000..1b88b00c
--- /dev/null
+++ b/QSB/ServerSettings/ServerSettingsMessage.cs
@@ -0,0 +1,27 @@
+using Mirror;
+using QSB.Messaging;
+
+namespace QSB.ServerSettings;
+
+internal class ServerSettingsMessage : QSBMessage
+{
+ private bool _showPlayerNames;
+
+ public ServerSettingsMessage()
+ => _showPlayerNames = QSBCore.ShowPlayerNames;
+
+ public override void Serialize(NetworkWriter writer)
+ {
+ base.Serialize(writer);
+ writer.Write(_showPlayerNames);
+ }
+
+ public override void Deserialize(NetworkReader reader)
+ {
+ base.Deserialize(reader);
+ _showPlayerNames = reader.ReadBool();
+ }
+
+ public override void OnReceiveRemote()
+ => ServerSettingsManager.ServerShowPlayerNames = _showPlayerNames;
+}
diff --git a/QSB/ShipSync/ShipThrusterVariableSyncer.cs b/QSB/ShipSync/ShipThrusterVariableSyncer.cs
index c8e31673..bb722be1 100644
--- a/QSB/ShipSync/ShipThrusterVariableSyncer.cs
+++ b/QSB/ShipSync/ShipThrusterVariableSyncer.cs
@@ -1,7 +1,7 @@
using Mirror;
using QSB.Player;
+using QSB.Player.TransformSync;
using QSB.Utility.VariableSync;
-using QSB.WorldSync;
using UnityEngine;
namespace QSB.ShipSync;
@@ -21,7 +21,7 @@ public class ShipThrusterVariableSyncer : NetworkBehaviour
public void Update()
{
- if (QSBPlayerManager.LocalPlayer.FlyingShip)
+ if (PlayerTransformSync.LocalInstance && QSBPlayerManager.LocalPlayer.FlyingShip)
{
GetFromShip();
return;
diff --git a/QSB/TimeSync/Patches/TimePatches.cs b/QSB/TimeSync/Patches/TimePatches.cs
index 24eab5fa..66d7899c 100644
--- a/QSB/TimeSync/Patches/TimePatches.cs
+++ b/QSB/TimeSync/Patches/TimePatches.cs
@@ -4,6 +4,7 @@ using QSB.Messaging;
using QSB.Patches;
using QSB.TimeSync.Messages;
using QSB.Utility;
+using UnityEngine;
namespace QSB.TimeSync.Patches;
@@ -25,8 +26,8 @@ internal class TimePatches : QSBPatch
public static void PlayerCameraEffectController_WakeUp(PlayerCameraEffectController __instance)
{
// prevent funny thing when you pause while waking up
- QSBInputManager.Instance.SetInputsEnabled(false);
- Delay.RunWhen(() => !__instance._isOpeningEyes, () => QSBInputManager.Instance.SetInputsEnabled(true));
+ Locator.GetPauseCommandListener().AddPauseCommandLock();
+ Delay.RunWhen(() => !__instance._isOpeningEyes, () => Locator.GetPauseCommandListener().RemovePauseCommandLock());
}
[HarmonyPrefix]
diff --git a/QSB/TimeSync/WakeUpSync.cs b/QSB/TimeSync/WakeUpSync.cs
index 8366a995..26479397 100644
--- a/QSB/TimeSync/WakeUpSync.cs
+++ b/QSB/TimeSync/WakeUpSync.cs
@@ -8,6 +8,7 @@ using QSB.Messaging;
using QSB.Player;
using QSB.Player.Messages;
using QSB.TimeSync.Messages;
+using QSB.TimeSync.Patches;
using QSB.Utility;
using QSB.WorldSync;
using System;
@@ -46,7 +47,6 @@ public class WakeUpSync : NetworkBehaviour
{
OWTime.SetTimeScale(1f);
OWTime.SetMaxDeltaTime(0.06666667f);
- OWTime.SetFixedTimestep(0.01666667f);
Locator.GetActiveCamera().enabled = true;
CurrentState = State.NotLoaded;
CurrentReason = null;
@@ -214,7 +214,6 @@ public class WakeUpSync : NetworkBehaviour
CurrentState = State.FastForwarding;
CurrentReason = reason;
OWTime.SetMaxDeltaTime(0.033333335f);
- OWTime.SetFixedTimestep(0.033333335f);
TimeSyncUI.TargetTime = _serverTime;
TimeSyncUI.Start(TimeSyncType.FastForwarding, reason);
}
@@ -245,7 +244,6 @@ public class WakeUpSync : NetworkBehaviour
{
OWTime.SetTimeScale(1f);
OWTime.SetMaxDeltaTime(0.06666667f);
- OWTime.SetFixedTimestep(0.01666667f);
Locator.GetActiveCamera().enabled = true;
CurrentState = State.Loaded;
CurrentReason = null;
diff --git a/QSB/Translations/zh_CN.json b/QSB/Translations/zh_CN.json
new file mode 100644
index 00000000..d64142b0
--- /dev/null
+++ b/QSB/Translations/zh_CN.json
@@ -0,0 +1,126 @@
+{
+ "Language": "CHINESE_SIMPLE",
+ "MainMenuHost": "开启多人游戏",
+ "MainMenuConnect": "连接至多人游戏",
+ "PauseMenuDisconnect": "断开连接",
+ "PauseMenuStopHosting": "关闭服务器",
+ "PublicIPAddress": "公共IP地址\n\n(您的多人存档数据将被覆盖)",
+ "ProductUserID": "用户ID\n\n(您的多人存档数据将被覆盖)",
+ "Connect": "连接",
+ "Cancel": "取消",
+ "HostExistingOrNewOrCopy": "您想使用一个现有的多人探险存档,或是开启一个新的存档,还是把现有的单人探险存档复制到多人探险存档?",
+ "HostNewOrCopy": "您想开启一个新的存档,还是把现有的单人探险存档复制到多人探险存档?",
+ "HostExistingOrNew": "您想使用一个现有的多人探险存档,还是开启一个新的存档?",
+ "ExistingSave": "现有存档",
+ "NewSave": "新建存档",
+ "CopySave": "复制存档",
+ "DisconnectAreYouSure": "您确定要断开连接吗?\n将会退出至主菜单。",
+ "Yes": "是",
+ "No": "否",
+ "StopHostingAreYouSure": "您确定要停止服务器吗?\n将会与所有人断开连接并且使他们退出至主菜单。",
+ "CopyProductUserIDToClipboard": "开启服务器\n其他玩家需要使用您的用户ID连接至服务器,用户ID是:\n{0}\n您想要复制到剪切板吗?",
+ "Connecting": "连接中……",
+ "OK": "好的",
+ "ServerRefusedConnection": "服务器拒绝了您的连接\n{0}",
+ "ClientDisconnectWithError": "客户端发生错误导致连接断开\n{0}",
+ "QSBVersionMismatch": "QSB版本号不匹配。(客户端:{0},服务端:{1})",
+ "OWVersionMismatch": "《星际拓荒》版本号不匹配。(客户端:{0},服务端:{1})",
+ "DLCMismatch": "DLC安装情况不匹配。(客户端:{0},服务端:{1})",
+ "GameProgressLimit": "游戏中时间太久了。",
+ "AddonMismatch": "插件不匹配(客户端:{0}插件,服务端:{1}插件)",
+ "IncompatibleMod": "使用了不兼容/不允许的模组,检测到的第一个模组是{0}",
+ "PlayerJoinedTheGame": "{0}加入了游戏!",
+ "PlayerWasKicked": "{0}被踢出了游戏。",
+ "KickedFromServer": "被踢出了游戏,理由是:{0}",
+ "RespawnPlayer": "复活玩家",
+ "TimeSyncTooFarBehind": "{0}\n快进以匹配服务器时间……",
+ "TimeSyncWaitingForStartOfServer": "等待服务器开始……",
+ "TimeSyncTooFarAhead": "{0}\n暂停等待以匹配服务器时间……",
+ "TimeSyncWaitForAllToReady": "等待开始轮回……",
+ "TimeSyncWaitForAllToDie": "等待轮回结束……",
+ "GalaxyMapEveryoneNotPresent": "现在还不是时候。需要所有人见证这个时刻。",
+ "YouAreDead": "你死了。",
+ "WaitingForRespawn": "等待某人将你复活……",
+ "WaitingForAllToDie": "等待{0}死亡……",
+ "AttachToShip": "固定在飞船上",
+ "DetachFromShip": "取消固定",
+ "DeathMessages": {
+ "Default": [
+ "{0}死了",
+ "{0}被杀了"
+ ],
+ "Impact": [
+ "{0}忘记使用推进器了",
+ "{0}拥抱了地面",
+ "{0}狠狠的撞上了地面",
+ "{0}爆炸了",
+ "{0}因为撞击而死",
+ "{0}撞击地面过猛"
+ ],
+ "Asphyxiation": [
+ "{0}忘记了需要呼吸",
+ "{0}窒息了",
+ "{0}窒息而死",
+ "{0}忘记了怎么呼吸",
+ "{0}忘记检查氧气了",
+ "{0}把空气用完了",
+ "{0}把氧气用完了",
+ "{0}不再需要呼吸了"
+ ],
+ "Energy": [
+ "{0}被烹饪了"
+ ],
+ "Supernova": [
+ "{0}没有时间了",
+ "{0}被烧掉了",
+ "{0}被超新星烤熟了",
+ "{0}升华了",
+ "{0}遗忘了时间"
+ ],
+ "Digestion": [
+ "{0}被吃掉了",
+ "{0}发现了一条鱼",
+ "{0}遇到了邪恶生物",
+ "{0}惹错了鱼",
+ "{0}被消化了",
+ "{0}因为消化系统而死"
+ ],
+ "Crushed": [
+ "{0}被压死了",
+ "{0}被压扁了",
+ "{0}埋葬了自己",
+ "{0}没能及时逃离",
+ "{0}想在沙子中游泳",
+ "{0}小看了沙子的力量",
+ "{0}卡在沙子下面了"
+ ],
+ "Lava": [
+ "{0}在岩浆中死去",
+ "{0}融化了",
+ "{0}尝试在岩浆中游泳",
+ "{0}掉进了岩浆",
+ "{0}因为岩浆而死",
+ "{0}在岩浆中游泳",
+ "{0}被岩浆烧毁"
+ ],
+ "BlackHole": [
+ "{0}尝试追寻自己的记忆"
+ ],
+ "DreamExplosion": [
+ "{0}爆炸了",
+ "{0}是第一个吃螃蟹的人",
+ "{0}被炸死了",
+ "{0}被炸了",
+ "{0}因为爆炸而死",
+ "{0}使用了错误的文物"
+ ],
+ "CrushedByElevator": [
+ "{0}被粉碎了",
+ "{0}被挤扁了",
+ "{0}被电梯撞击",
+ "{0}站在了电梯下",
+ "{0}变成了一个平板人",
+ "{0}被电梯挤扁了"
+ ]
+ }
+}
\ No newline at end of file
diff --git a/QSB/Utility/DebugActions.cs b/QSB/Utility/DebugActions.cs
index 46f85d5a..5f75a53c 100644
--- a/QSB/Utility/DebugActions.cs
+++ b/QSB/Utility/DebugActions.cs
@@ -1,4 +1,6 @@
using OWML.Common;
+using QSB.EchoesOfTheEye.DreamLantern;
+using QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
using QSB.ItemSync.WorldObjects.Items;
using QSB.Messaging;
using QSB.Player;
diff --git a/QSB/Utility/DebugLog.cs b/QSB/Utility/DebugLog.cs
index efbbfb5a..90badb74 100644
--- a/QSB/Utility/DebugLog.cs
+++ b/QSB/Utility/DebugLog.cs
@@ -5,6 +5,8 @@ using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
+#pragma warning disable CS0618
+
namespace QSB.Utility;
public static class DebugLog
diff --git a/QSB/Utility/DeterministicManager.cs b/QSB/Utility/DeterministicManager.cs
index c1982a1d..d6a71aef 100644
--- a/QSB/Utility/DeterministicManager.cs
+++ b/QSB/Utility/DeterministicManager.cs
@@ -31,11 +31,11 @@ public static class DeterministicManager
}
};
- public static void OnWorldObjectsReady()
+ public static void OnWorldObjectsAdded()
{
if (QSBCore.DebugSettings.DumpWorldObjects)
{
- using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, "world objects.csv")))
+ using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, $"[{DebugLog.ProcessInstanceId}] world objects.csv")))
{
file.WriteLine("world object,deterministic path");
foreach (var worldObject in QSBWorldSync.GetWorldObjects())
@@ -51,7 +51,7 @@ public static class DeterministicManager
}
}
- using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, "cache.csv")))
+ using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, $"[{DebugLog.ProcessInstanceId}] cache.csv")))
{
file.WriteLine("name,instance id,sibling index,parent,parent instance id");
foreach (var (transform, (siblingIndex, parent)) in _cache)
@@ -267,7 +267,7 @@ public static class DeterministicManager
}
///
- /// only call this before world objects ready
+ /// only call this before world objects added
///
public static string DeterministicPath(this Component component)
{
@@ -298,7 +298,7 @@ public static class DeterministicManager
}
///
- /// only call this before world objects ready
+ /// only call this before world objects added
///
public static IEnumerable SortDeterministic(this IEnumerable components) where T : Component
=> components.OrderBy(DeterministicPath);
diff --git a/QSB/Utility/Extensions.cs b/QSB/Utility/Extensions.cs
index 17c5c865..eede0565 100644
--- a/QSB/Utility/Extensions.cs
+++ b/QSB/Utility/Extensions.cs
@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
+using System.Text;
using UnityEngine;
using Object = UnityEngine.Object;
@@ -214,5 +215,23 @@ public static class Extensions
}
}
+ // https://stackoverflow.com/a/24031467
+ public static string GetMD5Hash(this IEnumerable list)
+ {
+ using var md5 = System.Security.Cryptography.MD5.Create();
+
+ var longString = string.Concat(list);
+ var bytes = Encoding.ASCII.GetBytes(longString);
+ var hashBytes = md5.ComputeHash(bytes);
+
+ var sb = new StringBuilder();
+ for (var i = 0; i < hashBytes.Length; i++)
+ {
+ sb.Append(hashBytes[i].ToString("X2"));
+ }
+
+ return sb.ToString();
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/QSB/Utility/ZOverride.cs b/QSB/Utility/ZOverride.cs
index 6966fcf2..98ae61e3 100644
--- a/QSB/Utility/ZOverride.cs
+++ b/QSB/Utility/ZOverride.cs
@@ -4,6 +4,7 @@ using UnityEngine.UI;
namespace QSB.Utility;
+[UsedInUnityProject]
public class ZOverride : MonoBehaviour
{
private const string shaderTestMode = "unity_GUIZTestMode";
diff --git a/QSB/WorldSync/QSBWorldSync.cs b/QSB/WorldSync/QSBWorldSync.cs
index 5d788f70..c57d6eeb 100644
--- a/QSB/WorldSync/QSBWorldSync.cs
+++ b/QSB/WorldSync/QSBWorldSync.cs
@@ -20,6 +20,7 @@ namespace QSB.WorldSync;
public static class QSBWorldSync
{
public static WorldObjectManager[] Managers;
+ public static string WorldObjectsHash { get; private set; }
///
/// Set when all WorldObjectManagers have called Init() on all their objects (AKA all the objects are created)
@@ -82,8 +83,14 @@ public static class QSBWorldSync
AllObjectsAdded = true;
DebugLog.DebugWrite("World Objects added.", MessageType.Success);
+ DeterministicManager.OnWorldObjectsAdded();
+
+ WorldObjectsHash = WorldObjects.Select(x => x.GetType().Name).GetMD5Hash();
+ DebugLog.DebugWrite($"WorldObject hash is {WorldObjectsHash}");
+
if (!QSBCore.IsHost)
{
+ new WorldObjectsHashMessage().Send();
new RequestLinksMessage().Send();
}
@@ -96,8 +103,6 @@ public static class QSBWorldSync
AllObjectsReady = true;
DebugLog.DebugWrite("World Objects ready.", MessageType.Success);
- DeterministicManager.OnWorldObjectsReady();
-
if (!QSBCore.IsHost)
{
new RequestInitialStatesMessage().Send();
@@ -247,7 +252,7 @@ public static class QSBWorldSync
if (WorldObjects[objectId] is not TWorldObject worldObject)
{
- DebugLog.ToConsole($"Error - {typeof(TWorldObject).Name} id {objectId} is actually {WorldObjects[objectId].GetType().Name}.", MessageType.Error);
+ DebugLog.ToConsole($"Error - WorldObject id {objectId} is {WorldObjects[objectId].GetType().Name}, expected {typeof(TWorldObject).Name}.", MessageType.Error);
return default;
}
diff --git a/QSB/WorldSync/WorldObjectsHashMessage.cs b/QSB/WorldSync/WorldObjectsHashMessage.cs
new file mode 100644
index 00000000..4d5e6bd2
--- /dev/null
+++ b/QSB/WorldSync/WorldObjectsHashMessage.cs
@@ -0,0 +1,30 @@
+using OWML.Common;
+using QSB.Messaging;
+using QSB.Player.Messages;
+using QSB.Utility;
+
+namespace QSB.WorldSync;
+
+///
+/// sends QSBWorldSync.WorldObjectsHash to the server for sanity checking
+///
+internal class WorldObjectsHashMessage : QSBMessage
+{
+ public WorldObjectsHashMessage() : base(QSBWorldSync.WorldObjectsHash) => To = 0;
+
+ public override void OnReceiveRemote()
+ {
+ var serverHash = QSBWorldSync.WorldObjectsHash;
+
+ if (serverHash != Data)
+ {
+ // oh fuck oh no oh god
+ DebugLog.ToConsole($"Kicking {From} because their WorldObjects hash is wrong. (server:{serverHash}, client:{Data})", MessageType.Error);
+ new PlayerKickMessage(From, $"WorldObject hash error. (Server:{serverHash}, Client:{Data})").Send();
+ }
+ else
+ {
+ DebugLog.DebugWrite($"WorldObject hash from {From} verified!", MessageType.Success);
+ }
+ }
+}
diff --git a/QSB/default-config.json b/QSB/default-config.json
index f78c880c..852343c8 100644
--- a/QSB/default-config.json
+++ b/QSB/default-config.json
@@ -1,7 +1,29 @@
{
"enabled": true,
"settings": {
- "defaultServerIP": "localhost",
- "incompatibleModsAllowed": false
+ "defaultServerIP": {
+ "title": "Last Entered IP/ID",
+ "type": "text",
+ "value": "localhost",
+ "tooltip": "Used if you leave the connect prompt blank."
+ },
+ "incompatibleModsAllowed": {
+ "title": "Incompatible Mods Allowed",
+ "type": "toggle",
+ "value": false,
+ "tooltip": "Kicks players if they have certain mods."
+ },
+ "showPlayerNames": {
+ "title": "Show Player Names",
+ "type": "toggle",
+ "value": true,
+ "tooltip": "Shows player names in the HUD and the map view."
+ },
+ "shipDamage": {
+ "title": "Ship Damage",
+ "type": "toggle",
+ "value": true,
+ "tooltip": "Take impact damage when inside the ship."
+ }
}
}
\ No newline at end of file
diff --git a/QSB/manifest.json b/QSB/manifest.json
index e0551f00..d78fe58b 100644
--- a/QSB/manifest.json
+++ b/QSB/manifest.json
@@ -7,8 +7,8 @@
"body": "- Disable *all* other mods. (Can heavily affect performance)\n- Make sure you are not running any other network-intensive applications."
},
"uniqueName": "Raicuparta.QuantumSpaceBuddies",
- "version": "0.22.0",
- "owmlVersion": "2.7.0",
+ "version": "0.23.0",
+ "owmlVersion": "2.8.0",
"dependencies": [ "_nebula.MenuFramework", "JohnCorby.VanillaFix" ],
"pathsToPreserve": [ "debugsettings.json", "storage.json" ]
}
diff --git a/README.md b/README.md
index 0c11f2cc..71fc9180 100644
--- a/README.md
+++ b/README.md
@@ -99,7 +99,6 @@ See [TRANSLATING.md](TRANSLATING.md)
- Clone QSB's source
- Open the file `DevEnv.targets` in your favorite text editor
- (optional if copying built dlls manually) Edit the entry `` to point to your OWML directory (it is installed inside the Mod Manager directory)
-- (optional if no unity project) Edit the entry `` to point to the directory where Outer Wilds is installed
- (optional if no unity project) Edit the entry `` to point to the Assets folder of the QSB unity project
- Open the project solution file `QSB.sln` in Visual Studio 2022
@@ -171,7 +170,7 @@ The template for this file is this :
### Authors
-- [\_nebula](https://github.com/misternebula) - Developer of v0.3 onwards
+- [\_nebula](https://github.com/misternebula) - Developer of v0.3.0 onwards
- [JohnCorby](https://github.com/JohnCorby) - Co-developer of v0.13.0 onwards.
- [AmazingAlek](https://github.com/amazingalek) - Developer of v0.1.0 - v0.7.1.
- [Raicuparta](https://github.com/Raicuparta) - Developer of v0.1.0 - v0.2.0.
@@ -180,9 +179,10 @@ The template for this file is this :
- [Chris Yeninas](https://github.com/PhantomGamers) - Help with project files and GitHub workflows.
- [Tlya](https://github.com/Tllya) - Russian translation.
-- [Xen](https://github.com/xen-42) - French translation.
+- [Xen](https://github.com/xen-42) - French translation, and help with particle effects and sounds.
- [ShoosGun](https://github.com/ShoosGun) - Portuguese translation.
- [DertolleDude](https://github.com/DertolleDude) - German translation.
+- [SakuradaYuki](https://github.com/SakuradaYuki) - Chinese translation.
### Special Thanks
- Thanks to Logan Ver Hoef for help with the game code, and for helping make the damn game in the first place.
diff --git a/TRANSLATING.md b/TRANSLATING.md
index ce4437c2..9cdf25b1 100644
--- a/TRANSLATING.md
+++ b/TRANSLATING.md
@@ -10,13 +10,13 @@ QSB can only be translated to the languages Outer Wilds supports - so if you don
- Russian
- Portuguese (Brazil)
- German
+- Chinese (Simplified)
### Un-translated languages :
- Spanish (Latin American)
- Italian
- Polish
- Japanese
-- Chinese (Simplified)
- Korean
- Turkish
@@ -38,4 +38,4 @@ Once you are happy with it, go to [this page](https://github.com/misternebula/qu
Scroll down to the "Propose new file" box. In the title box (default "Create new file") write something along the lines of "Add translation for (language)".
-Press the big green "Propose new file", and we'll review it soon!
\ No newline at end of file
+Press the big green "Propose new file", and we'll review it soon!