mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-01-30 03:32:47 +00:00
commit
c19536eaec
@ -16,7 +16,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Label="Default Locations" Condition="!Exists('$(DevEnvLoc)')">
|
<PropertyGroup Label="Default Locations" Condition="!Exists('$(DevEnvLoc)')">
|
||||||
<GameDir>C:\Program Files\Epic Games\OuterWilds</GameDir>
|
|
||||||
<OwmlDir>$(AppData)\OuterWildsModManager\OWML</OwmlDir>
|
<OwmlDir>$(AppData)\OuterWildsModManager\OWML</OwmlDir>
|
||||||
<UnityAssetsDir>$(SolutionDir)\qsb-unityproject\Assets</UnityAssetsDir>
|
<UnityAssetsDir>$(SolutionDir)\qsb-unityproject\Assets</UnityAssetsDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -39,6 +39,7 @@ public class AnimationSync : PlayerSyncObject
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// This wipes the NetworkAnimator's fields, so it assumes the parameters have changed.
|
/// This wipes the NetworkAnimator's fields, so it assumes the parameters have changed.
|
||||||
/// Basically just forces it to set all its dirty flags.
|
/// 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>
|
/// </summary>
|
||||||
private void SendInitialState(uint to) => NetworkAnimator.Invoke("Awake");
|
private void SendInitialState(uint to) => NetworkAnimator.Invoke("Awake");
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
using UnityEngine;
|
using QSB.Utility;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.ConversationSync;
|
namespace QSB.ConversationSync;
|
||||||
|
|
||||||
|
[UsedInUnityProject]
|
||||||
public class CameraFacingBillboard : MonoBehaviour
|
public class CameraFacingBillboard : MonoBehaviour
|
||||||
{
|
{
|
||||||
private OWCamera _activeCam;
|
private OWCamera _activeCam;
|
||||||
|
@ -3,7 +3,6 @@ using QSB.DeathSync.Messages;
|
|||||||
using QSB.Messaging;
|
using QSB.Messaging;
|
||||||
using QSB.Patches;
|
using QSB.Patches;
|
||||||
using QSB.Player;
|
using QSB.Player;
|
||||||
using QSB.Utility;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -14,96 +13,47 @@ public class DeathPatches : QSBPatch
|
|||||||
{
|
{
|
||||||
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// don't take damage from impact in ship
|
||||||
|
/// </summary>
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(PlayerResources), nameof(PlayerResources.OnImpact))]
|
[HarmonyPatch(typeof(PlayerResources), nameof(PlayerResources.OnImpact))]
|
||||||
public static bool PlayerResources_OnImpact(PlayerResources __instance, ImpactData impact) =>
|
public static bool PlayerResources_OnImpact(PlayerResources __instance, ImpactData impact)
|
||||||
// don't take damage from impact in ship
|
{
|
||||||
!PlayerState.IsInsideShip();
|
if (QSBCore.ShipDamage)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !PlayerState.IsInsideShip();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// don't insta-die from impact in ship
|
/// don't insta-die from impact in ship
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(HighSpeedImpactSensor), nameof(HighSpeedImpactSensor.FixedUpdate))]
|
[HarmonyPatch(typeof(HighSpeedImpactSensor), nameof(HighSpeedImpactSensor.HandlePlayerInsideShip))]
|
||||||
public static bool HighSpeedImpactSensor_FixedUpdate(HighSpeedImpactSensor __instance)
|
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._body.SetPosition(shipCenter);
|
||||||
__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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (__instance._isPlayer && PlayerState.IsInsideShip())
|
if (!__instance._dead)
|
||||||
{
|
{
|
||||||
var shipCenter = Locator.GetShipTransform().position + Locator.GetShipTransform().up * 2f;
|
var a = __instance._body.GetVelocity() - Locator.GetShipBody().GetPointVelocity(__instance._body.GetPosition());
|
||||||
var distanceFromShip = Vector3.Distance(__instance._body.GetPosition(), shipCenter);
|
if (a.sqrMagnitude > __instance._sqrCheckSpeedThreshold)
|
||||||
if (distanceFromShip > 8f)
|
|
||||||
{
|
{
|
||||||
__instance._body.SetPosition(shipCenter);
|
__instance._impactSpeed = a.magnitude;
|
||||||
}
|
__instance._body.AddVelocityChange(-a);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
||||||
|
using QSB.Utility;
|
||||||
using QSB.WorldSync;
|
using QSB.WorldSync;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace QSB.EchoesOfTheEye.AlarmTotemSync;
|
namespace QSB.EchoesOfTheEye.AlarmTotemSync;
|
||||||
|
|
||||||
@ -11,18 +12,12 @@ public class AlarmTotemManager : WorldObjectManager
|
|||||||
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
|
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
|
||||||
public override bool DlcOnly => true;
|
public override bool DlcOnly => true;
|
||||||
|
|
||||||
private QSBAlarmSequenceController _qsbAlarmSequenceController;
|
public static AlarmBell[] AlarmBells;
|
||||||
|
|
||||||
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
|
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
|
||||||
{
|
{
|
||||||
// QSBWorldSync.Init<QSBAlarmTotem, AlarmTotem>();
|
QSBWorldSync.Init<QSBAlarmTotem, AlarmTotem>();
|
||||||
QSBWorldSync.Init<QSBAlarmBell, AlarmBell>();
|
QSBWorldSync.Init<QSBAlarmBell, AlarmBell>();
|
||||||
|
AlarmBells = QSBWorldSync.GetUnityObjects<AlarmBell>().Where(x => x._lightController).SortDeterministic().ToArray();
|
||||||
_qsbAlarmSequenceController = new GameObject(nameof(QSBAlarmSequenceController))
|
|
||||||
.AddComponent<QSBAlarmSequenceController>();
|
|
||||||
DontDestroyOnLoad(_qsbAlarmSequenceController.gameObject);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 HarmonyLib;
|
||||||
|
using QSB.AuthoritySync;
|
||||||
using QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
|
using QSB.EchoesOfTheEye.AlarmTotemSync.Messages;
|
||||||
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
using QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
||||||
using QSB.Messaging;
|
using QSB.Messaging;
|
||||||
using QSB.Patches;
|
using QSB.Patches;
|
||||||
|
using QSB.Player;
|
||||||
|
using QSB.Utility;
|
||||||
using QSB.WorldSync;
|
using QSB.WorldSync;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -12,27 +15,58 @@ public class AlarmTotemPatches : QSBPatch
|
|||||||
{
|
{
|
||||||
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
||||||
|
|
||||||
/*
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(AlarmTotem), nameof(AlarmTotem.OnSectorOccupantAdded))]
|
[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>()
|
return true;
|
||||||
.SendMessage(new TotemEnabledMessage(true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sectorDetector.GetOccupantType() == DynamicOccupant.Player)
|
||||||
|
{
|
||||||
|
__instance.enabled = true;
|
||||||
|
var qsbAlarmTotem = __instance.GetWorldObject<QSBAlarmTotem>();
|
||||||
|
qsbAlarmTotem.RequestOwnership();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(AlarmTotem), nameof(AlarmTotem.OnSectorOccupantRemoved))]
|
[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>()
|
return true;
|
||||||
.SendMessage(new TotemEnabledMessage(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]
|
[HarmonyPrefix]
|
||||||
@ -43,45 +77,87 @@ public class AlarmTotemPatches : QSBPatch
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var qsbAlarmTotem = __instance.GetWorldObject<QSBAlarmTotem>();
|
var qsbAlarmTotem = __instance.GetWorldObject<QSBAlarmTotem>();
|
||||||
|
|
||||||
var isLocallyVisible = qsbAlarmTotem.IsLocallyVisible;
|
if (qsbAlarmTotem.Owner != QSBPlayerManager.LocalPlayerId)
|
||||||
qsbAlarmTotem.IsLocallyVisible = __instance.CheckPlayerVisible();
|
|
||||||
if (qsbAlarmTotem.IsLocallyVisible && !isLocallyVisible)
|
|
||||||
{
|
{
|
||||||
qsbAlarmTotem.SendMessage(new TotemVisibleMessage(true));
|
return false;
|
||||||
}
|
|
||||||
else if (isLocallyVisible && !qsbAlarmTotem.IsLocallyVisible)
|
|
||||||
{
|
|
||||||
qsbAlarmTotem.SendMessage(new TotemVisibleMessage(false));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isPlayerVisible = __instance._isPlayerVisible;
|
var isPlayerVisible = __instance._isPlayerVisible;
|
||||||
__instance._isPlayerVisible = qsbAlarmTotem.VisibleFor.Count > 0;
|
__instance._isPlayerVisible = __instance.CheckPlayerVisible();
|
||||||
if (__instance._isPlayerVisible && !isPlayerVisible)
|
if (!isPlayerVisible && __instance._isPlayerVisible)
|
||||||
{
|
{
|
||||||
Locator.GetAlarmSequenceController().IncreaseAlarmCounter();
|
Locator.GetAlarmSequenceController().IncreaseAlarmCounter();
|
||||||
|
__instance._secondsConcealed = 0f;
|
||||||
__instance._simTotemMaterials[0] = __instance._simAlarmMaterial;
|
__instance._simTotemMaterials[0] = __instance._simAlarmMaterial;
|
||||||
__instance._simTotemRenderer.sharedMaterials = __instance._simTotemMaterials;
|
__instance._simTotemRenderer.sharedMaterials = __instance._simTotemMaterials;
|
||||||
__instance._simVisionConeRenderer.SetColor(__instance._simAlarmColor);
|
__instance._simVisionConeRenderer.SetColor(__instance._simAlarmColor);
|
||||||
if (__instance._isTutorialTotem)
|
GlobalMessenger.FireEvent("AlarmTotemTriggered");
|
||||||
{
|
qsbAlarmTotem.SendMessage(new SetVisibleMessage(true));
|
||||||
GlobalMessenger.FireEvent("TutorialAlarmTotemTriggered");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (isPlayerVisible && !__instance._isPlayerVisible)
|
else if (isPlayerVisible && !__instance._isPlayerVisible)
|
||||||
{
|
{
|
||||||
Locator.GetAlarmSequenceController().DecreaseAlarmCounter();
|
Locator.GetAlarmSequenceController().DecreaseAlarmCounter();
|
||||||
|
__instance._secondsConcealed = 0f;
|
||||||
__instance._simTotemMaterials[0] = __instance._origSimEyeMaterial;
|
__instance._simTotemMaterials[0] = __instance._origSimEyeMaterial;
|
||||||
__instance._simTotemRenderer.sharedMaterials = __instance._simTotemMaterials;
|
__instance._simTotemRenderer.sharedMaterials = __instance._simTotemMaterials;
|
||||||
__instance._simVisionConeRenderer.SetColor(__instance._simVisionConeRenderer.GetOriginalColor());
|
__instance._simVisionConeRenderer.SetColor(__instance._simVisionConeRenderer.GetOriginalColor());
|
||||||
__instance._pulseLightController.FadeTo(0f, 0.5f);
|
__instance._pulseLightController.FadeTo(0f, 0.5f);
|
||||||
|
qsbAlarmTotem.SendMessage(new SetVisibleMessage(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
return 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]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(AlarmBell), nameof(AlarmBell.OnEntry))]
|
[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.EchoesOfTheEye.AlarmTotemSync.Messages;
|
||||||
using QSB.Messaging;
|
using QSB.Messaging;
|
||||||
using QSB.Player;
|
|
||||||
using QSB.WorldSync;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
namespace QSB.EchoesOfTheEye.AlarmTotemSync.WorldObjects;
|
||||||
|
|
||||||
/// <summary>
|
public class QSBAlarmTotem : AuthWorldObject<AlarmTotem>
|
||||||
/// TODO: make this not NRE (by not doing enable sync) and then readd it back in
|
|
||||||
/// </summary>
|
|
||||||
public class QSBAlarmTotem : WorldObject<AlarmTotem>
|
|
||||||
{
|
{
|
||||||
public readonly List<uint> VisibleFor = new();
|
public override bool CanOwn => AttachedObject.enabled;
|
||||||
public bool IsLocallyVisible;
|
|
||||||
|
|
||||||
public override void SendInitialState(uint to)
|
public override void SendInitialState(uint to)
|
||||||
{
|
{
|
||||||
this.SendMessage(new TotemEnabledMessage(AttachedObject.enabled) { To = to });
|
base.SendInitialState(to);
|
||||||
this.SendMessage(new TotemVisibleForMessage(VisibleFor) { To = to });
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async UniTask Init(CancellationToken ct) =>
|
this.SendMessage(new SetVisibleMessage(AttachedObject._isPlayerVisible) { To = to });
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,9 @@ public class DreamLanternManager : WorldObjectManager
|
|||||||
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
|
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
|
||||||
public override bool DlcOnly => true;
|
public override bool DlcOnly => true;
|
||||||
|
|
||||||
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) =>
|
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct)
|
||||||
|
{
|
||||||
QSBWorldSync.Init<QSBDreamLanternController, DreamLanternController>();
|
QSBWorldSync.Init<QSBDreamLanternController, DreamLanternController>();
|
||||||
|
QSBWorldSync.Init<QSBDreamLanternItem, DreamLanternItem>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
|
using QSB.ItemSync.WorldObjects.Items;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.ItemSync.WorldObjects.Items;
|
namespace QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
|
||||||
|
|
||||||
public class QSBDreamLanternItem : QSBItem<DreamLanternItem>
|
public class QSBDreamLanternItem : QSBItem<DreamLanternItem>
|
||||||
{
|
{
|
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,5 +1,5 @@
|
|||||||
using QSB.EchoesOfTheEye.Ghosts.WorldObjects;
|
using QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
|
||||||
using QSB.ItemSync.WorldObjects.Items;
|
using QSB.EchoesOfTheEye.Ghosts.WorldObjects;
|
||||||
using QSB.Messaging;
|
using QSB.Messaging;
|
||||||
using QSB.Player;
|
using QSB.Player;
|
||||||
using QSB.Player.TransformSync;
|
using QSB.Player.TransformSync;
|
||||||
|
@ -50,5 +50,8 @@ internal class ExitDreamWorldMessage : QSBMessage
|
|||||||
ghost.GetEffects().OnSectorOccupantsUpdated();
|
ghost.GetEffects().OnSectorOccupantsUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Locator.GetAlarmSequenceController().OnExitDreamWorld();
|
||||||
|
DreamWorldFakePlayer.Destroy(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@ namespace QSB.EchoesOfTheEye.RaftSync.Messages;
|
|||||||
|
|
||||||
public class RaftDockOnPressInteractMessage : QSBWorldObjectMessage<QSBRaftDock>
|
public class RaftDockOnPressInteractMessage : QSBWorldObjectMessage<QSBRaftDock>
|
||||||
{
|
{
|
||||||
public override void OnReceiveRemote() => WorldObject.OnPressInteract();
|
public override void OnReceiveRemote() => WorldObject.AttachedObject.OnPressInteract();
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,4 @@ namespace QSB.EchoesOfTheEye.RaftSync.WorldObjects;
|
|||||||
public class QSBRaftDock : WorldObject<RaftDock>, IQSBDropTarget
|
public class QSBRaftDock : WorldObject<RaftDock>, IQSBDropTarget
|
||||||
{
|
{
|
||||||
IItemDropTarget IQSBDropTarget.AttachedObject => AttachedObject;
|
IItemDropTarget IQSBDropTarget.AttachedObject => AttachedObject;
|
||||||
|
|
||||||
public void OnPressInteract() => AttachedObject.OnPressInteract();
|
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ public class QSBSarcophagus : WorldObject<SarcophagusController>
|
|||||||
{
|
{
|
||||||
public override void SendInitialState(uint to)
|
public override void SendInitialState(uint to)
|
||||||
{
|
{
|
||||||
if (AttachedObject._isOpen)
|
if (AttachedObject._isOpen || AttachedObject._isSlightlyOpen)
|
||||||
{
|
{
|
||||||
this.SendMessage(new OpenMessage());
|
this.SendMessage(new OpenMessage());
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
using QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
|
||||||
|
using QSB.Messaging;
|
||||||
|
|
||||||
|
namespace QSB.EchoesOfTheEye.VisionTorch.Messages;
|
||||||
|
|
||||||
|
public class VisionTorchProjectMessage : QSBWorldObjectMessage<QSBVisionTorchItem, bool>
|
||||||
|
{
|
||||||
|
public VisionTorchProjectMessage(bool projecting) : base(projecting) { }
|
||||||
|
|
||||||
|
public override void OnReceiveRemote()
|
||||||
|
{
|
||||||
|
WorldObject.AttachedObject._isProjecting = Data;
|
||||||
|
WorldObject.AttachedObject._mindProjectorTrigger.SetProjectorActive(Data);
|
||||||
|
// prevent the torch from actually doing things remotely
|
||||||
|
WorldObject.AttachedObject.mindProjectorTrigger._triggerVolume.SetTriggerActivation(false);
|
||||||
|
}
|
||||||
|
}
|
45
QSB/EchoesOfTheEye/VisionTorch/Patches/VisionTorchPatches.cs
Normal file
45
QSB/EchoesOfTheEye/VisionTorch/Patches/VisionTorchPatches.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using QSB.EchoesOfTheEye.VisionTorch.Messages;
|
||||||
|
using QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
|
||||||
|
using QSB.Messaging;
|
||||||
|
using QSB.Patches;
|
||||||
|
using QSB.WorldSync;
|
||||||
|
|
||||||
|
namespace QSB.EchoesOfTheEye.VisionTorch.Patches;
|
||||||
|
|
||||||
|
public class VisionTorchPatches : QSBPatch
|
||||||
|
{
|
||||||
|
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
||||||
|
|
||||||
|
[HarmonyPrefix]
|
||||||
|
[HarmonyPatch(typeof(VisionTorchItem), nameof(VisionTorchItem.Update))]
|
||||||
|
private static bool Update(VisionTorchItem __instance)
|
||||||
|
{
|
||||||
|
if (!QSBWorldSync.AllObjectsReady)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PlayerState.IsViewingProjector() && __instance._mindSlideProjector.mindSlideCollection.slideCollectionContainer.slideIndex == 1)
|
||||||
|
{
|
||||||
|
OWInput.ChangeInputMode(InputMode.None);
|
||||||
|
__instance._mindSlideProjector.OnProjectionComplete += __instance.OnProjectionComplete;
|
||||||
|
__instance.enabled = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
__instance._wasProjecting = __instance._isProjecting;
|
||||||
|
__instance._isProjecting = OWInput.IsPressed(InputLibrary.toolActionPrimary, InputMode.Character);
|
||||||
|
if (__instance._isProjecting && !__instance._wasProjecting)
|
||||||
|
{
|
||||||
|
__instance._mindProjectorTrigger.SetProjectorActive(true);
|
||||||
|
__instance.GetWorldObject<QSBVisionTorchItem>().SendMessage(new VisionTorchProjectMessage(true));
|
||||||
|
}
|
||||||
|
else if (!__instance._isProjecting && __instance._wasProjecting)
|
||||||
|
{
|
||||||
|
__instance._mindProjectorTrigger.SetProjectorActive(false);
|
||||||
|
__instance.GetWorldObject<QSBVisionTorchItem>().SendMessage(new VisionTorchProjectMessage(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
15
QSB/EchoesOfTheEye/VisionTorch/VisionTorchManager.cs
Normal file
15
QSB/EchoesOfTheEye/VisionTorch/VisionTorchManager.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
|
||||||
|
using QSB.WorldSync;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace QSB.EchoesOfTheEye.VisionTorch;
|
||||||
|
|
||||||
|
public class VisionTorchManager : WorldObjectManager
|
||||||
|
{
|
||||||
|
public override WorldObjectScene WorldObjectScene => WorldObjectScene.SolarSystem;
|
||||||
|
public override bool DlcOnly => true;
|
||||||
|
|
||||||
|
public override async UniTask BuildWorldObjects(OWScene scene, CancellationToken ct) =>
|
||||||
|
QSBWorldSync.Init<QSBVisionTorchItem, VisionTorchItem>();
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
using QSB.EchoesOfTheEye.VisionTorch.Messages;
|
||||||
|
using QSB.ItemSync.WorldObjects.Items;
|
||||||
|
using QSB.Messaging;
|
||||||
|
|
||||||
|
namespace QSB.EchoesOfTheEye.VisionTorch.WorldObjects;
|
||||||
|
|
||||||
|
public class QSBVisionTorchItem : QSBItem<VisionTorchItem>
|
||||||
|
{
|
||||||
|
public override void SendInitialState(uint to)
|
||||||
|
{
|
||||||
|
this.SendMessage(new VisionTorchProjectMessage(AttachedObject._isProjecting) { To = to });
|
||||||
|
}
|
||||||
|
}
|
@ -4,9 +4,6 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace QSB;
|
namespace QSB;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TODO: TEST THIS. see if things horribly break. this could be huge.
|
|
||||||
/// </summary>
|
|
||||||
[HarmonyPatch(typeof(OWExtensions))]
|
[HarmonyPatch(typeof(OWExtensions))]
|
||||||
public class GetAttachedOWRigidbodyPatch : QSBPatch
|
public class GetAttachedOWRigidbodyPatch : QSBPatch
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,23 @@ internal class InputPatches : QSBPatch
|
|||||||
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
public override QSBPatchTypes Type => QSBPatchTypes.OnClientConnect;
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
[HarmonyPatch(typeof(OWInput), nameof(OWInput.Update))]
|
[HarmonyPatch(typeof(AbstractCommands), nameof(AbstractCommands.Update))]
|
||||||
public static bool OWInput_Update()
|
public static bool AbstractCommands_Update(AbstractCommands __instance)
|
||||||
=> QSBInputManager.Instance.InputsEnabled;
|
{
|
||||||
|
if (QSBInputManager.Instance.InputsEnabled)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__instance.Consumed = false;
|
||||||
|
__instance.WasActiveLastFrame = __instance.IsActiveThisFrame;
|
||||||
|
__instance.IsActiveThisFrame = false;
|
||||||
|
|
||||||
|
if (__instance.WasActiveLastFrame)
|
||||||
|
{
|
||||||
|
__instance.InputStartedTime = float.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
@ -5,7 +5,6 @@ using QSB.ItemSync.WorldObjects.Items;
|
|||||||
using QSB.ItemSync.WorldObjects.Sockets;
|
using QSB.ItemSync.WorldObjects.Sockets;
|
||||||
using QSB.Utility;
|
using QSB.Utility;
|
||||||
using QSB.WorldSync;
|
using QSB.WorldSync;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@ -21,14 +20,13 @@ internal class ItemManager : WorldObjectManager
|
|||||||
DebugLog.DebugWrite("Building OWItems...", MessageType.Info);
|
DebugLog.DebugWrite("Building OWItems...", MessageType.Info);
|
||||||
|
|
||||||
// Items
|
// Items
|
||||||
QSBWorldSync.Init<QSBDreamLanternItem, DreamLanternItem>();
|
|
||||||
QSBWorldSync.Init<QSBNomaiConversationStone, NomaiConversationStone>();
|
QSBWorldSync.Init<QSBNomaiConversationStone, NomaiConversationStone>();
|
||||||
QSBWorldSync.Init<QSBScrollItem, ScrollItem>();
|
QSBWorldSync.Init<QSBScrollItem, ScrollItem>();
|
||||||
QSBWorldSync.Init<QSBSharedStone, SharedStone>();
|
QSBWorldSync.Init<QSBSharedStone, SharedStone>();
|
||||||
QSBWorldSync.Init<QSBSimpleLanternItem, SimpleLanternItem>();
|
QSBWorldSync.Init<QSBSimpleLanternItem, SimpleLanternItem>();
|
||||||
QSBWorldSync.Init<QSBSlideReelItem, SlideReelItem>();
|
QSBWorldSync.Init<QSBSlideReelItem, SlideReelItem>();
|
||||||
QSBWorldSync.Init<QSBVisionTorchItem, VisionTorchItem>();
|
|
||||||
QSBWorldSync.Init<QSBWarpCoreItem, WarpCoreItem>();
|
QSBWorldSync.Init<QSBWarpCoreItem, WarpCoreItem>();
|
||||||
|
// dream lantern and vision torch are set up in their own managers
|
||||||
|
|
||||||
// Sockets
|
// Sockets
|
||||||
QSBWorldSync.Init<QSBItemSocket, OWItemSocket>();
|
QSBWorldSync.Init<QSBItemSocket, OWItemSocket>();
|
||||||
|
@ -149,6 +149,12 @@ internal class ItemRemotePatches : QSBPatch
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (__instance._isProjecting)
|
||||||
|
{
|
||||||
|
__instance._mindProjectorTrigger.SetProjectorActive(false);
|
||||||
|
__instance._isProjecting = false;
|
||||||
|
}
|
||||||
|
|
||||||
// if (Locator.GetDreamWorldController().IsInDream())
|
// if (Locator.GetDreamWorldController().IsInDream())
|
||||||
// {
|
// {
|
||||||
base_DropItem(__instance, position, normal, parent, sector, customDropTarget);
|
base_DropItem(__instance, position, normal, parent, sector, customDropTarget);
|
||||||
@ -213,6 +219,12 @@ internal class ItemRemotePatches : QSBPatch
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (__instance._isProjecting)
|
||||||
|
{
|
||||||
|
__instance._mindProjectorTrigger.SetProjectorActive(false);
|
||||||
|
__instance._isProjecting = false;
|
||||||
|
}
|
||||||
|
|
||||||
base_SocketItem(__instance, socketTransform, sector);
|
base_SocketItem(__instance, socketTransform, sector);
|
||||||
if (__instance._visionBeam != null)
|
if (__instance._visionBeam != null)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
namespace QSB.ItemSync.WorldObjects.Items;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// TODO: SYNC THIS SHIT LMAOOOOOO
|
|
||||||
/// </summary>
|
|
||||||
internal class QSBVisionTorchItem : QSBItem<VisionTorchItem> { }
|
|
@ -2,7 +2,6 @@
|
|||||||
using QSB.Utility;
|
using QSB.Utility;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@ -82,28 +81,4 @@ public static class QSBLocalization
|
|||||||
Current = newTranslation;
|
Current = newTranslation;
|
||||||
LanguageChanged?.Invoke();
|
LanguageChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CultureInfo CultureInfo
|
|
||||||
=> Current.Language switch
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Language tags from BCP-47 standard, implemented by windows
|
|
||||||
* https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
|
|
||||||
* I have no fucking idea if this will work on linux. ¯\_(ツ)_/¯
|
|
||||||
*/
|
|
||||||
|
|
||||||
TextTranslation.Language.ENGLISH => new CultureInfo("en"),
|
|
||||||
TextTranslation.Language.SPANISH_LA => new CultureInfo("es-419"),
|
|
||||||
TextTranslation.Language.GERMAN => new CultureInfo("de"),
|
|
||||||
TextTranslation.Language.FRENCH => new CultureInfo("fr"),
|
|
||||||
TextTranslation.Language.ITALIAN => new CultureInfo("it"),
|
|
||||||
TextTranslation.Language.POLISH => new CultureInfo("pl"),
|
|
||||||
TextTranslation.Language.PORTUGUESE_BR => new CultureInfo("pt-BR"),
|
|
||||||
TextTranslation.Language.JAPANESE => new CultureInfo("ja"),
|
|
||||||
TextTranslation.Language.RUSSIAN => new CultureInfo("ru"),
|
|
||||||
TextTranslation.Language.CHINESE_SIMPLE => new CultureInfo("zh-Hans"),
|
|
||||||
TextTranslation.Language.KOREAN => new CultureInfo("ko"),
|
|
||||||
TextTranslation.Language.TURKISH => new CultureInfo("tr"),
|
|
||||||
_ => new CultureInfo("en") // what
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ internal class MenuManager : MonoBehaviour, IAddComponentOnStart
|
|||||||
private const int _titleButtonIndex = 2;
|
private const int _titleButtonIndex = 2;
|
||||||
private float _connectPopupOpenTime;
|
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;
|
private Action<bool> PopupClose;
|
||||||
|
|
||||||
|
@ -74,6 +74,9 @@ internal class UseFlightConsoleMessage : QSBMessage<bool>
|
|||||||
// Client messes up its position when they start flying it
|
// Client messes up its position when they start flying it
|
||||||
// We can just recall it immediately so its in the right place.
|
// We can just recall it immediately so its in the right place.
|
||||||
var console = QSBWorldSync.GetUnityObject<RemoteFlightConsole>();
|
var console = QSBWorldSync.GetUnityObject<RemoteFlightConsole>();
|
||||||
console.RespawnModelShip(false);
|
if (console._modelShipBody) // for when model ship is destroyed
|
||||||
|
{
|
||||||
|
console.RespawnModelShip(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
using Mirror;
|
using QSB.Player;
|
||||||
using QSB.Player;
|
using QSB.Player.TransformSync;
|
||||||
using QSB.Utility;
|
|
||||||
using QSB.Utility.VariableSync;
|
using QSB.Utility.VariableSync;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.ModelShip;
|
namespace QSB.ModelShip;
|
||||||
@ -26,7 +23,7 @@ public class ModelShipThrusterVariableSyncer : MonoBehaviour
|
|||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
if (QSBPlayerManager.LocalPlayer.FlyingModelShip)
|
if (PlayerTransformSync.LocalInstance && QSBPlayerManager.LocalPlayer.FlyingModelShip)
|
||||||
{
|
{
|
||||||
GetFromShip();
|
GetFromShip();
|
||||||
return;
|
return;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using QSB.Utility;
|
using QSB.ServerSettings;
|
||||||
|
using QSB.Utility;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.Player;
|
namespace QSB.Player;
|
||||||
@ -34,7 +35,16 @@ public class PlayerHUDMarker : HUDDistanceMarker
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _player.IsReady && !_player.IsDead && (!_player.InDreamWorld || QSBPlayerManager.LocalPlayer.InDreamWorld) && _player.Visible;
|
if (!ServerSettingsManager.ShowPlayerNames)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _player.IsReady &&
|
||||||
|
!_player.IsDead &&
|
||||||
|
_player.Visible &&
|
||||||
|
_player.InDreamWorld == QSBPlayerManager.LocalPlayer.InDreamWorld &&
|
||||||
|
_player.IsInMoon == QSBPlayerManager.LocalPlayer.IsInMoon;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
|
@ -22,6 +22,7 @@ public partial class PlayerInfo
|
|||||||
public uint PlayerId { get; }
|
public uint PlayerId { get; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public PlayerHUDMarker HudMarker { get; set; }
|
public PlayerHUDMarker HudMarker { get; set; }
|
||||||
|
public PlayerMapMarker MapMarker { get; set; }
|
||||||
public PlayerTransformSync TransformSync { get; }
|
public PlayerTransformSync TransformSync { get; }
|
||||||
public ClientState State { get; set; }
|
public ClientState State { get; set; }
|
||||||
public EyeState EyeState { get; set; }
|
public EyeState EyeState { get; set; }
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using QSB.ItemSync.WorldObjects.Items;
|
using QSB.EchoesOfTheEye.DreamLantern;
|
||||||
|
using QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
|
||||||
|
using QSB.ItemSync.WorldObjects.Items;
|
||||||
|
|
||||||
namespace QSB.Player;
|
namespace QSB.Player;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using QSB.Utility;
|
using QSB.ServerSettings;
|
||||||
|
using QSB.Utility;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.Player;
|
namespace QSB.Player;
|
||||||
@ -31,6 +32,7 @@ public class PlayerMapMarker : MonoBehaviour
|
|||||||
public void Init(PlayerInfo player)
|
public void Init(PlayerInfo player)
|
||||||
{
|
{
|
||||||
_player = player;
|
_player = player;
|
||||||
|
_player.MapMarker = this;
|
||||||
_hasBeenSetUpForInit = true;
|
_hasBeenSetUpForInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,10 +59,20 @@ public class PlayerMapMarker : MonoBehaviour
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ServerSettingsManager.ShowPlayerNames)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var playerScreenPos = Locator.GetActiveCamera().WorldToScreenPoint(transform.position);
|
var playerScreenPos = Locator.GetActiveCamera().WorldToScreenPoint(transform.position);
|
||||||
var isInfrontOfCamera = playerScreenPos.z > 0f;
|
var isInfrontOfCamera = playerScreenPos.z > 0f;
|
||||||
|
|
||||||
return _player.IsReady && !_player.IsDead && (!_player.InDreamWorld || QSBPlayerManager.LocalPlayer.InDreamWorld) && _player.Visible && isInfrontOfCamera;
|
return isInfrontOfCamera &&
|
||||||
|
_player.IsReady &&
|
||||||
|
!_player.IsDead &&
|
||||||
|
_player.Visible &&
|
||||||
|
_player.InDreamWorld == QSBPlayerManager.LocalPlayer.InDreamWorld &&
|
||||||
|
_player.IsInMoon == QSBPlayerManager.LocalPlayer.IsInMoon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LateUpdate()
|
public void LateUpdate()
|
||||||
@ -77,4 +89,9 @@ public class PlayerMapMarker : MonoBehaviour
|
|||||||
_canvasMarker.SetVisibility(shouldBeVisible);
|
_canvasMarker.SetVisibility(shouldBeVisible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Remove()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
@ -54,6 +54,7 @@ public class PlayerTransformSync : SectoredTransformSync
|
|||||||
QSBPatch.Remote = false;
|
QSBPatch.Remote = false;
|
||||||
base.OnStopClient();
|
base.OnStopClient();
|
||||||
Player.HudMarker?.Remove();
|
Player.HudMarker?.Remove();
|
||||||
|
Player.MapMarker?.Remove();
|
||||||
QSBPlayerManager.PlayerList.Remove(Player);
|
QSBPlayerManager.PlayerList.Remove(Player);
|
||||||
DebugLog.DebugWrite($"Remove Player : {Player}", MessageType.Info);
|
DebugLog.DebugWrite($"Remove Player : {Player}", MessageType.Info);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,20 @@ public static class ShaderReplacer
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
material.shader = replacementShader;
|
// preserve override tag and render queue (for Standard shader)
|
||||||
|
// keywords and properties are already preserved
|
||||||
|
if (material.renderQueue != material.shader.renderQueue)
|
||||||
|
{
|
||||||
|
var renderType = material.GetTag("RenderType", false);
|
||||||
|
var renderQueue = material.renderQueue;
|
||||||
|
material.shader = replacementShader;
|
||||||
|
material.SetOverrideTag("RenderType", renderType);
|
||||||
|
material.renderQueue = renderQueue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
material.shader = replacementShader;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,6 @@
|
|||||||
<NoWarn>CS1998;CS0649</NoWarn>
|
<NoWarn>CS1998;CS0649</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<Target Name="clean before building" BeforeTargets="PreBuildEvent">
|
|
||||||
<ItemGroup>
|
|
||||||
<_Files Remove="@(_Files)" />
|
|
||||||
<_Files Include="$(OutputPath)\*.dll" />
|
|
||||||
<_Files Include="$(OutputPath)\*.exe" />
|
|
||||||
<_Files Include="$(OutputPath)\*.pdb" />
|
|
||||||
|
|
||||||
<_Files Include="$(OutputPath)\AssetBundles\*" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Delete Files="@(_Files)" />
|
|
||||||
</Target>
|
|
||||||
<Target Name="clean after building" AfterTargets="PostBuildEvent">
|
<Target Name="clean after building" AfterTargets="PostBuildEvent">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<_Files Remove="@(_Files)" />
|
<_Files Remove="@(_Files)" />
|
||||||
@ -31,33 +20,13 @@
|
|||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<GameDllsDir Condition="Exists('$(GameDir)')">$(GameDir)\OuterWilds_Data\Managed</GameDllsDir>
|
|
||||||
<UnityDllsDir Condition="Exists('$(UnityAssetsDir)')">$(UnityAssetsDir)\Dlls</UnityDllsDir>
|
<UnityDllsDir Condition="Exists('$(UnityAssetsDir)')">$(UnityAssetsDir)\Dlls</UnityDllsDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Target Name="copy dlls to unity" AfterTargets="PostBuildEvent" Condition="Exists('$(UnityDllsDir)') and Exists('$(GameDllsDir)')">
|
<Target Name="copy dlls to unity" AfterTargets="PostBuildEvent" Condition="Exists('$(UnityDllsDir)')">
|
||||||
<ItemGroup>
|
|
||||||
<_Files Remove="@(_Files)" />
|
|
||||||
<_Files Include="$(UnityDllsDir)\*.dll" />
|
|
||||||
<_Files Include="$(UnityDllsDir)\*.exe" />
|
|
||||||
<_Files Include="$(UnityDllsDir)\*.pdb" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Delete Files="@(_Files)" />
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<_Files Remove="@(_Files)" />
|
<_Files Remove="@(_Files)" />
|
||||||
<_Files Include="$(OutputPath)\*.dll" />
|
<_Files Include="$(OutputPath)\*.dll" />
|
||||||
<_Files Include="$(OutputPath)\*.exe" />
|
<_Files Include="$(OutputPath)\*.exe" />
|
||||||
<_Files Include="$(OutputPath)\*.pdb" />
|
|
||||||
|
|
||||||
<_Files Include="$(GameDllsDir)\EOS-SDK.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\Autofac.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\Newtonsoft.Json.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\0Harmony.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\MonoMod*.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\Mono.Cecil.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\OWML*.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\NAudio-Unity.dll" />
|
|
||||||
<_Files Include="$(GameDllsDir)\com.rlabrecque.steamworks.net.dll" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Copy SourceFiles="@(_Files)" DestinationFolder="$(UnityDllsDir)" />
|
<Copy SourceFiles="@(_Files)" DestinationFolder="$(UnityDllsDir)" />
|
||||||
</Target>
|
</Target>
|
||||||
@ -90,7 +59,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="OuterWildsGameLibs" Version="1.1.13.393" IncludeAssets="compile" />
|
<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="..\Mirror\*.dll" />
|
||||||
<Reference Include="..\UniTask\*.dll" />
|
<Reference Include="..\UniTask\*.dll" />
|
||||||
<ProjectReference Include="..\EpicOnlineTransport\EpicOnlineTransport.csproj" />
|
<ProjectReference Include="..\EpicOnlineTransport\EpicOnlineTransport.csproj" />
|
||||||
|
@ -4,9 +4,11 @@ using OWML.Common;
|
|||||||
using OWML.ModHelper;
|
using OWML.ModHelper;
|
||||||
using QSB.Localization;
|
using QSB.Localization;
|
||||||
using QSB.Menus;
|
using QSB.Menus;
|
||||||
|
using QSB.Messaging;
|
||||||
using QSB.Patches;
|
using QSB.Patches;
|
||||||
using QSB.QuantumSync;
|
using QSB.QuantumSync;
|
||||||
using QSB.SaveSync;
|
using QSB.SaveSync;
|
||||||
|
using QSB.ServerSettings;
|
||||||
using QSB.Utility;
|
using QSB.Utility;
|
||||||
using QSB.WorldSync;
|
using QSB.WorldSync;
|
||||||
using System;
|
using System;
|
||||||
@ -56,6 +58,8 @@ public class QSBCore : ModBehaviour
|
|||||||
Application.version.Split('.').Take(3).Join(delimiter: ".");
|
Application.version.Split('.').Take(3).Join(delimiter: ".");
|
||||||
public static bool DLCInstalled => EntitlementsManager.IsDlcOwned() == EntitlementsManager.AsyncOwnershipStatus.Owned;
|
public static bool DLCInstalled => EntitlementsManager.IsDlcOwned() == EntitlementsManager.AsyncOwnershipStatus.Owned;
|
||||||
public static bool IncompatibleModsAllowed { get; private set; }
|
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 GameVendor GameVendor { get; private set; } = GameVendor.None;
|
||||||
public static bool IsStandalone => GameVendor is GameVendor.Epic or GameVendor.Steam;
|
public static bool IsStandalone => GameVendor is GameVendor.Epic or GameVendor.Steam;
|
||||||
public static IProfileManager ProfileManager => IsStandalone
|
public static IProfileManager ProfileManager => IsStandalone
|
||||||
@ -242,6 +246,14 @@ public class QSBCore : ModBehaviour
|
|||||||
{
|
{
|
||||||
DefaultServerIP = config.GetSettingsValue<string>("defaultServerIP");
|
DefaultServerIP = config.GetSettingsValue<string>("defaultServerIP");
|
||||||
IncompatibleModsAllowed = config.GetSettingsValue<bool>("incompatibleModsAllowed");
|
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()
|
private void Update()
|
||||||
|
@ -315,7 +315,11 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
|
|||||||
Destroy(GetComponent<RespawnOnDeath>());
|
Destroy(GetComponent<RespawnOnDeath>());
|
||||||
Destroy(GetComponent<ServerStateManager>());
|
Destroy(GetComponent<ServerStateManager>());
|
||||||
Destroy(GetComponent<ClientStateManager>());
|
Destroy(GetComponent<ClientStateManager>());
|
||||||
QSBPlayerManager.PlayerList.ForEach(player => player.HudMarker?.Remove());
|
QSBPlayerManager.PlayerList.ForEach(player =>
|
||||||
|
{
|
||||||
|
player.HudMarker?.Remove();
|
||||||
|
player.MapMarker?.Remove();
|
||||||
|
});
|
||||||
|
|
||||||
QSBWorldSync.RemoveWorldObjects();
|
QSBWorldSync.RemoveWorldObjects();
|
||||||
|
|
||||||
@ -397,7 +401,11 @@ public class QSBNetworkManager : NetworkManager, IAddComponentOnStart
|
|||||||
DebugLog.DebugWrite("OnStopServer", MessageType.Info);
|
DebugLog.DebugWrite("OnStopServer", MessageType.Info);
|
||||||
Destroy(GetComponent<RespawnOnDeath>());
|
Destroy(GetComponent<RespawnOnDeath>());
|
||||||
DebugLog.ToConsole("Server stopped!", MessageType.Info);
|
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();
|
base.OnStopServer();
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ public class RespawnHUDMarker : HUDDistanceMarker
|
|||||||
{
|
{
|
||||||
_markerRadius = 0.2f;
|
_markerRadius = 0.2f;
|
||||||
_markerTarget = transform;
|
_markerTarget = transform;
|
||||||
_markerLabel = QSBLocalization.Current.RespawnPlayer.ToUpper(QSBLocalization.CultureInfo);
|
_markerLabel = QSBLocalization.Current.RespawnPlayer.ToUpper();
|
||||||
_isReady = true;
|
_isReady = true;
|
||||||
|
|
||||||
base.InitCanvasMarker();
|
base.InitCanvasMarker();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using QSB.ConversationSync.Messages;
|
using QSB.ConversationSync.Messages;
|
||||||
using QSB.Messaging;
|
using QSB.Messaging;
|
||||||
using QSB.Player;
|
using QSB.Player;
|
||||||
|
using QSB.ServerSettings;
|
||||||
using QSB.Utility;
|
using QSB.Utility;
|
||||||
|
|
||||||
namespace QSB.SaveSync.Messages;
|
namespace QSB.SaveSync.Messages;
|
||||||
@ -21,6 +22,7 @@ internal class RequestGameStateMessage : QSBMessage
|
|||||||
}
|
}
|
||||||
|
|
||||||
new GameStateMessage(From).Send();
|
new GameStateMessage(From).Send();
|
||||||
|
new ServerSettingsMessage().Send();
|
||||||
|
|
||||||
var gameSave = PlayerData._currentGameSave;
|
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;
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using Mirror;
|
using Mirror;
|
||||||
using QSB.Player;
|
using QSB.Player;
|
||||||
|
using QSB.Player.TransformSync;
|
||||||
using QSB.Utility.VariableSync;
|
using QSB.Utility.VariableSync;
|
||||||
using QSB.WorldSync;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.ShipSync;
|
namespace QSB.ShipSync;
|
||||||
@ -21,7 +21,7 @@ public class ShipThrusterVariableSyncer : NetworkBehaviour
|
|||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
if (QSBPlayerManager.LocalPlayer.FlyingShip)
|
if (PlayerTransformSync.LocalInstance && QSBPlayerManager.LocalPlayer.FlyingShip)
|
||||||
{
|
{
|
||||||
GetFromShip();
|
GetFromShip();
|
||||||
return;
|
return;
|
||||||
|
@ -4,6 +4,7 @@ using QSB.Messaging;
|
|||||||
using QSB.Patches;
|
using QSB.Patches;
|
||||||
using QSB.TimeSync.Messages;
|
using QSB.TimeSync.Messages;
|
||||||
using QSB.Utility;
|
using QSB.Utility;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace QSB.TimeSync.Patches;
|
namespace QSB.TimeSync.Patches;
|
||||||
|
|
||||||
@ -25,8 +26,8 @@ internal class TimePatches : QSBPatch
|
|||||||
public static void PlayerCameraEffectController_WakeUp(PlayerCameraEffectController __instance)
|
public static void PlayerCameraEffectController_WakeUp(PlayerCameraEffectController __instance)
|
||||||
{
|
{
|
||||||
// prevent funny thing when you pause while waking up
|
// prevent funny thing when you pause while waking up
|
||||||
QSBInputManager.Instance.SetInputsEnabled(false);
|
Locator.GetPauseCommandListener().AddPauseCommandLock();
|
||||||
Delay.RunWhen(() => !__instance._isOpeningEyes, () => QSBInputManager.Instance.SetInputsEnabled(true));
|
Delay.RunWhen(() => !__instance._isOpeningEyes, () => Locator.GetPauseCommandListener().RemovePauseCommandLock());
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPrefix]
|
[HarmonyPrefix]
|
||||||
|
@ -8,6 +8,7 @@ using QSB.Messaging;
|
|||||||
using QSB.Player;
|
using QSB.Player;
|
||||||
using QSB.Player.Messages;
|
using QSB.Player.Messages;
|
||||||
using QSB.TimeSync.Messages;
|
using QSB.TimeSync.Messages;
|
||||||
|
using QSB.TimeSync.Patches;
|
||||||
using QSB.Utility;
|
using QSB.Utility;
|
||||||
using QSB.WorldSync;
|
using QSB.WorldSync;
|
||||||
using System;
|
using System;
|
||||||
@ -46,7 +47,6 @@ public class WakeUpSync : NetworkBehaviour
|
|||||||
{
|
{
|
||||||
OWTime.SetTimeScale(1f);
|
OWTime.SetTimeScale(1f);
|
||||||
OWTime.SetMaxDeltaTime(0.06666667f);
|
OWTime.SetMaxDeltaTime(0.06666667f);
|
||||||
OWTime.SetFixedTimestep(0.01666667f);
|
|
||||||
Locator.GetActiveCamera().enabled = true;
|
Locator.GetActiveCamera().enabled = true;
|
||||||
CurrentState = State.NotLoaded;
|
CurrentState = State.NotLoaded;
|
||||||
CurrentReason = null;
|
CurrentReason = null;
|
||||||
@ -214,7 +214,6 @@ public class WakeUpSync : NetworkBehaviour
|
|||||||
CurrentState = State.FastForwarding;
|
CurrentState = State.FastForwarding;
|
||||||
CurrentReason = reason;
|
CurrentReason = reason;
|
||||||
OWTime.SetMaxDeltaTime(0.033333335f);
|
OWTime.SetMaxDeltaTime(0.033333335f);
|
||||||
OWTime.SetFixedTimestep(0.033333335f);
|
|
||||||
TimeSyncUI.TargetTime = _serverTime;
|
TimeSyncUI.TargetTime = _serverTime;
|
||||||
TimeSyncUI.Start(TimeSyncType.FastForwarding, reason);
|
TimeSyncUI.Start(TimeSyncType.FastForwarding, reason);
|
||||||
}
|
}
|
||||||
@ -245,7 +244,6 @@ public class WakeUpSync : NetworkBehaviour
|
|||||||
{
|
{
|
||||||
OWTime.SetTimeScale(1f);
|
OWTime.SetTimeScale(1f);
|
||||||
OWTime.SetMaxDeltaTime(0.06666667f);
|
OWTime.SetMaxDeltaTime(0.06666667f);
|
||||||
OWTime.SetFixedTimestep(0.01666667f);
|
|
||||||
Locator.GetActiveCamera().enabled = true;
|
Locator.GetActiveCamera().enabled = true;
|
||||||
CurrentState = State.Loaded;
|
CurrentState = State.Loaded;
|
||||||
CurrentReason = null;
|
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,4 +1,6 @@
|
|||||||
using OWML.Common;
|
using OWML.Common;
|
||||||
|
using QSB.EchoesOfTheEye.DreamLantern;
|
||||||
|
using QSB.EchoesOfTheEye.DreamLantern.WorldObjects;
|
||||||
using QSB.ItemSync.WorldObjects.Items;
|
using QSB.ItemSync.WorldObjects.Items;
|
||||||
using QSB.Messaging;
|
using QSB.Messaging;
|
||||||
using QSB.Player;
|
using QSB.Player;
|
||||||
|
@ -5,6 +5,8 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
#pragma warning disable CS0618
|
||||||
|
|
||||||
namespace QSB.Utility;
|
namespace QSB.Utility;
|
||||||
|
|
||||||
public static class DebugLog
|
public static class DebugLog
|
||||||
|
@ -31,11 +31,11 @@ public static class DeterministicManager
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static void OnWorldObjectsReady()
|
public static void OnWorldObjectsAdded()
|
||||||
{
|
{
|
||||||
if (QSBCore.DebugSettings.DumpWorldObjects)
|
if (QSBCore.DebugSettings.DumpWorldObjects)
|
||||||
{
|
{
|
||||||
using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, "world objects.csv")))
|
using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, $"[{DebugLog.ProcessInstanceId}] world objects.csv")))
|
||||||
{
|
{
|
||||||
file.WriteLine("world object,deterministic path");
|
file.WriteLine("world object,deterministic path");
|
||||||
foreach (var worldObject in QSBWorldSync.GetWorldObjects())
|
foreach (var worldObject in QSBWorldSync.GetWorldObjects())
|
||||||
@ -51,7 +51,7 @@ public static class DeterministicManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, "cache.csv")))
|
using (var file = File.CreateText(Path.Combine(QSBCore.Helper.Manifest.ModFolderPath, $"[{DebugLog.ProcessInstanceId}] cache.csv")))
|
||||||
{
|
{
|
||||||
file.WriteLine("name,instance id,sibling index,parent,parent instance id");
|
file.WriteLine("name,instance id,sibling index,parent,parent instance id");
|
||||||
foreach (var (transform, (siblingIndex, parent)) in _cache)
|
foreach (var (transform, (siblingIndex, parent)) in _cache)
|
||||||
@ -267,7 +267,7 @@ public static class DeterministicManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// only call this before world objects ready
|
/// only call this before world objects added
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string DeterministicPath(this Component component)
|
public static string DeterministicPath(this Component component)
|
||||||
{
|
{
|
||||||
@ -298,7 +298,7 @@ public static class DeterministicManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// only call this before world objects ready
|
/// only call this before world objects added
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IEnumerable<T> SortDeterministic<T>(this IEnumerable<T> components) where T : Component
|
public static IEnumerable<T> SortDeterministic<T>(this IEnumerable<T> components) where T : Component
|
||||||
=> components.OrderBy(DeterministicPath);
|
=> components.OrderBy(DeterministicPath);
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Object = UnityEngine.Object;
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
@ -214,5 +215,23 @@ public static class Extensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/a/24031467
|
||||||
|
public static string GetMD5Hash(this IEnumerable<string> list)
|
||||||
|
{
|
||||||
|
using var md5 = System.Security.Cryptography.MD5.Create();
|
||||||
|
|
||||||
|
var longString = string.Concat(list);
|
||||||
|
var bytes = Encoding.ASCII.GetBytes(longString);
|
||||||
|
var hashBytes = md5.ComputeHash(bytes);
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
for (var i = 0; i < hashBytes.Length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(hashBytes[i].ToString("X2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ using UnityEngine.UI;
|
|||||||
|
|
||||||
namespace QSB.Utility;
|
namespace QSB.Utility;
|
||||||
|
|
||||||
|
[UsedInUnityProject]
|
||||||
public class ZOverride : MonoBehaviour
|
public class ZOverride : MonoBehaviour
|
||||||
{
|
{
|
||||||
private const string shaderTestMode = "unity_GUIZTestMode";
|
private const string shaderTestMode = "unity_GUIZTestMode";
|
||||||
|
@ -20,6 +20,7 @@ namespace QSB.WorldSync;
|
|||||||
public static class QSBWorldSync
|
public static class QSBWorldSync
|
||||||
{
|
{
|
||||||
public static WorldObjectManager[] Managers;
|
public static WorldObjectManager[] Managers;
|
||||||
|
public static string WorldObjectsHash { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set when all WorldObjectManagers have called Init() on all their objects (AKA all the objects are created)
|
/// Set when all WorldObjectManagers have called Init() on all their objects (AKA all the objects are created)
|
||||||
@ -82,8 +83,14 @@ public static class QSBWorldSync
|
|||||||
AllObjectsAdded = true;
|
AllObjectsAdded = true;
|
||||||
DebugLog.DebugWrite("World Objects added.", MessageType.Success);
|
DebugLog.DebugWrite("World Objects added.", MessageType.Success);
|
||||||
|
|
||||||
|
DeterministicManager.OnWorldObjectsAdded();
|
||||||
|
|
||||||
|
WorldObjectsHash = WorldObjects.Select(x => x.GetType().Name).GetMD5Hash();
|
||||||
|
DebugLog.DebugWrite($"WorldObject hash is {WorldObjectsHash}");
|
||||||
|
|
||||||
if (!QSBCore.IsHost)
|
if (!QSBCore.IsHost)
|
||||||
{
|
{
|
||||||
|
new WorldObjectsHashMessage().Send();
|
||||||
new RequestLinksMessage().Send();
|
new RequestLinksMessage().Send();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +103,6 @@ public static class QSBWorldSync
|
|||||||
AllObjectsReady = true;
|
AllObjectsReady = true;
|
||||||
DebugLog.DebugWrite("World Objects ready.", MessageType.Success);
|
DebugLog.DebugWrite("World Objects ready.", MessageType.Success);
|
||||||
|
|
||||||
DeterministicManager.OnWorldObjectsReady();
|
|
||||||
|
|
||||||
if (!QSBCore.IsHost)
|
if (!QSBCore.IsHost)
|
||||||
{
|
{
|
||||||
new RequestInitialStatesMessage().Send();
|
new RequestInitialStatesMessage().Send();
|
||||||
@ -247,7 +252,7 @@ public static class QSBWorldSync
|
|||||||
|
|
||||||
if (WorldObjects[objectId] is not TWorldObject worldObject)
|
if (WorldObjects[objectId] is not TWorldObject worldObject)
|
||||||
{
|
{
|
||||||
DebugLog.ToConsole($"Error - {typeof(TWorldObject).Name} id {objectId} is actually {WorldObjects[objectId].GetType().Name}.", MessageType.Error);
|
DebugLog.ToConsole($"Error - WorldObject id {objectId} is {WorldObjects[objectId].GetType().Name}, expected {typeof(TWorldObject).Name}.", MessageType.Error);
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
QSB/WorldSync/WorldObjectsHashMessage.cs
Normal file
30
QSB/WorldSync/WorldObjectsHashMessage.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using OWML.Common;
|
||||||
|
using QSB.Messaging;
|
||||||
|
using QSB.Player.Messages;
|
||||||
|
using QSB.Utility;
|
||||||
|
|
||||||
|
namespace QSB.WorldSync;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// sends QSBWorldSync.WorldObjectsHash to the server for sanity checking
|
||||||
|
/// </summary>
|
||||||
|
internal class WorldObjectsHashMessage : QSBMessage<string>
|
||||||
|
{
|
||||||
|
public WorldObjectsHashMessage() : base(QSBWorldSync.WorldObjectsHash) => To = 0;
|
||||||
|
|
||||||
|
public override void OnReceiveRemote()
|
||||||
|
{
|
||||||
|
var serverHash = QSBWorldSync.WorldObjectsHash;
|
||||||
|
|
||||||
|
if (serverHash != Data)
|
||||||
|
{
|
||||||
|
// oh fuck oh no oh god
|
||||||
|
DebugLog.ToConsole($"Kicking {From} because their WorldObjects hash is wrong. (server:{serverHash}, client:{Data})", MessageType.Error);
|
||||||
|
new PlayerKickMessage(From, $"WorldObject hash error. (Server:{serverHash}, Client:{Data})").Send();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DebugLog.DebugWrite($"WorldObject hash from {From} verified!", MessageType.Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,29 @@
|
|||||||
{
|
{
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"settings": {
|
"settings": {
|
||||||
"defaultServerIP": "localhost",
|
"defaultServerIP": {
|
||||||
"incompatibleModsAllowed": false
|
"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."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,8 +7,8 @@
|
|||||||
"body": "- Disable *all* other mods. (Can heavily affect performance)\n- Make sure you are not running any other network-intensive applications."
|
"body": "- Disable *all* other mods. (Can heavily affect performance)\n- Make sure you are not running any other network-intensive applications."
|
||||||
},
|
},
|
||||||
"uniqueName": "Raicuparta.QuantumSpaceBuddies",
|
"uniqueName": "Raicuparta.QuantumSpaceBuddies",
|
||||||
"version": "0.22.0",
|
"version": "0.23.0",
|
||||||
"owmlVersion": "2.7.0",
|
"owmlVersion": "2.8.0",
|
||||||
"dependencies": [ "_nebula.MenuFramework", "JohnCorby.VanillaFix" ],
|
"dependencies": [ "_nebula.MenuFramework", "JohnCorby.VanillaFix" ],
|
||||||
"pathsToPreserve": [ "debugsettings.json", "storage.json" ]
|
"pathsToPreserve": [ "debugsettings.json", "storage.json" ]
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,6 @@ See [TRANSLATING.md](TRANSLATING.md)
|
|||||||
- Clone QSB's source
|
- Clone QSB's source
|
||||||
- Open the file `DevEnv.targets` in your favorite text editor
|
- Open the file `DevEnv.targets` in your favorite text editor
|
||||||
- (optional if copying built dlls manually) Edit the entry `<OwmlDir>` to point to your OWML directory (it is installed inside the Mod Manager directory)
|
- (optional if copying built dlls manually) Edit the entry `<OwmlDir>` to point to your OWML directory (it is installed inside the Mod Manager directory)
|
||||||
- (optional if no unity project) Edit the entry `<GameDir>` to point to the directory where Outer Wilds is installed
|
|
||||||
- (optional if no unity project) Edit the entry `<UnityAssetsDir>` to point to the Assets folder of the QSB unity project
|
- (optional if no unity project) Edit the entry `<UnityAssetsDir>` to point to the Assets folder of the QSB unity project
|
||||||
- Open the project solution file `QSB.sln` in Visual Studio 2022
|
- Open the project solution file `QSB.sln` in Visual Studio 2022
|
||||||
|
|
||||||
@ -171,7 +170,7 @@ The template for this file is this :
|
|||||||
|
|
||||||
### Authors
|
### 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.
|
- [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.
|
- [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.
|
- [Raicuparta](https://github.com/Raicuparta) - Developer of v0.1.0 - v0.2.0.
|
||||||
@ -180,9 +179,10 @@ The template for this file is this :
|
|||||||
|
|
||||||
- [Chris Yeninas](https://github.com/PhantomGamers) - Help with project files and GitHub workflows.
|
- [Chris Yeninas](https://github.com/PhantomGamers) - Help with project files and GitHub workflows.
|
||||||
- [Tlya](https://github.com/Tllya) - Russian translation.
|
- [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.
|
- [ShoosGun](https://github.com/ShoosGun) - Portuguese translation.
|
||||||
- [DertolleDude](https://github.com/DertolleDude) - German translation.
|
- [DertolleDude](https://github.com/DertolleDude) - German translation.
|
||||||
|
- [SakuradaYuki](https://github.com/SakuradaYuki) - Chinese translation.
|
||||||
|
|
||||||
### Special Thanks
|
### Special Thanks
|
||||||
- Thanks to Logan Ver Hoef for help with the game code, and for helping make the damn game in the first place.
|
- 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
|
- Russian
|
||||||
- Portuguese (Brazil)
|
- Portuguese (Brazil)
|
||||||
- German
|
- German
|
||||||
|
- Chinese (Simplified)
|
||||||
|
|
||||||
### Un-translated languages :
|
### Un-translated languages :
|
||||||
- Spanish (Latin American)
|
- Spanish (Latin American)
|
||||||
- Italian
|
- Italian
|
||||||
- Polish
|
- Polish
|
||||||
- Japanese
|
- Japanese
|
||||||
- Chinese (Simplified)
|
|
||||||
- Korean
|
- Korean
|
||||||
- Turkish
|
- 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)".
|
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