diff --git a/EpicRerouter/EpicRerouter.csproj b/EpicRerouter/EpicRerouter.csproj index 3cff5ff9..f52659e0 100644 --- a/EpicRerouter/EpicRerouter.csproj +++ b/EpicRerouter/EpicRerouter.csproj @@ -4,6 +4,6 @@ - + diff --git a/MirrorWeaver/MirrorWeaver.csproj b/MirrorWeaver/MirrorWeaver.csproj index 61a05999..6e06d15e 100644 --- a/MirrorWeaver/MirrorWeaver.csproj +++ b/MirrorWeaver/MirrorWeaver.csproj @@ -4,7 +4,7 @@ - + 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/DeathSync/Patches/DeathPatches.cs b/QSB/DeathSync/Patches/DeathPatches.cs index 2b1fe4a1..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); } } @@ -141,15 +91,10 @@ public class DeathPatches : QSBPatch Achievements.Earn(Achievements.Type.EARLY_ADOPTER); } - if (PlayerState.InDreamWorld()) + if (PlayerState.InDreamWorld() && deathType != DeathType.Dream && deathType != DeathType.DreamExplosion && deathType != DeathType.Supernova && deathType != DeathType.TimeLoop && deathType != DeathType.Meditation) { - // exit dream world either way to prevent goof with respawn - // TODO: test Locator.GetDreamWorldController().ExitDreamWorld(deathType); - if (deathType != DeathType.Dream && deathType != DeathType.DreamExplosion && deathType != DeathType.Supernova && deathType != DeathType.TimeLoop && deathType != DeathType.Meditation) - { - return; - } + return; } if (!@this._isDying) 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/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 b0c1dbd9..7bd9b6ad 100644 --- a/QSB/EchoesOfTheEye/DreamWorld/Messages/EnterDreamWorldMessage.cs +++ b/QSB/EchoesOfTheEye/DreamWorld/Messages/EnterDreamWorldMessage.cs @@ -1,7 +1,5 @@ -using QSB.EchoesOfTheEye.DreamLantern; -using QSB.EchoesOfTheEye.DreamLantern.WorldObjects; +using QSB.EchoesOfTheEye.DreamLantern.WorldObjects; using QSB.EchoesOfTheEye.Ghosts.WorldObjects; -using QSB.ItemSync.WorldObjects.Items; 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/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/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/Player/PlayerHUDMarker.cs b/QSB/Player/PlayerHUDMarker.cs index ebcc7e04..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,6 +35,11 @@ public class PlayerHUDMarker : HUDDistanceMarker return false; } + if (!ServerSettingsManager.ShowPlayerNames) + { + return false; + } + return _player.IsReady && !_player.IsDead && _player.Visible && 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/PlayerMapMarker.cs b/QSB/Player/PlayerMapMarker.cs index 6904b095..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,6 +59,11 @@ public class PlayerMapMarker : MonoBehaviour return false; } + if (!ServerSettingsManager.ShowPlayerNames) + { + return false; + } + var playerScreenPos = Locator.GetActiveCamera().WorldToScreenPoint(transform.position); var isInfrontOfCamera = playerScreenPos.z > 0f; @@ -82,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 69f05fbb..338b436b 100644 --- a/QSB/PlayerBodySetup/Remote/ShaderReplacer.cs +++ b/QSB/PlayerBodySetup/Remote/ShaderReplacer.cs @@ -29,11 +29,18 @@ public static class ShaderReplacer // preserve override tag and render queue (for Standard shader) // keywords and properties are already preserved - var renderType = material.GetTag("RenderType", false); - var renderQueue = material.renderQueue; - material.shader = replacementShader; - material.SetOverrideTag("RenderType", renderType); - material.renderQueue = renderQueue; + 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 8bfae7dd..177373de 100644 --- a/QSB/QSB.csproj +++ b/QSB/QSB.csproj @@ -59,7 +59,7 @@ - + diff --git a/QSB/QSBCore.cs b/QSB/QSBCore.cs index 32ff5fa1..48e9137c 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 @@ -247,6 +251,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/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/TimeSync/Patches/TimePatches.cs b/QSB/TimeSync/Patches/TimePatches.cs index 3b807a19..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; 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/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 c49e7688..d78fe58b 100644 --- a/QSB/manifest.json +++ b/QSB/manifest.json @@ -8,7 +8,7 @@ }, "uniqueName": "Raicuparta.QuantumSpaceBuddies", "version": "0.23.0", - "owmlVersion": "2.7.0", + "owmlVersion": "2.8.0", "dependencies": [ "_nebula.MenuFramework", "JohnCorby.VanillaFix" ], "pathsToPreserve": [ "debugsettings.json", "storage.json" ] } diff --git a/README.md b/README.md index e0980867..71fc9180 100644 --- a/README.md +++ b/README.md @@ -170,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. @@ -179,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!