mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-02-06 00:39:55 +00:00
Merge branch 'dev' into nh-stuff
This commit is contained in:
commit
7113eec0e9
@ -4,6 +4,6 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" IncludeAssets="compile" />
|
||||
<PackageReference Include="OWML" Version="2.7.0" IncludeAssets="compile" />
|
||||
<PackageReference Include="OWML" Version="2.8.0" IncludeAssets="compile" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -4,7 +4,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" />
|
||||
<PackageReference Include="OWML" Version="2.7.0" />
|
||||
<PackageReference Include="OWML" Version="2.8.0" />
|
||||
<Reference Include="../Mirror/*.dll" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -39,6 +39,7 @@ public class AnimationSync : PlayerSyncObject
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
private void SendInitialState(uint to) => NetworkAnimator.Invoke("Awake");
|
||||
|
||||
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// don't take damage from impact in ship
|
||||
/// </summary>
|
||||
[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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// don't insta-die from impact in ship
|
||||
/// </summary>
|
||||
[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<ShipDamageController>().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<OWRigidbody>();
|
||||
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)
|
||||
|
@ -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<QSBAlarmTotem, AlarmTotem>();
|
||||
QSBWorldSync.Init<QSBAlarmTotem, AlarmTotem>();
|
||||
QSBWorldSync.Init<QSBAlarmBell, AlarmBell>();
|
||||
|
||||
_qsbAlarmSequenceController = new GameObject(nameof(QSBAlarmSequenceController))
|
||||
.AddComponent<QSBAlarmSequenceController>();
|
||||
DontDestroyOnLoad(_qsbAlarmSequenceController.gameObject);
|
||||
AlarmBells = QSBWorldSync.GetUnityObjects<AlarmBell>().Where(x => x._lightController).SortDeterministic().ToArray();
|
||||
}
|
||||
|
||||
public override void UnbuildWorldObjects() =>
|
||||
Destroy(_qsbAlarmSequenceController.gameObject);
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
||||
using QSB.Messaging;
|
||||
|
||||
namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
|
||||
|
||||
public class SetVisibleMessage : QSBWorldObjectMessage<QSBAlarmTotem, bool>
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
||||
using QSB.Messaging;
|
||||
|
||||
namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
|
||||
|
||||
public class TotemEnabledMessage : QSBWorldObjectMessage<QSBAlarmTotem, bool>
|
||||
{
|
||||
public TotemEnabledMessage(bool enabled) : base(enabled) { }
|
||||
|
||||
public override void OnReceiveRemote() =>
|
||||
WorldObject.SetEnabled(Data);
|
||||
}
|
@ -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<QSBAlarmTotem, List<uint>>
|
||||
{
|
||||
public TotemVisibleForMessage(List<uint> visibleFor) : base(visibleFor) { }
|
||||
|
||||
public override void OnReceiveRemote()
|
||||
{
|
||||
WorldObject.VisibleFor.Clear();
|
||||
WorldObject.VisibleFor.AddRange(Data);
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
||||
using QSB.Messaging;
|
||||
|
||||
namespace QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
|
||||
|
||||
public class TotemVisibleMessage : QSBWorldObjectMessage<QSBAlarmTotem, bool>
|
||||
{
|
||||
public TotemVisibleMessage(bool visible) : base(visible) { }
|
||||
public override void OnReceiveLocal() => OnReceiveRemote();
|
||||
public override void OnReceiveRemote() => WorldObject.SetVisible(From, Data);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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<QSBAlarmTotem>()
|
||||
.SendMessage(new TotemEnabledMessage(true));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sectorDetector.GetOccupantType() == DynamicOccupant.Player)
|
||||
{
|
||||
__instance.enabled = true;
|
||||
var qsbAlarmTotem = __instance.GetWorldObject<QSBAlarmTotem>();
|
||||
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<QSBAlarmTotem>()
|
||||
.SendMessage(new TotemEnabledMessage(false));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sectorDetector.GetOccupantType() == DynamicOccupant.Player)
|
||||
{
|
||||
__instance.enabled = false;
|
||||
var qsbAlarmTotem = __instance.GetWorldObject<QSBAlarmTotem>();
|
||||
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<QSBAlarmTotem>();
|
||||
|
||||
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))]
|
||||
|
@ -1,245 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace QSB.EchoesOfTheEye.AlarmTotemSync;
|
||||
|
||||
/// <summary>
|
||||
/// copied and modified from base game
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: make this not NRE (by not doing enable sync) and then readd it back in
|
||||
/// </summary>
|
||||
public class QSBAlarmTotem : WorldObject<AlarmTotem>
|
||||
public class QSBAlarmTotem : AuthWorldObject<AlarmTotem>
|
||||
{
|
||||
public readonly List<uint> 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 });
|
||||
}
|
||||
}
|
||||
|
114
QSB/EchoesOfTheEye/DreamWorld/Messages/DreamWorldFakePlayer.cs
Normal file
114
QSB/EchoesOfTheEye/DreamWorld/Messages/DreamWorldFakePlayer.cs
Normal file
@ -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<DreamWorldFakePlayer> _instances = new();
|
||||
|
||||
public static void Create(PlayerInfo player)
|
||||
{
|
||||
var go = new GameObject($"player {player} DreamWorldFakePlayer");
|
||||
go.SetActive(false);
|
||||
go.AddComponent<DreamWorldFakePlayer>()._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<Animator>());
|
||||
Destroy(fakePlayer.GetComponent<PlayerHeadRotationSync>());
|
||||
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// do this early to create the fake player BEFORE teleporting
|
||||
/// </summary>
|
||||
[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));
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -50,5 +50,8 @@ internal class ExitDreamWorldMessage : QSBMessage
|
||||
ghost.GetEffects().OnSectorOccupantsUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
Locator.GetAlarmSequenceController().OnExitDreamWorld();
|
||||
DreamWorldFakePlayer.Destroy(player);
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,6 @@ using UnityEngine;
|
||||
|
||||
namespace QSB;
|
||||
|
||||
/// <summary>
|
||||
/// TODO: TEST THIS. see if things horribly break. this could be huge.
|
||||
/// </summary>
|
||||
[HarmonyPatch(typeof(OWExtensions))]
|
||||
public class GetAttachedOWRigidbodyPatch : QSBPatch
|
||||
{
|
||||
|
@ -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<bool> PopupClose;
|
||||
|
||||
|
@ -74,6 +74,9 @@ internal class UseFlightConsoleMessage : QSBMessage<bool>
|
||||
// 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<RemoteFlightConsole>();
|
||||
console.RespawnModelShip(false);
|
||||
if (console._modelShipBody) // for when model ship is destroyed
|
||||
{
|
||||
console.RespawnModelShip(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 &&
|
||||
|
@ -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; }
|
||||
|
@ -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
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,7 +59,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" IncludeAssets="compile" />
|
||||
<PackageReference Include="OWML" Version="2.7.0" IncludeAssets="compile" />
|
||||
<PackageReference Include="OWML" Version="2.8.0" IncludeAssets="compile" />
|
||||
<Reference Include="..\Mirror\*.dll" />
|
||||
<Reference Include="..\UniTask\*.dll" />
|
||||
<ProjectReference Include="..\EpicOnlineTransport\EpicOnlineTransport.csproj" />
|
||||
|
@ -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<string>("defaultServerIP");
|
||||
IncompatibleModsAllowed = config.GetSettingsValue<bool>("incompatibleModsAllowed");
|
||||
ShowPlayerNames = config.GetSettingsValue<bool>("showPlayerNames");
|
||||
ShipDamage = config.GetSettingsValue<bool>("shipDamage");
|
||||
|
||||
if (IsHost)
|
||||
{
|
||||
ServerSettingsManager.ServerShowPlayerNames = ShowPlayerNames;
|
||||
new ServerSettingsMessage().Send();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
|
@ -315,7 +315,11 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
|
||||
Destroy(GetComponent<RespawnOnDeath>());
|
||||
Destroy(GetComponent<ServerStateManager>());
|
||||
Destroy(GetComponent<ClientStateManager>());
|
||||
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<RespawnOnDeath>());
|
||||
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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
10
QSB/ServerSettings/ServerSettingsManager.cs
Normal file
10
QSB/ServerSettings/ServerSettingsManager.cs
Normal file
@ -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;
|
||||
}
|
27
QSB/ServerSettings/ServerSettingsMessage.cs
Normal file
27
QSB/ServerSettings/ServerSettingsMessage.cs
Normal file
@ -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;
|
||||
}
|
@ -4,6 +4,7 @@ using QSB.Messaging;
|
||||
using QSB.Patches;
|
||||
using QSB.TimeSync.Messages;
|
||||
using QSB.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
namespace QSB.TimeSync.Patches;
|
||||
|
||||
|
@ -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;
|
||||
|
126
QSB/Translations/zh_CN.json
Normal file
126
QSB/Translations/zh_CN.json
Normal file
@ -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}被电梯挤扁了"
|
||||
]
|
||||
}
|
||||
}
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
@ -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" ]
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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!
|
||||
Press the big green "Propose new file", and we'll review it soon!
|
||||
|
Loading…
x
Reference in New Issue
Block a user